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
//
// GENERATED FILE
//
use super::*;
use crate::SpiceContext;
use f2rust_std::*;
/// N'th word in a character string
///
/// Return the Nth word in a character string, and its location
/// in the string.
///
/// # Brief I/O
///
/// ```text
/// VARIABLE I/O DESCRIPTION
/// -------- --- --------------------------------------------------
/// STRING I Input character string.
/// NTH I Index of the word to be returned.
/// WORD O The NTH word in STRING.
/// LOC O Location of WORD in STRING.
/// ```
///
/// # Detailed Input
///
/// ```text
/// STRING is the input string to be parsed. Each word of this
/// string is a maximal sequence of consecutive non-blank
/// characters.
///
/// NTH is the index of the word to be returned. (One for the
/// first word, two for the second, and so on.)
/// ```
///
/// # Detailed Output
///
/// ```text
/// WORD is the NTH word in STRING. If STRING is blank, or NTH is
/// non-positive or too large, WORD is blank.
///
/// WORD may overwrite STRING.
///
/// LOC is the location of WORD in STRING. (That is, WORD begins
/// at STRING(LOC:LOC)). If STRING is blank, or NTH is
/// non-positive or too large, LOC is zero.
/// ```
///
/// # Exceptions
///
/// ```text
/// Error free.
///
/// 1) If the declared length of WORD is not large enough to contain
/// the NTH word in STRING, the word will be truncated on the
/// right.
/// ```
///
/// # Particulars
///
/// ```text
/// NTHWD, like NEXTWD, is useful primarily for parsing input commands
/// consisting of one or more words, where a word is defined to be a
/// maximal sequence of consecutive non-blank characters. Each word is
/// bounded on both sides by a blank character, or by the start or end
/// of the input string. Successive calls to NEXTWD allow the calling
/// routine to neatly parse and process one word at a time.
///
/// The chief difference between the two routines is that
/// NTHWD allows the calling routine to access the words making
/// up the input string in random order. (NEXTWD allows only
/// sequential access.)
///
/// NTHWD may be more efficient than NEXTWD, since NTHWD doesn't
/// update an output string consisting of the remaining, unparsed
/// string.
/// ```
///
/// # Examples
///
/// ```text
/// The numerical results shown for this example may differ across
/// platforms. The results depend on the SPICE kernels used as
/// input, the compiler and supporting libraries, and the machine
/// specific arithmetic implementation.
///
/// 1) Given a character string, get the N'th word within, and the
/// word's location.
///
///
/// Example code begins here.
///
///
/// PROGRAM NTHWD_EX1
/// IMPLICIT NONE
///
/// C
/// C SPICELIB functions.
/// C
/// INTEGER RTRIM
///
/// C
/// C Local parameters.
/// C
/// CHARACTER*(*) STRING
/// PARAMETER ( STRING = ' Now is the time, '
/// . // 'for all good men to come.' )
///
/// CHARACTER*(*) FMT
/// PARAMETER ( FMT = '(A,I3,3A,I3)' )
///
/// INTEGER WRDSZ
/// PARAMETER ( WRDSZ = 5 )
///
/// C
/// C Local variables.
/// C
/// CHARACTER*(WRDSZ) WORD
/// INTEGER LOC
/// INTEGER NTH
///
///
/// DO NTH = -1, 11
///
/// CALL NTHWD ( STRING, NTH, WORD, LOC )
/// WRITE(*,FMT) 'Word #', NTH, ' is <',
/// . WORD(:RTRIM(WORD)),
/// . '>, starting at position', LOC
///
/// END DO
///
/// END
///
///
/// When this program was executed on a Mac/Intel/gfortran/64-bit
/// platform, the output was:
///
///
/// Word # -1 is < >, starting at position 0
/// Word # 0 is < >, starting at position 0
/// Word # 1 is <Now>, starting at position 2
/// Word # 2 is <is>, starting at position 6
/// Word # 3 is <the>, starting at position 9
/// Word # 4 is <time,>, starting at position 13
/// Word # 5 is <for>, starting at position 21
/// Word # 6 is <all>, starting at position 25
/// Word # 7 is <good>, starting at position 29
/// Word # 8 is <men>, starting at position 34
/// Word # 9 is <to>, starting at position 42
/// Word # 10 is <come.>, starting at position 45
/// Word # 11 is < >, starting at position 0
/// ```
///
/// # Author and Institution
///
/// ```text
/// N.J. Bachman (JPL)
/// J. Diaz del Rio (ODC Space)
/// W.L. Taber (JPL)
/// I.M. Underwood (JPL)
/// E.D. Wright (JPL)
/// ```
///
/// # Version
///
/// ```text
/// - SPICELIB Version 1.2.0, 26-OCT-2021 (NJB) (JDR)
///
/// Added IMPLICIT NONE statement.
///
/// Edited the header to comply with NAIF standard. Added complete
/// code example based on the existing fragment.
///
/// Updated header documentation. Added entry #1 in $Exceptions
/// section.
///
/// - SPICELIB Version 1.1.0, 10-MAY-2006 (EDW)
///
/// Added logic to prevent the evaluation of STRING(I:I)
/// if I exceeds the length of STRING. Functionally, the
/// evaluation had no effect on NTHWD's output, but the ifort
/// F95 compiler flagged the evaluation as an array
/// overrun error. This occurred because given:
///
/// A .AND. B
///
/// ifort evaluates A then B then performs the logical
/// comparison.
///
/// - 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)
/// ```
pub fn nthwd(string: &str, nth: i32, word: &mut str, loc: &mut i32) {
NTHWD(
string.as_bytes(),
nth,
fstr::StrBytes::new(word).as_mut(),
loc,
);
}
//$Procedure NTHWD ( N'th word in a character string )
pub fn NTHWD(STRING: &[u8], NTH: i32, WORD: &mut [u8], LOC: &mut i32) {
let mut N: i32 = 0;
let mut I: i32 = 0;
let mut LENGTH: i32 = 0;
let mut LOOP: bool = false;
//
// Local variables
//
//
// Trivial cases first. Blank STRING? Nonpositive NTH?
//
if (fstr::eq(STRING, b" ") || (NTH < 1)) {
fstr::assign(WORD, b" ");
*LOC = 0;
return;
}
//
// Skip leading blanks.
//
*LOC = 1;
while fstr::eq(fstr::substr(STRING, *LOC..=*LOC), b" ") {
*LOC = (*LOC + 1);
}
//
// If we wanted the first word, we have the location. Otherwise,
// keep stepping through STRING. Quit when the N'TH word is found,
// or when the end of the string is reached. (The current word is
// ended whenever a blank is encountered.)
//
// N is the number of words found so far.
// I is the current location in STRING.
//
N = 1;
I = *LOC;
LENGTH = intrinsics::LEN(STRING);
while ((I < LENGTH) && (N < NTH)) {
I = (I + 1);
//
// Blank signals end of the current word.
//
if fstr::eq(fstr::substr(STRING, I..=I), b" ") {
//
// Skip ahead to the next one. The logic ensures no
// evaluation of STRING(I:I) if I > LEN(STRING).
//
LOOP = (I <= LENGTH);
if LOOP {
LOOP = (LOOP && fstr::eq(fstr::substr(STRING, I..=I), b" "));
}
while LOOP {
I = (I + 1);
if (I > LENGTH) {
LOOP = false;
} else if fstr::ne(fstr::substr(STRING, I..=I), b" ") {
LOOP = false;
} else {
LOOP = true;
}
}
//
// If not at the end of the string, we have another word.
//
if (I <= LENGTH) {
N = (N + 1);
*LOC = I;
}
}
}
//
// Couldn't find enough words? Return blank and zero.
//
if (N < NTH) {
fstr::assign(WORD, b" ");
*LOC = 0;
//
// Otherwise, find the rest of WORD (it continues until the next
// blank), and return the current LOC.
//
} else {
I = intrinsics::INDEX(fstr::substr(STRING, *LOC..), b" ");
if (I == 0) {
fstr::assign(WORD, fstr::substr(STRING, *LOC..));
} else {
fstr::assign(WORD, fstr::substr(STRING, *LOC..=((*LOC + I) - 1)));
}
}
}