1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
//
// GENERATED FILE
//
use super::*;
use crate::SpiceContext;
use f2rust_std::*;
const NWC: i32 = 1024;
const NWD: i32 = 128;
const NWI: i32 = 256;
const CHAR: i32 = 1;
const DP: i32 = 2;
const FWDLOC: i32 = 1;
const BEGDSC: i32 = 9;
struct SaveVars {
NEXT: StackArray<i32, 3>,
PREV: StackArray<i32, 3>,
}
impl SaveInit for SaveVars {
fn new() -> Self {
let mut NEXT = StackArray::<i32, 3>::new(1..=3);
let mut PREV = StackArray::<i32, 3>::new(1..=3);
{
use f2rust_std::data::Val;
let mut clist = [Val::I(2), Val::I(3), Val::I(1)].into_iter();
NEXT.iter_mut()
.for_each(|n| *n = clist.next().unwrap().into_i32());
debug_assert!(clist.next().is_none(), "DATA not fully initialised");
}
{
use f2rust_std::data::Val;
let mut clist = [Val::I(3), Val::I(1), Val::I(2)].into_iter();
PREV.iter_mut()
.for_each(|n| *n = clist.next().unwrap().into_i32());
debug_assert!(clist.next().is_none(), "DATA not fully initialised");
}
Self { NEXT, PREV }
}
}
/// DAS, remove comment records
///
/// Decrease the size of the comment area in a DAS file to reclaim
/// space freed by the removal of a specified number of comment
/// records.
///
/// # Required Reading
///
/// * [DAS](crate::required_reading::das)
///
/// # Brief I/O
///
/// ```text
/// VARIABLE I/O DESCRIPTION
/// -------- --- --------------------------------------------------
/// HANDLE I A DAS file handle.
/// N I Number of comment records to remove.
/// ```
///
/// # Detailed Input
///
/// ```text
/// HANDLE is the handle of an existing DAS file opened for
/// comment area modification by DASOPC.
///
/// N is the number of records to remove from the end of
/// the comment area. of the specified file. If NCOMR
/// is the number of comment records present in the
/// file on input, then on output the number of comment
/// records will be MAX ( 0, NCOMR - N ).
/// ```
///
/// # Detailed Output
///
/// ```text
/// None. See $Particulars for a description of the effect of this
/// routine.
/// ```
///
/// # Exceptions
///
/// ```text
/// 1) If the input handle is invalid, an error is signaled by a
/// routine in the call tree of this routine.
///
/// 2) If an I/O error occurs during the removal process, the error
/// is signaled by a routine in the call tree of this routine. The
/// DAS file will probably be corrupted in this case.
/// ```
///
/// # Files
///
/// ```text
/// See the description of the argument HANDLE in $Detailed_Input.
/// ```
///
/// # Particulars
///
/// ```text
/// This routine is used to reclaim freed space in the comment area
/// of a DAS file subsequent to removal of comments from the file.
/// Any existing directory records and data records will be shifted
/// up by N records.
///
/// This routine updates the file record of the specified DAS file
/// to reflect the addition of records to the file's comment area.
/// Also, the file summary obtainable from DASHFS will be updated to
/// reflect the addition of comment records.
///
/// The disk space occupied by the specified DAS file will not
/// decrease as a result of calling this routine, but the number of
/// records occupied by meaningful data will decrease. The useful
/// records in the file can be copied by DAS routines to create a
/// new, smaller file which contains only the meaningful data.
///
/// This routine may be used only on existing DAS files opened by
/// DASOPC.
///
/// The association of DAS logical addresses and data within the
/// specified file will remain unaffected by use of this routine.
///
/// Normally, SPICELIB applications will not call this routine
/// directly, but will remove comments by calling DASRC.
///
/// This routine has an inverse DASACR, which appends a specified
/// number of records to the end of the comment area.
/// ```
///
/// # Examples
///
/// ```text
/// C
/// C Open an existing DAS file for modification of
/// C the comment area. We'll presume that the file
/// C contains 20 comment records.
/// C
/// CALL DASOPC ( DAS, HANDLE )
///
/// C
/// C Remove the last 10 comment records from the file.
/// C
/// CALL DASRCR ( HANDLE, 10 )
///
/// C
/// C Close the file.
/// C
/// CALL DASCLS ( HANDLE )
/// ```
///
/// # Restrictions
///
/// ```text
/// 1) The DAS file must have a binary file format native to the host
/// system.
/// ```
///
/// # Author and Institution
///
/// ```text
/// N.J. Bachman (JPL)
/// J. Diaz del Rio (ODC Space)
/// W.L. Taber (JPL)
/// ```
///
/// # Version
///
/// ```text
/// - SPICELIB Version 1.3.0, 02-JUN-2021 (JDR)
///
/// Added IMPLICIT NONE statement.
///
/// Edited the header to comply with NAIF standard.
///
/// - SPICELIB Version 1.2.0, 05-FEB-2015 (NJB)
///
/// Updated to support integration with the handle
/// manager subsystem.
///
/// Cleaned up use of unnecessary variables and unneeded
/// declarations.
///
/// - SPICELIB Version 1.0.0, 15-NOV-1992 (NJB) (WLT)
/// ```
pub fn dasrcr(ctx: &mut SpiceContext, handle: i32, n: i32) -> crate::Result<()> {
DASRCR(handle, n, ctx.raw_context())?;
ctx.handle_errors()?;
Ok(())
}
//$Procedure DASRCR ( DAS, remove comment records )
pub fn DASRCR(HANDLE: i32, N: i32, ctx: &mut Context) -> f2rust_std::Result<()> {
let save = ctx.get_vars::<SaveVars>();
let save = &mut *save.borrow_mut();
let mut RECC = [b' '; NWC as usize];
let mut RECD = StackArray::<f64, 128>::new(1..=NWD);
let mut BASE: i32 = 0;
let mut DIRREC = StackArray::<i32, 256>::new(1..=NWI);
let mut FREE: i32 = 0;
let mut LASTLA = StackArray::<i32, 3>::new(1..=3);
let mut LASTRC = StackArray::<i32, 3>::new(1..=3);
let mut LASTWD = StackArray::<i32, 3>::new(1..=3);
let mut LOC: i32 = 0;
let mut LREC: i32 = 0;
let mut LINDEX: i32 = 0;
let mut LWORD: i32 = 0;
let mut NCOMC: i32 = 0;
let mut NCOMR: i32 = 0;
let mut NREC: i32 = 0;
let mut NRESVC: i32 = 0;
let mut NRESVR: i32 = 0;
let mut NSHIFT: i32 = 0;
let mut POS: i32 = 0;
let mut RECI = StackArray::<i32, 256>::new(1..=NWI);
let mut TYPE: i32 = 0;
let mut UNIT: i32 = 0;
//
// SPICELIB functions
//
//
// Local parameters
//
//
// Words per data record, for each data type:
//
//
// Data type parameters
//
//
// Directory pointer location (forward):
//
//
// Location of first type descriptor
//
//
// Local variables
//
//
// Saved variables
//
//
// NEXT and PREV map the DAS data type codes to their
// successors and predecessors, respectively.
//
//
// Initial values
//
//
// Standard SPICE error handling.
//
if RETURN(ctx) {
return Ok(());
}
CHKIN(b"DASRCR", ctx)?;
//
// Make sure this DAS file is open for writing. Signal an error if
// not.
//
DASSIH(HANDLE, b"WRITE", ctx)?;
//
// Get the logical unit for this DAS file.
//
ZZDDHHLU(HANDLE, b"DAS", false, &mut UNIT, ctx)?;
if FAILED(ctx) {
CHKOUT(b"DASRCR", ctx)?;
return Ok(());
}
//
// It's a mistake to use a negative value of N.
//
if (N < 0) {
SETMSG(b"Number of comment records to remove must be non-negative. Actual number requested was #.", ctx);
ERRINT(b"#", N, ctx);
SIGERR(b"SPICE(DASINVALIDCOUNT)", ctx)?;
CHKOUT(b"DASRCR", ctx)?;
return Ok(());
}
//
// Before doing anything to the file, make sure that the DASRWR
// data buffers do not contain any updated records for this file.
// All of the record numbers that pertain to this file and remain
// in the DASRWR buffers will be invalidated after this routine
// returns.
//
// DASWBR flushes buffered records to the file.
//
DASWBR(HANDLE, ctx)?;
//
// Grab the file summary for this DAS file. Find the number of
// reserved records and the number of the first free record.
//
DASHFS(
HANDLE,
&mut NRESVR,
&mut NRESVC,
&mut NCOMR,
&mut NCOMC,
&mut FREE,
LASTLA.as_slice_mut(),
LASTRC.as_slice_mut(),
LASTWD.as_slice_mut(),
ctx,
)?;
//
// Determine the size of the record shift we'll actually perform.
//
NSHIFT = intrinsics::MIN0(&[N, NCOMR]);
//
// Find the record and word positions LREC and LWORD of the last
// descriptor in the file.
//
MAXAI(LASTRC.as_slice(), 3, &mut LREC, &mut LOC);
LWORD = 0;
for I in 1..=3 {
if ((LASTRC[I] == LREC) && (LASTWD[I] > LWORD)) {
LWORD = LASTWD[I];
}
}
//
// LREC and LWORD are now the record and word index of the last
// descriptor in the file. If LREC is zero, there are no directories
// in the file yet. However, even DAS files that don't contain any
// data have their first directory records zeroed out, and this
// should remain true after the removal of the comment records.
//
if (LREC == 0) {
//
// Just write the zero-filled record to record number
//
// NRESVR + NCOMR + 2 - NSHIFT
//
CLEARI(NWI, DIRREC.as_slice_mut());
DASIOI(
b"WRITE",
UNIT,
(((NRESVR + NCOMR) + 2) - NSHIFT),
DIRREC.as_slice_mut(),
ctx,
)?;
} else {
//
// There really is stuff to move. For each directory record,
// move the record and then all of the records described by that
// record. We start at the beginning of the data area and move
// downwards in the file as we go.
//
NREC = ((NRESVR + NCOMR) + 2);
while ((NREC <= LREC) && (NREC != 0)) {
//
// Read the current directory record and move it.
//
DASIOI(b"READ", UNIT, NREC, DIRREC.as_slice_mut(), ctx)?;
DASIOI(b"WRITE", UNIT, (NREC - NSHIFT), DIRREC.as_slice_mut(), ctx)?;
//
// For each descriptor in the current directory, move the
// cluster of data records it refers to.
//
// Find the data type, size, and base record number of the
// first cluster described by the current directory. Also
// find the index within the directory of the directory's
// last descriptor.
//
TYPE = DIRREC[BEGDSC];
BASE = (NREC + 1);
if (NREC == LREC) {
LINDEX = LWORD;
} else {
LINDEX = NWI;
}
//
// We'll now traverse the directory in forward order, keeping
// track of cluster sizes and types as we go.
//
// POS will be the index of the descriptor of the current
// cluster.
//
POS = (BEGDSC + 1);
while (POS <= LINDEX) {
if (POS > (BEGDSC + 1)) {
//
// We'll need to determine the type of the current
// cluster. If the descriptor contains a positive
// value, the data type of the cluster it refers to is
// the successor of the previous type, according to our
// ordering of types.
//
if (DIRREC[POS] > 0) {
TYPE = save.NEXT[TYPE];
} else {
TYPE = save.PREV[TYPE];
}
//
// Update the cluster base record number.
//
BASE = (BASE + i32::abs(DIRREC[(POS - 1)]));
}
//
// BASE and TYPE now are correctly set for the current
// cluster. Move the cluster.
//
for I in BASE..=((BASE + i32::abs(DIRREC[POS])) - 1) {
if (TYPE == CHAR) {
DASIOC(b"READ", UNIT, I, &mut RECC, ctx)?;
DASIOC(b"WRITE", UNIT, (I - NSHIFT), &mut RECC, ctx)?;
} else if (TYPE == DP) {
DASIOD(b"READ", UNIT, I, RECD.as_slice_mut(), ctx)?;
DASIOD(b"WRITE", UNIT, (I - NSHIFT), RECD.as_slice_mut(), ctx)?;
} else {
DASIOI(b"READ", UNIT, I, RECI.as_slice_mut(), ctx)?;
DASIOI(b"WRITE", UNIT, (I - NSHIFT), RECI.as_slice_mut(), ctx)?;
}
}
//
// The next descriptor to look at is the next one in the
// current directory.
//
POS = (POS + 1);
}
//
// Find the next directory record.
//
NREC = DIRREC[FWDLOC];
}
}
//
// Update the file summary. The number of comment records and the
// number of the first free record have been decremented by NSHIFT.
// The numbers of the records containing the last descriptor of each
// type have been decremented by NSHIFT only if they were non-zero.
//
//
// The call to DASUFS will update the file record as well as the
// file summary.
//
NCOMR = (NCOMR - NSHIFT);
FREE = (FREE - NSHIFT);
for I in 1..=3 {
if (LASTRC[I] != 0) {
LASTRC[I] = (LASTRC[I] - NSHIFT);
}
}
DASUFS(
HANDLE,
NRESVR,
NRESVC,
NCOMR,
NCOMC,
FREE,
LASTLA.as_slice(),
LASTRC.as_slice(),
LASTWD.as_slice(),
ctx,
)?;
CHKOUT(b"DASRCR", ctx)?;
Ok(())
}