rsspice 0.1.0

Pure Rust port of the SPICE Toolkit for space geometry
Documentation
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
//
// GENERATED FILE
//

use super::*;
use crate::SpiceContext;
use f2rust_std::*;

pub const LBCELL: i32 = -5;
pub const LINLEN: i32 = 80;
const COMMA: &[u8; 1] = &fstr::extend_const::<1>(b",");
const BLANK: &[u8; 1] = &fstr::extend_const::<1>(b" ");
const LPAREN: &[u8; 1] = &fstr::extend_const::<1>(b"(");
const RPAREN: &[u8; 1] = &fstr::extend_const::<1>(b")");

/// Read the next variable from a kernel file
///
/// Read the next variable from a SPICE ASCII kernel file into a
/// double precision symbol table.
///
/// # Required Reading
///
/// * [KERNEL](crate::required_reading::kernel)
/// * [SYMBOLS](crate::required_reading::symbols)
///
/// # Brief I/O
///
/// ```text
///  VARIABLE  I/O  DESCRIPTION
///  --------  ---  --------------------------------------------------
///  TABSYM,
///  TABPTR,
///  TABVAL    I-O  Symbol table.
///  NAME       O   Name of the variable.
///  EOF        O   End of file indicator.
///  LINLEN     P   Maximum line length.
/// ```
///
/// # Detailed Input
///
/// ```text
///  TABSYM,
///  TABPTR,
///  TABVAL   are the components of a double precision symbol table. On
///           input, the table may or may not contain any variables.
/// ```
///
/// # Detailed Output
///
/// ```text
///  TABSYM,
///  TABPTR,
///  TABVAL   on output, contains the name and values of the next
///           variable in kernel file. Depending on the assignment
///           directive, the values in the file may replace or augment
///           any existing values.
///
///   NAME    is the name of the variable. NAME is blank if no variable
///           is read.
///
///   EOF     is .TRUE. when the end of the kernel file has been
///           reached, and is .FALSE. otherwise. The kernel file is
///           closed automatically when the end of the file is reached.
/// ```
///
/// # Parameters
///
/// ```text
///  LINLEN   is the maximum length of a line in the kernel file.
/// ```
///
/// # Exceptions
///
/// ```text
///  1)  If an error occurs parsing a date from the kernel file, the
///      error SPICE(DATEEXPECTED) is signaled.
///
///  2)  If an error occurs parsing a numeric value from the kernel
///      file, the error SPICE(NUMBEREXPECTED) is signaled.
/// ```
///
/// # Files
///
/// ```text
///  RDKVAR reads from the file most recently opened by RDKNEW.
/// ```
///
/// # Examples
///
/// ```text
///  In the following example, RDKNEW and RDKVAR are used to read
///  the contents of two kernel files into a single symbol table.
///  First, the table is cleared.
///
///      CALL SCARDC ( 0, TABSYM )
///      CALL SCARDI ( 0, TABPTR )
///      CALL SCARDD ( 0, TABVAL )
///
///  Next, the files are opened and read individually.
///
///      DO I = 1, 2
///         CALL RDKNEW ( KERNEL(I), EOF )
///
///         DO WHILE ( .NOT. EOF )
///            CALL RDKVAR ( TABSYM, TABPTR, TABVAL, NAME, EOF )
///         END DO
///      END DO
///
///  Let the files KERNEL(1) and KERNEL(2) contain
///
///      ===========================================================
///
///      \begindata
///      DELTA_T_A       =   32.184
///      K               =    1.657D-3
///      ORBIT_ECC       =    1.671D-2
///      MEAN_ANOM       = (  6.239996D0,  1.99096871D-7 )
///
///      ===========================================================
///
///  and
///
///      ===========================================================
///      \begindata
///       K               =    0.0D0
///      ===========================================================
///
///  respectively. Then the contents of the symbol table are
///
///       DELTA_T_A  -->   32.184
///       K          -->    0.0D0
///       MEAN_ANOM  -->    6.239996D0
///                         1.99096871D-7
///       ORBIT_ECC  -->    1.671D-2
///
///  In particular, the value of K read from the second file replaces
///  the value read from the first file.
/// ```
///
/// # Restrictions
///
/// ```text
///  1)  The input file must be opened and initialized by RDKNEW prior
///      to the first call to RDKVAR.
/// ```
///
/// # Author and Institution
///
/// ```text
///  J. Diaz del Rio    (ODC Space)
///  W.L. Taber         (JPL)
///  I.M. Underwood     (JPL)
/// ```
///
/// # Version
///
/// ```text
/// -    SPICELIB Version 1.2.0, 17-JUN-2021 (JDR)
///
///         Added IMPLICIT NONE statement.
///
///         Edited the header to comply with NAIF standard.
///
/// -    SPICELIB Version 1.1.0, 10-MAR-1992 (WLT)
///
///         Changed the length of the local character variable ERROR so
///         that it would always have a length greater than the lengths of
///         the character string values placed into it.
///
/// -    SPICELIB Version 1.0.1, 10-MAR-1992 (WLT)
///
///         Comment section for permuted index source lines was added
///         following the header.
///
/// -    SPICELIB Version 1.0.0, 31-JAN-1990 (IMU)
/// ```
///
/// # Revisions
///
/// ```text
/// -    SPICELIB Version 1.1.0, 10-MAR-1992 (WLT)
///
///         Changed the length of the local character variable ERROR so
///         that it would always have a length greater than the lengths of
///         the character string values placed into it.
///
///         The length of the character variable ERROR was changed from 30
///         to 80.
///
/// -    SPICELIB Version 1.0.1, 10-MAR-1992 (WLT)
///
///         Comment section for permuted index source lines was added
///         following the header.
/// -    Beta Version 2.0.0, 23-OCT-1989 (HAN)
///
///         Added a test to FAILED in the main DO-loop to prevent
///         infinite looping. If the error mode was set to 'RETURN'
///         and an error occurred, the same line could be processed
///         forever.
///
/// -    Beta Version 1.1.0, 13-JAN-1989 (IMU)
///
///         Variable name may now take up an entire line. The previous
///         maximum length (32 characters) was tied to the known length
///         used by POOL. That length is now parameterized. Rather than
///         have two parameters, which could get out of synch, RDKVAR
///         now assumes that a variable name can be as long as an input
///         line.
/// ```
pub fn rdkvar(
    ctx: &mut SpiceContext,
    tabsym: CharArrayMut,
    tabptr: &mut [i32],
    tabval: &mut [f64],
    name: &mut str,
    eof: &mut bool,
) -> crate::Result<()> {
    RDKVAR(
        tabsym,
        tabptr,
        tabval,
        fstr::StrBytes::new(name).as_mut(),
        eof,
        ctx.raw_context(),
    )?;
    ctx.handle_errors()?;
    Ok(())
}

