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
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
//
// 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 BWDLOC: i32 = 1;
const FWDLOC: i32 = 2;
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, add comment records
///
/// Increase the size of the comment area in a DAS file to accommodate
/// a specified number of additional 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 append to the comment
/// area of the specified file.
/// ```
///
/// # 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 append to the comment
/// area. If NCOMR is the number of comment records
/// present in the file on input, then on output the
/// number of comment records will be 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 addition 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 create space in the comment area of a DAS
/// file to allow addition of comments to the file. If there are
/// comment records present in the file at the time this routine is
/// called, the number of comment records specified by the input
/// argument N will be appended to the existing comment records.
/// In any case, any existing directory records and data records will
/// be shifted down 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.
///
/// This routine may be used only on existing DAS files opened by
/// DASOPW.
///
/// 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 add comments by calling DASAC.
///
/// This routine has an inverse DASRCR, which removes a specified
/// number of records from the end of the comment area.
/// ```
///
/// # Examples
///
/// ```text
/// 1) Make room for 10 comment records in the comment area of a
/// new DAS file.
///
/// C
/// C Create a new DAS file.
/// C
/// CALL DASOPW ( DAS, HANDLE )
///
/// C
/// C Now add 10 comment records to the comment area.
/// C
/// CALL DASACR ( HANDLE, 10 )
/// ```
///
/// # 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, 13-AUG-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.1.0, 11-OCT-1996 (NJB)
///
/// Bug fix: backward and forward directory record pointers
/// are now updated when directory records are moved.
///
/// - SPICELIB Version 1.0.0, 01-FEB-1993 (NJB) (WLT)
/// ```
///
/// # Revisions
///
/// ```text
/// - SPICELIB Version 1.1.0, 11-OCT-1996 (NJB)
///
/// Bug fix: backward and forward directory record pointers
/// are now updated when directory records are moved.
///
/// Because these pointers are not used by the DAS software
/// once a DAS file is segregated, this bug had no effect on
/// DAS files that were created and closed via DASCLS, then
/// commented via the commnt utility.
/// ```
pub fn dasacr(ctx: &mut SpiceContext, handle: i32, n: i32) -> crate::Result<()> {
DASACR(handle, n, ctx.raw_context())?;
ctx.handle_errors()?;
Ok(())
}
//$Procedure DASACR ( DAS, add comment records )
pub fn DASACR(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 NXTTYP: i32 = 0;
let mut POS: i32 = 0;
let mut PREC: 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 locations (backward and 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"DASACR", ctx)?;
//
// Programmer's note: the calls to
//
// DASIOC
// DASIOD
// DASIOI
//
// for read access are valid only for native format DAS files.
// If this routine is updated to support writing to non-native
// DAS files, at least the calls to the numeric I/O routines
// will need to be replaced. (Consider using ZZDASGRD, ZZDASGRI.)
//
// 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"DASACR", ctx)?;
return Ok(());
}
//
// It's a mistake to use a negative value of N.
//
if (N < 0) {
SETMSG(b"Number of comment records to add must be non-negative. Actual number requested was #.", ctx);
ERRINT(b"#", N, ctx);
SIGERR(b"SPICE(DASINVALIDCOUNT)", ctx)?;
CHKOUT(b"DASACR", 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
// comment 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,
)?;
//
// 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 word
// 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 addition of the comment
// records.
//
if (LREC == 0) {
//
// Just write the zero-filled record to record number
//
// NRESVR + NCOMR + N + 2
//
CLEARI(NWI, DIRREC.as_slice_mut());
DASIOI(
b"WRITE",
UNIT,
(((NRESVR + NCOMR) + N) + 2),
DIRREC.as_slice_mut(),
ctx,
)?;
} else {
//
// There really is stuff to move. For each directory record,
// move all of the records described by that directory. We start
// with the last directory and work our way toward the beginning
// of the file.
//
NREC = LREC;
while (NREC > 0) {
//
// For each descriptor in the current directory, move the
// cluster of data records it refers to.
//
// Read the current directory record.
//
DASIOI(b"READ", UNIT, NREC, DIRREC.as_slice_mut(), ctx)?;
//
// Find the data type, size, and base record number of the
// last cluster in the current directory. To do this,
// traverse the directory record, keeping track of the record
// count and data types of descriptors as we go.
//
TYPE = DIRREC[BEGDSC];
BASE = (NREC + 1);
if (NREC == LREC) {
LINDEX = LWORD;
} else {
LINDEX = NWI;
}
for I in (BEGDSC + 2)..=LINDEX {
if (DIRREC[I] < 0) {
TYPE = save.PREV[TYPE];
} else {
TYPE = save.NEXT[TYPE];
}
BASE = (BASE + i32::abs(DIRREC[(I - 1)]));
}
//
// TYPE and BASE are now the data type and base record number
// of the last cluster described by the current directory.
//
// We'll now traverse the directory in reverse order, keeping
// track of cluster sizes and types as we go.
//
// POS will be the index of the descriptor of the current
// cluster.
//
POS = LINDEX;
while (POS > BEGDSC) {
if (POS < LINDEX) {
//
// We'll need to determine the type of the current
// cluster. If the next descriptor contains a positive
// value, the data type of the cluster it refers to is
// the successor of the current type, according to our
// ordering of types.
//
if (DIRREC[(POS + 1)] > 0) {
//
// This assignment and the one below in the ELSE
// block are performed from the second loop iteration
// onward. NXTTYP is initialized on the first loop
// iteration.
//
TYPE = save.PREV[NXTTYP];
} else {
TYPE = save.NEXT[NXTTYP];
}
//
// Update the cluster base record number.
//
BASE = (BASE - i32::abs(DIRREC[POS]));
}
//
// Move the current cluster.
//
for I in intrinsics::range(((BASE + i32::abs(DIRREC[POS])) - 1), BASE, -1) {
if (TYPE == CHAR) {
DASIOC(b"READ", UNIT, I, &mut RECC, ctx)?;
DASIOC(b"WRITE", UNIT, (I + N), &mut RECC, ctx)?;
} else if (TYPE == DP) {
DASIOD(b"READ", UNIT, I, RECD.as_slice_mut(), ctx)?;
DASIOD(b"WRITE", UNIT, (I + N), RECD.as_slice_mut(), ctx)?;
} else {
DASIOI(b"READ", UNIT, I, RECI.as_slice_mut(), ctx)?;
DASIOI(b"WRITE", UNIT, (I + N), RECI.as_slice_mut(), ctx)?;
}
}
//
// The next descriptor to look at is the preceding one in
// the directory.
//
POS = (POS - 1);
NXTTYP = TYPE;
}
//
// Find the preceding directory record.
//
PREC = DIRREC[BWDLOC];
//
// Update the backward and forward pointers in the current
// directory record. However, don't modify null pointers.
//
if (DIRREC[FWDLOC] > 0) {
DIRREC[FWDLOC] = (DIRREC[FWDLOC] + N);
}
if (DIRREC[BWDLOC] > 0) {
DIRREC[BWDLOC] = (DIRREC[BWDLOC] + N);
}
//
// Move the current directory record.
//
DASIOI(b"WRITE", UNIT, (NREC + N), DIRREC.as_slice_mut(), ctx)?;
//
// Consider the previous directory.
//
NREC = PREC;
}
}
//
// Update the file summary. The number of comment records and the
// number of the first free record have been incremented by N.
// The numbers of the records containing the last descriptor of each
// type have been incremented by N only if they were non-zero.
//
// The call to DASUFS will update the file record as well as the
// file summary.
//
NCOMR = (NCOMR + N);
FREE = (FREE + N);
for I in 1..=3 {
if (LASTRC[I] != 0) {
LASTRC[I] = (LASTRC[I] + N);
}
}
DASUFS(
HANDLE,
NRESVR,
NRESVC,
NCOMR,
NCOMC,
FREE,
LASTLA.as_slice(),
LASTRC.as_slice(),
LASTWD.as_slice(),
ctx,
)?;
CHKOUT(b"DASACR", ctx)?;
Ok(())
}