//$Procedure RDKVAR ( Read the next variable from a kernel file )
pub fn RDKVAR(
    TABSYM: CharArrayMut,
    TABPTR: &mut [i32],
    TABVAL: &mut [f64],
    NAME: &mut [u8],
    EOF: &mut bool,
    ctx: &mut Context,
) -> f2rust_std::Result<()> {
    let mut TABSYM = DummyCharArrayMut::new(TABSYM, None, LBCELL..);
    let mut TABPTR = DummyArrayMut::new(TABPTR, LBCELL..);
    let mut TABVAL = DummyArrayMut::new(TABVAL, LBCELL..);
    let mut LINE = [b' '; LINLEN as usize];
    let mut VARNAM = [b' '; LINLEN as usize];
    let mut DIRCTV = [b' '; 3];
    let mut STATUS = [b' '; 6];
    let mut CVALUE = [b' '; 30];
    let mut DVALUE: f64 = 0.0;
    let mut I: i32 = 0;
    let mut ERROR = [b' '; 80];

    //
    // SPICELIB functions
    //

    //
    // Local variables
    //

    //
    // Standard SPICE error handling.
    //
    if RETURN(ctx) {
        return Ok(());
    } else {
        CHKIN(b"RDKVAR", ctx)?;
    }

    //
    // No variable yet.
    //
    fstr::assign(NAME, b" ");

    //
    // No parsing error has occurred yet.
    //
    fstr::assign(&mut ERROR, b" ");

    //
    // Get the next data line. Unless something is terribly wrong,
    // this will begin a new variable definition. We have to read
    // the whole variable, unless we luck out and get an error, in
    // which case we can quit.
    //
    fstr::assign(&mut STATUS, b"BEGIN");

    while (fstr::ne(&STATUS, b"DONE") && !FAILED(ctx)) {
        RDKDAT(&mut LINE, EOF, ctx)?;

        if *EOF {
            CHKOUT(b"RDKVAR", ctx)?;
            return Ok(());
        }

        //
        // Replace commas with blanks. We make no distinctions between
        // the two.
        //
        REPLCH(&LINE.clone(), COMMA, BLANK, &mut LINE);

        //
        // The first word on the first line should be the name of a
        // variable. The second word should be a directive: = or +=.
        //
        if fstr::eq(&STATUS, b"BEGIN") {
            NEXTWD(&LINE.clone(), &mut VARNAM, &mut LINE);
            NEXTWD(&LINE.clone(), &mut DIRCTV, &mut LINE);

            //
            // If this is replacement (=) and not an addition (+=),
            // delete the values currently associated with the variable.
            // They will be replaced later.
            //
            if fstr::eq(&DIRCTV, b"=") {
                SYDELD(
                    &VARNAM,
                    TABSYM.as_arg_mut(),
                    TABPTR.as_slice_mut(),
                    TABVAL.as_slice_mut(),
                    ctx,
                )?;
            }

            //
            // If this is a vector, the next thing on the line will be a
            // left parenthesis. Otherwise, assume that this is a scalar.
            // If it's a vector, get the first value. If it's a scalar,
            // plant a bogus right parenthesis, to make the following loop
            // terminate after one iteration.
            //
            NEXTWD(&LINE.clone(), &mut CVALUE, &mut LINE);

            if fstr::eq(&CVALUE, LPAREN) {
                NEXTWD(&LINE.clone(), &mut CVALUE, &mut LINE);
            } else {
                fstr::assign(&mut LINE, RPAREN);
            }

        //
        // For subsequent lines, treat everything as a new value.
        //
        } else {
            NEXTWD(&LINE.clone(), &mut CVALUE, &mut LINE);
        }

        //
        // We have a value anyway. Store it in the table.
        //
        // Keep going until the other shoe (the right parenthesis)
        // drops, or until the end of the line is reached.
        //
        // Dates begin with @; anything else is presumed to be a number.
        //
        while (fstr::ne(&CVALUE, RPAREN) && fstr::ne(&CVALUE, BLANK)) {
            if fstr::eq(fstr::substr(&CVALUE, 1..=1), b"@") {
                TPARSE(fstr::substr(&CVALUE, 2..), &mut DVALUE, &mut ERROR, ctx)?;

                if fstr::ne(&ERROR, b" ") {
                    fstr::assign(
                        &mut ERROR,
                        &fstr::concat(b"Encountered : ", fstr::substr(&CVALUE, 2..)),
                    );
                    SETMSG(&ERROR, ctx);
                    SIGERR(b"SPICE(DATEEXPECTED)", ctx)?;
                    CHKOUT(b"RDKVAR", ctx)?;
                    return Ok(());
                }
            } else {
                NPARSD(&CVALUE, &mut DVALUE, &mut ERROR, &mut I, ctx);

                if fstr::ne(&ERROR, b" ") {
                    fstr::assign(&mut ERROR, &fstr::concat(b"Encountered : ", &CVALUE));
                    SETMSG(&ERROR, ctx);
                    SIGERR(b"SPICE(NUMBEREXPECTED)", ctx)?;
                    CHKOUT(b"RDKVAR", ctx)?;
                    return Ok(());
                }
            }

            SYENQD(
                &VARNAM,
                DVALUE,
                TABSYM.as_arg_mut(),
                TABPTR.as_slice_mut(),
                TABVAL.as_slice_mut(),
                ctx,
            )?;

            NEXTWD(&LINE.clone(), &mut CVALUE, &mut LINE);
        }

        if fstr::eq(&CVALUE, RPAREN) {
            fstr::assign(&mut STATUS, b"DONE");
        } else {
            fstr::assign(&mut STATUS, b"INVAR");
        }
    }

    //
    // Return the name of the variable, but only if everything went okay.
    //
    fstr::assign(NAME, &VARNAM);

    CHKOUT(b"RDKVAR", ctx)?;
    Ok(())
}