tomwalters@0
|
1
|
tomwalters@0
|
2 #include <stdio.h>
|
tomwalters@0
|
3 #include <math.h>
|
tomwalters@0
|
4 #include "options.h"
|
tomwalters@0
|
5 #include "strmatch.h"
|
tomwalters@0
|
6 #include "units.h"
|
tomwalters@0
|
7
|
tomwalters@0
|
8
|
tomwalters@0
|
9 /*
|
tomwalters@0
|
10 Defaults for i/o parameters.
|
tomwalters@0
|
11 These are declared externally in options.h so they may be overridden by
|
tomwalters@0
|
12 option assignment.
|
tomwalters@0
|
13 */
|
tomwalters@0
|
14
|
tomwalters@0
|
15 int LINE_LENGTH = 256 ; /* max length of line for ascii data. */
|
tomwalters@0
|
16 int FIELDWIDTH = 0 ; /* field width for printf. */
|
tomwalters@0
|
17 /* (FIELDWIDTH=0 sets no extra fieldwidth. */
|
tomwalters@0
|
18 /* Positive integer fieldwidth sets right-justified */
|
tomwalters@0
|
19 /* columns, negative integer fieldwidth sets left- */
|
tomwalters@0
|
20 /* justified columns). */
|
tomwalters@0
|
21 int PRECISION = 3 ; /* precision (num decimal places) for printf, */
|
tomwalters@0
|
22 /* (PRECISION=0 sets integer output). */
|
tomwalters@0
|
23
|
tomwalters@0
|
24
|
tomwalters@0
|
25
|
tomwalters@0
|
26 /*
|
tomwalters@0
|
27 Return a file pointer to a file `name' opened to read.
|
tomwalters@0
|
28 If `name' is `-' then return stdin.
|
tomwalters@0
|
29 If file `name' is not found return null pointer.
|
tomwalters@0
|
30 */
|
tomwalters@0
|
31
|
tomwalters@0
|
32 FILE *fropen( name )
|
tomwalters@0
|
33 char *name ;
|
tomwalters@0
|
34 {
|
tomwalters@0
|
35 FILE *fopen() ;
|
tomwalters@0
|
36
|
tomwalters@0
|
37 if ( isstr( name, "-" ) ) return stdin ;
|
tomwalters@0
|
38 else return ( fopen( name, "r" ) ) ;
|
tomwalters@0
|
39 }
|
tomwalters@0
|
40
|
tomwalters@0
|
41
|
tomwalters@0
|
42 /*
|
tomwalters@0
|
43 Generic options handler and file opener.
|
tomwalters@0
|
44 Return a file pointer to an opened file, either stdin (if no args remained on
|
tomwalters@0
|
45 command line after scanning) or the first name left on the command line.
|
tomwalters@0
|
46 */
|
tomwalters@0
|
47
|
tomwalters@0
|
48 FILE *openopts( option, argc, argv )
|
tomwalters@0
|
49 Options *option ;
|
tomwalters@0
|
50 int argc ;
|
tomwalters@0
|
51 char *argv[] ;
|
tomwalters@0
|
52 {
|
tomwalters@0
|
53 FILE *fp ;
|
tomwalters@0
|
54 int i ;
|
tomwalters@0
|
55
|
tomwalters@0
|
56 if ( ( i = getopts( option, argc, argv ) ) == 0 )
|
tomwalters@0
|
57 return stdin ;
|
tomwalters@0
|
58 if ( ( fp = fropen( argv[argc-i] ) ) == (FILE *)0 ) {
|
tomwalters@0
|
59 fprintf(stderr, "%s: can't open %s\n", argv[0], argv[argc-i] ) ;
|
tomwalters@0
|
60 exit( 1 ) ;
|
tomwalters@0
|
61 }
|
tomwalters@0
|
62 return ( fp ) ;
|
tomwalters@0
|
63 }
|
tomwalters@0
|
64
|
tomwalters@0
|
65
|
tomwalters@0
|
66 /*
|
tomwalters@0
|
67 Options handler and two file opener.
|
tomwalters@0
|
68 If one file is on command line after scanning options, then the first file
|
tomwalters@0
|
69 fp1 is assumed to be the stdin. Otherwise two files are expected.
|
tomwalters@0
|
70 Return 0 if incorrect number of files, otherwise return 1.
|
tomwalters@0
|
71 (Note: fp1 and fp2 are pts to file ptrs, so pass them as &fp1, &fp2 if
|
tomwalters@0
|
72 originally declared as file ptrs).
|
tomwalters@0
|
73 */
|
tomwalters@0
|
74
|
tomwalters@0
|
75 open2opts( option, argc, argv, fp1, fp2 )
|
tomwalters@0
|
76 Options *option ;
|
tomwalters@0
|
77 int argc ;
|
tomwalters@0
|
78 char *argv[] ;
|
tomwalters@0
|
79 FILE **fp1 ;
|
tomwalters@0
|
80 FILE **fp2 ;
|
tomwalters@0
|
81 {
|
tomwalters@0
|
82 switch ( getopts( option, argc, argv ) ) {
|
tomwalters@0
|
83
|
tomwalters@0
|
84 case 1 :
|
tomwalters@0
|
85 *fp1 = stdin;
|
tomwalters@0
|
86 if ( ( *fp2 = fropen( argv[argc-1] ) ) == (FILE *)0 ) {
|
tomwalters@0
|
87 fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-1] ) ;
|
tomwalters@0
|
88 exit( 1 ) ;
|
tomwalters@0
|
89 }
|
tomwalters@0
|
90 break ;
|
tomwalters@0
|
91 case 2 :
|
tomwalters@0
|
92 if ( ( *fp1 = fropen( argv[argc-2] ) ) == (FILE *)0 ) {
|
tomwalters@0
|
93 fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-2] ) ;
|
tomwalters@0
|
94 exit( 1 ) ;
|
tomwalters@0
|
95 }
|
tomwalters@0
|
96 if ( ( *fp2 = fropen( argv[argc-1] ) ) == (FILE *)0 ) {
|
tomwalters@0
|
97 fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-1] ) ;
|
tomwalters@0
|
98 exit( 1 ) ;
|
tomwalters@0
|
99 }
|
tomwalters@0
|
100 break ;
|
tomwalters@0
|
101 default :
|
tomwalters@0
|
102 return ( 0 ) ;
|
tomwalters@0
|
103 }
|
tomwalters@0
|
104 return ( 1 ) ;
|
tomwalters@0
|
105 }
|
tomwalters@0
|
106
|
tomwalters@0
|
107
|
tomwalters@0
|
108
|
tomwalters@0
|
109 /*
|
tomwalters@0
|
110 Build an options table.
|
tomwalters@0
|
111 First assign all the option values with the defaults given in the table.
|
tomwalters@0
|
112 Then scan the command line for arguments to overwrite corresponding vals.
|
tomwalters@0
|
113
|
tomwalters@0
|
114 Argument syntax is one of the following three types (or combinations).
|
tomwalters@0
|
115 Each syntax must contain either a leading '-' char or an embedded '=' char,
|
tomwalters@0
|
116 to distinguish arguments from possible filenames.
|
tomwalters@0
|
117
|
tomwalters@0
|
118
|
tomwalters@0
|
119 1) -<name> FLAG_SYNTAX
|
tomwalters@0
|
120 2) -<name>[=]<value> ARG_SYNTAX
|
tomwalters@0
|
121 3) [-]<name>=<value> EQ_SYNTAX
|
tomwalters@0
|
122
|
tomwalters@0
|
123 FLAG_SYNTAX takes no value. (The returned value is the empty string).
|
tomwalters@0
|
124
|
tomwalters@0
|
125 ARG_SYNTAX takes a value after an optional '=' char.
|
tomwalters@0
|
126 If the '=' char is not found, then the <value> is whatever follows the
|
tomwalters@0
|
127 longest matching <name> string. Otherwise the <value> is whatever follows
|
tomwalters@0
|
128 the '=' char. (The value is not allowed to be empty).
|
tomwalters@0
|
129
|
tomwalters@0
|
130 EQ_SYNTAX takes a value which is whatever follows the '=' char.
|
tomwalters@0
|
131 (The value is not allowed to be empty).
|
tomwalters@0
|
132
|
tomwalters@0
|
133 It is assumed that all args remaining on the command line after an arg with
|
tomwalters@0
|
134 invalid syntax must be filenames. These remain unscanned.
|
tomwalters@0
|
135 Return argc, the number of args remaining unscanned on the command line,
|
tomwalters@0
|
136 (argc=0 if no args left).
|
tomwalters@0
|
137 To scan the remainder of the command line, and (eg) print the filenames:-
|
tomwalters@0
|
138
|
tomwalters@0
|
139 if ( ( i = getopts( option, argc, argv, ) ) == 0 )
|
tomwalters@0
|
140 printf("stdin\n" );
|
tomwalters@0
|
141 else
|
tomwalters@0
|
142 for ( ; i>0 ; i--)
|
tomwalters@0
|
143 printf("[%s]\n", argv[argc-i] );
|
tomwalters@0
|
144
|
tomwalters@0
|
145 */
|
tomwalters@0
|
146
|
tomwalters@0
|
147
|
tomwalters@0
|
148 int getopts( option, argc, argv )
|
tomwalters@0
|
149 Options *option ;
|
tomwalters@0
|
150 int argc ;
|
tomwalters@0
|
151 char *argv[] ;
|
tomwalters@0
|
152 {
|
tomwalters@0
|
153 char *prog, *val ;
|
tomwalters@0
|
154 int i, n, index[64], span[64] ;
|
tomwalters@0
|
155
|
tomwalters@0
|
156 /* Assign option vals using the defaults */
|
tomwalters@0
|
157
|
tomwalters@0
|
158 for (i=0 ; option[i].name != (char *)0 ; i++)
|
tomwalters@0
|
159 *(option[i].val) = option[i].dflt ;
|
tomwalters@0
|
160
|
tomwalters@0
|
161 /* Overwrite option vals with corresponding vals found on command line */
|
tomwalters@0
|
162
|
tomwalters@0
|
163 prog = *argv ;
|
tomwalters@0
|
164 while ( --argc > 0 && ++argv ) {
|
tomwalters@0
|
165
|
tomwalters@0
|
166 /* find list of options all with longest matching name span */
|
tomwalters@0
|
167 /* returning if none, with argc args remaining */
|
tomwalters@0
|
168 if ( ( n = whichopt( option, *argv, index, span ) ) == 0 )
|
tomwalters@0
|
169 return ( argc ) ;
|
tomwalters@0
|
170
|
tomwalters@0
|
171 /* check arg syntax, returning if invalid with argc args remaining */
|
tomwalters@0
|
172 for ( i=0 ; i<n && ( val = checksyntax( *argv, span[i], option[index[i]].type ) ) == (char *)0 ; i++ )
|
tomwalters@0
|
173 ;
|
tomwalters@0
|
174 if ( val == (char *)0 )
|
tomwalters@0
|
175 return ( argc ) ;
|
tomwalters@0
|
176
|
tomwalters@0
|
177 /* if whichopt was ambiguous, yet an arg is valid, then its an */
|
tomwalters@0
|
178 /* ambiguous option, (and not a possible filename). */
|
tomwalters@0
|
179 if ( n > 1 ) {
|
tomwalters@0
|
180 fprintf(stderr,"%s: ambiguous option [%s]\n", prog, *argv ) ;
|
tomwalters@0
|
181 exit ( 1 ) ;
|
tomwalters@0
|
182 }
|
tomwalters@0
|
183
|
tomwalters@0
|
184 /* do operation */
|
tomwalters@0
|
185 operate( option, *index, val ) ;
|
tomwalters@0
|
186 side_effect( option, *index ) ;
|
tomwalters@0
|
187
|
tomwalters@0
|
188 }
|
tomwalters@0
|
189 return argc ;
|
tomwalters@0
|
190 }
|
tomwalters@0
|
191
|
tomwalters@0
|
192
|
tomwalters@0
|
193 /*
|
tomwalters@0
|
194 Find the default value of the first option whose name unambiguously matches
|
tomwalters@0
|
195 `s' (possibly abbreviated).
|
tomwalters@0
|
196 Return a ptr to the default value of the matching option.
|
tomwalters@0
|
197 Otherwise return the null ptr if a matching name is not found or is ambiguous.
|
tomwalters@0
|
198 */
|
tomwalters@0
|
199
|
tomwalters@0
|
200 char *optdflt( option, s )
|
tomwalters@0
|
201 Options *option ;
|
tomwalters@0
|
202 char *s ;
|
tomwalters@0
|
203 {
|
tomwalters@0
|
204 int i ;
|
tomwalters@0
|
205
|
tomwalters@0
|
206 if ( ( i = optindex( option, s ) ) < 0 )
|
tomwalters@0
|
207 return ( (char *)0 ) ;
|
tomwalters@0
|
208 return ( option[i].dflt ) ;
|
tomwalters@0
|
209 }
|
tomwalters@0
|
210
|
tomwalters@0
|
211 /*
|
tomwalters@0
|
212 Find the option whose name unambiguously matches `s' (possibly abbreviated).
|
tomwalters@0
|
213 Return the option list index of the matching option.
|
tomwalters@0
|
214 Otherwise return -1 if a matching name is not found, or -2 if the name is
|
tomwalters@0
|
215 ambiguous.
|
tomwalters@0
|
216 */
|
tomwalters@0
|
217
|
tomwalters@0
|
218 int optindex( option, s )
|
tomwalters@0
|
219 Options *option ;
|
tomwalters@0
|
220 char *s ;
|
tomwalters@0
|
221 {
|
tomwalters@0
|
222 int i, n, index[64], span[64] ;
|
tomwalters@0
|
223
|
tomwalters@0
|
224 if ( ( n = whichopt( option, s, index, span ) ) == 0 )
|
tomwalters@0
|
225 return (-1) ; /* option not found */
|
tomwalters@0
|
226 if ( n > 1 )
|
tomwalters@0
|
227 return (-2) ; /* option name ambiguous */
|
tomwalters@0
|
228 return ( *index ) ;
|
tomwalters@0
|
229 }
|
tomwalters@0
|
230
|
tomwalters@0
|
231
|
tomwalters@0
|
232 /*
|
tomwalters@0
|
233 Find the option whose name has the longest matching span with the head of `s'
|
tomwalters@0
|
234 (the argument string, possibly abbreviated or with trailing value parts).
|
tomwalters@0
|
235 Pass the option list index of the matching option back via arg `index'.
|
tomwalters@0
|
236 Pass the length of the matching span back via arg `span'.
|
tomwalters@0
|
237 Return the number of options found which have an equal longest matching span.
|
tomwalters@0
|
238 (Any `-' at the head of `s' is skipped before matching).
|
tomwalters@0
|
239 If there is an exact match (ie the longest matching span equals the length of
|
tomwalters@0
|
240 the option name) then return an unambiguous match.
|
tomwalters@0
|
241 */
|
tomwalters@0
|
242
|
tomwalters@0
|
243 int whichopt( option, s, index, span )
|
tomwalters@0
|
244 Options *option ;
|
tomwalters@0
|
245 char *s ;
|
tomwalters@0
|
246 int *index, *span ;
|
tomwalters@0
|
247 {
|
tomwalters@0
|
248 int i, j, n = 0, jmax = 0 ;
|
tomwalters@0
|
249
|
tomwalters@0
|
250 if ( *s == '-' ) s++ ; /* Skip leading hyphen */
|
tomwalters@0
|
251
|
tomwalters@0
|
252 for ( i = 0 ; option[i].name != (char *)0 ; i++ ) {
|
tomwalters@0
|
253
|
tomwalters@0
|
254 if ( ( j = streqspn( s, option[i].name ) ) > jmax ) {
|
tomwalters@0
|
255 jmax = j ; /* a new longest matching span */
|
tomwalters@0
|
256 n = 0 ;
|
tomwalters@0
|
257 index[n] = i ;
|
tomwalters@0
|
258 span[n++] = j ;
|
tomwalters@0
|
259 }
|
tomwalters@0
|
260 else if ( j > 0 && j == jmax ) { /* ambiguous name with same matching span */
|
tomwalters@0
|
261 index[n] = i ;
|
tomwalters@0
|
262 span[n++] = j ;
|
tomwalters@0
|
263 }
|
tomwalters@0
|
264 }
|
tomwalters@0
|
265
|
tomwalters@0
|
266 for ( i = 0 ; i < n ; i++ ) /* check for an exact match */
|
tomwalters@0
|
267 if ( span[i] == strlen( option[index[i]].name ) ) {
|
tomwalters@0
|
268 index[0] = index[i] ;
|
tomwalters@0
|
269 span[0] = span[i] ;
|
tomwalters@0
|
270 return 1 ;
|
tomwalters@0
|
271 }
|
tomwalters@0
|
272
|
tomwalters@0
|
273 return n ;
|
tomwalters@0
|
274 }
|
tomwalters@0
|
275
|
tomwalters@0
|
276
|
tomwalters@0
|
277 /*
|
tomwalters@0
|
278 Check arg syntax and return a pointer to the value part, (or a pointer to the
|
tomwalters@0
|
279 terminating null if the value part is empty).
|
tomwalters@0
|
280 Return a NULL pointer if the syntax is invalid. It is assumed then that the
|
tomwalters@0
|
281 current arg (and all remaining) is a filename.
|
tomwalters@0
|
282 Print a warning if the syntax is an error rather than a possible filename,
|
tomwalters@0
|
283 (the filename will not be found in this case).
|
tomwalters@0
|
284
|
tomwalters@0
|
285 The check is arranged so that different option syntax types can be OR'd.
|
tomwalters@0
|
286 */
|
tomwalters@0
|
287
|
tomwalters@0
|
288 char *checksyntax( s, span, type )
|
tomwalters@0
|
289 char *s ;
|
tomwalters@0
|
290 int span, type ;
|
tomwalters@0
|
291 {
|
tomwalters@0
|
292 int i ;
|
tomwalters@0
|
293 char *v, *val = (char *)0 ;
|
tomwalters@0
|
294
|
tomwalters@0
|
295 if ( bitset( type, FLAG_SYNTAX ) ) { /* -<name> */
|
tomwalters@0
|
296 if ( *s == '-' && *(v = s+1 + span) == '\0' )
|
tomwalters@0
|
297 val = v ;
|
tomwalters@0
|
298 }
|
tomwalters@0
|
299
|
tomwalters@0
|
300 if ( bitset( type, ARG_SYNTAX ) ) { /* -<name>[=]<value> */
|
tomwalters@0
|
301 if ( *s == '-' ) {
|
tomwalters@0
|
302 if ( *(v = s+1 + span) == '=' ) v++ ;
|
tomwalters@0
|
303 if ( *v != '\0' ) val = v ;
|
tomwalters@0
|
304 }
|
tomwalters@0
|
305 }
|
tomwalters@0
|
306
|
tomwalters@0
|
307 if ( bitset( type, EQ_SYNTAX ) ) { /* [-]<name>=<value> */
|
tomwalters@0
|
308 if ( *s == '-' ) s++ ;
|
tomwalters@0
|
309 if ( *(v = s + span) == '=' && *++v != '\0' )
|
tomwalters@0
|
310 val = v ;
|
tomwalters@0
|
311 }
|
tomwalters@0
|
312
|
tomwalters@0
|
313 return ( val ) ;
|
tomwalters@0
|
314 }
|
tomwalters@0
|
315
|
tomwalters@0
|
316
|
tomwalters@0
|
317 /*
|
tomwalters@0
|
318 Return 1 if string s a possible option, (ie. a string which is not a <number>,
|
tomwalters@0
|
319 and contains either an embedded '=' or a leading '-').
|
tomwalters@0
|
320 Otherwise return 0.
|
tomwalters@0
|
321 */
|
tomwalters@0
|
322
|
tomwalters@0
|
323 int isopt( s )
|
tomwalters@0
|
324 char *s ;
|
tomwalters@0
|
325 {
|
tomwalters@0
|
326 if ( isnumber( s ) ) return 0 ;
|
tomwalters@0
|
327 if ( *s == '-' ) return 1 ;
|
tomwalters@0
|
328 if ( strchr( s, '=' ) != (char *)0 ) return 1 ;
|
tomwalters@0
|
329 return 0 ;
|
tomwalters@0
|
330 }
|
tomwalters@0
|
331
|
tomwalters@0
|
332
|
tomwalters@0
|
333 operate( option, i, val )
|
tomwalters@0
|
334 Options *option ;
|
tomwalters@0
|
335 int i ;
|
tomwalters@0
|
336 char *val ;
|
tomwalters@0
|
337 {
|
tomwalters@0
|
338 if ( bitset( option[i].type, LATCH ) ) /* LATCH */
|
tomwalters@0
|
339 *(option[i].val) = val ;
|
tomwalters@0
|
340
|
tomwalters@0
|
341 else if ( bitset( option[i].type, AND ) ) /* AND */
|
tomwalters@0
|
342 *(option[i].val) = offstr ;
|
tomwalters@0
|
343
|
tomwalters@0
|
344 else if ( bitset( option[i].type, OR ) ) /* OR */
|
tomwalters@0
|
345 *(option[i].val) = onstr ;
|
tomwalters@0
|
346
|
tomwalters@0
|
347 else if ( bitset( option[i].type, TOGGLE ) ) { /* TOGGLE */
|
tomwalters@0
|
348 if ( isempty( val ) ) {
|
tomwalters@0
|
349 if ( ison( *(option[i].val) ) )
|
tomwalters@0
|
350 *(option[i].val) = offstr ;
|
tomwalters@0
|
351 else
|
tomwalters@0
|
352 *(option[i].val) = onstr ;
|
tomwalters@0
|
353 }
|
tomwalters@0
|
354 else *(option[i].val) = val ;
|
tomwalters@0
|
355 }
|
tomwalters@0
|
356 }
|
tomwalters@0
|
357
|
tomwalters@0
|
358
|
tomwalters@0
|
359 /*
|
tomwalters@0
|
360 Side-effects of options type specifiers.
|
tomwalters@0
|
361 */
|
tomwalters@0
|
362
|
tomwalters@0
|
363 side_effect( option, j )
|
tomwalters@0
|
364 Options *option ;
|
tomwalters@0
|
365 int j ;
|
tomwalters@0
|
366 {
|
tomwalters@0
|
367 int i ;
|
tomwalters@0
|
368 char *exstr ;
|
tomwalters@0
|
369
|
tomwalters@0
|
370 if ( bitset( option[j].type, EXCLUDE ) ) { /* EXCLUDE */
|
tomwalters@0
|
371 if ( ison( *(option[j].val) ) )
|
tomwalters@0
|
372 exstr = offstr ;
|
tomwalters@0
|
373 else
|
tomwalters@0
|
374 exstr = onstr ;
|
tomwalters@0
|
375 for ( i=0; option[i].name != (char *)0 ; i++)
|
tomwalters@0
|
376 if ( i != j && bitset( option[i].type, EXCLUDE ) )
|
tomwalters@0
|
377 *(option[i].val) = exstr ;
|
tomwalters@0
|
378 }
|
tomwalters@0
|
379 }
|
tomwalters@0
|
380
|
tomwalters@0
|
381
|
tomwalters@0
|
382
|
tomwalters@0
|
383 /*
|
tomwalters@0
|
384 Separate an option value string `optval' into two string tokens at the first
|
tomwalters@0
|
385 occurrence of a separator character `sep'. (Given as a string of one char).
|
tomwalters@0
|
386 Return the tokens via the pointers `val1' and `val2' (which could be passed
|
tomwalters@0
|
387 as the addresses of string pointers).
|
tomwalters@0
|
388 Return BADVAL if the option value string is bad (meaning that either `optval' was
|
tomwalters@0
|
389 null or empty, or the separator char was found but the 2nd token was missing).
|
tomwalters@0
|
390 Return 1 if the option value string is good (meaning that either two tokens
|
tomwalters@0
|
391 were found, or only the 1st token with no separator char, in which case `val2'
|
tomwalters@0
|
392 will be a ptr to an empty string). (See routine strpsep()).
|
tomwalters@0
|
393 */
|
tomwalters@0
|
394
|
tomwalters@0
|
395 int getvals( optval, val1, val2, sep )
|
tomwalters@0
|
396 char *optval ;
|
tomwalters@0
|
397 char **val1, **val2 ;
|
tomwalters@0
|
398 char *sep ;
|
tomwalters@0
|
399 {
|
tomwalters@0
|
400 *val1 = optval ;
|
tomwalters@0
|
401 if ( isnull( *val2 = strsep( optval, sep ) ) )
|
tomwalters@0
|
402 return BADVAL ;
|
tomwalters@0
|
403 return 1 ;
|
tomwalters@0
|
404 }
|
tomwalters@0
|
405
|
tomwalters@0
|
406
|
tomwalters@0
|
407 /*
|
tomwalters@0
|
408 Parse a range selector of the form: a[-b]
|
tomwalters@0
|
409 Return 0 if bad selectors, otherwise return 1.
|
tomwalters@0
|
410 Items are numbered 1,2,...,max, (where max is 0 by convention).
|
tomwalters@0
|
411 When either limit is "min", then set the respective value to 1.
|
tomwalters@0
|
412 When either limit is "max", then set the respective value to 0.
|
tomwalters@0
|
413 When `b' is missing, then set b=a.
|
tomwalters@0
|
414
|
tomwalters@0
|
415 If (a==0) then seek eof and process the final item.
|
tomwalters@0
|
416 Else seek past (a-1) items, and then process the next (b-a+1) items
|
tomwalters@0
|
417 (or all items until eof if (b==0)).
|
tomwalters@0
|
418 Eg:
|
tomwalters@0
|
419 seekstart( a-1, bytes, fp ) ;
|
tomwalters@0
|
420 for ( i = 0 ; ( b == 0 || i < b-a+1 ) ; i++ )
|
tomwalters@0
|
421 do process
|
tomwalters@0
|
422
|
tomwalters@0
|
423 */
|
tomwalters@0
|
424
|
tomwalters@0
|
425 int selector( s, a, b )
|
tomwalters@0
|
426 char *s ;
|
tomwalters@0
|
427 int *a, *b ;
|
tomwalters@0
|
428 {
|
tomwalters@0
|
429 char *val1, *val2 ;
|
tomwalters@0
|
430
|
tomwalters@0
|
431 if ( getvals( s, &val1, &val2, "-" ) == BADVAL )
|
tomwalters@0
|
432 return ( 0 ) ;
|
tomwalters@0
|
433 if ( ismin( val1 ) ) *a = 1 ; /* first object */
|
tomwalters@0
|
434 else if ( ismax( val1 ) ) *a = 0 ; /* last object */
|
tomwalters@0
|
435 else if ( ( *a = atoi( val1 ) ) <= 0 ) { /* intermediate object */
|
tomwalters@0
|
436 if ( *a == 0 ) fprintf( stderr,"warning: selected items are numbered 1,...,max\n" ) ;
|
tomwalters@0
|
437 return ( 0 ) ;
|
tomwalters@0
|
438 }
|
tomwalters@0
|
439 if ( isempty( val2 ) ) *b = *a ; /* single object */
|
tomwalters@0
|
440 else if ( ismin( val2 ) ) *b = 1 ;
|
tomwalters@0
|
441 else if ( ismax( val2 ) ) *b = 0 ;
|
tomwalters@0
|
442 else if ( ( *b = atoi( val2 ) ) <= 0 ) {
|
tomwalters@0
|
443 return ( 0 ) ;
|
tomwalters@0
|
444 }
|
tomwalters@0
|
445 if ( *b > 0 && ( *a == 0 || *a > *b ) )
|
tomwalters@0
|
446 return ( 0 ) ;
|
tomwalters@0
|
447
|
tomwalters@0
|
448 return ( 1 ) ;
|
tomwalters@0
|
449 }
|
tomwalters@0
|
450
|
tomwalters@0
|
451
|
tomwalters@0
|
452 /*
|
tomwalters@0
|
453 Parse a time range selector of the form: a[-b]
|
tomwalters@0
|
454 The range is returned as limits meaning: start==a duration==b-a+1.
|
tomwalters@0
|
455 (Note: when range=max or range=max-max then a==b==(-1) and duration==1).
|
tomwalters@0
|
456 Return 0 if bad selectors, otherwise return 1.
|
tomwalters@0
|
457 Time is numbered 0,2,...,max, (where max is (-1) by convention).
|
tomwalters@0
|
458 When either limit is "min", then set the respective value to 0.
|
tomwalters@0
|
459 When either limit is "max", then set the respective value to (-1).
|
tomwalters@0
|
460 When `b' is missing, then set b=a.
|
tomwalters@0
|
461 Time is specified as <number>[<units>], where <units> = {p, ms, s}.
|
tomwalters@0
|
462 Empty units are interpreted as `p' (ie sample points).
|
tomwalters@0
|
463 Convert `a' and `b' to sample points using the given samplerate.
|
tomwalters@0
|
464
|
tomwalters@0
|
465 (Note: this is like selector() but using to_p() instead of atoi(), and
|
tomwalters@0
|
466 numbering from 0 instead of 1).
|
tomwalters@0
|
467
|
tomwalters@0
|
468 If (a<0) then seek eof and process the final item.
|
tomwalters@0
|
469 Else seek past (a) items, and then process the next (b-a+1) items
|
tomwalters@0
|
470 (or all items until eof if (b==-1)).
|
tomwalters@0
|
471 Eg:
|
tomwalters@0
|
472 seekstart( a, bytes, fp ) ;
|
tomwalters@0
|
473 for ( i = 0 ; ( b < 0 || i < b-a+1 ) ; i++ )
|
tomwalters@0
|
474 do process
|
tomwalters@0
|
475
|
tomwalters@0
|
476 */
|
tomwalters@0
|
477
|
tomwalters@0
|
478 int range( s, a, b, samplerate )
|
tomwalters@0
|
479 char *s ;
|
tomwalters@0
|
480 int *a, *b ;
|
tomwalters@0
|
481 int samplerate ;
|
tomwalters@0
|
482 {
|
tomwalters@0
|
483 char *val1, *val2 ;
|
tomwalters@0
|
484
|
tomwalters@0
|
485 if ( getvals( s, &val1, &val2, "-" ) == BADVAL )
|
tomwalters@0
|
486 return ( 0 ) ;
|
tomwalters@0
|
487 if ( ismin( val1 ) ) *a = 0 ; /* first object */
|
tomwalters@0
|
488 else if ( ismax( val1 ) ) *a = (-1) ; /* last object */
|
tomwalters@0
|
489 else if ( ( *a = to_p( val1, samplerate ) ) < 0 ) {
|
tomwalters@0
|
490 return ( 0 ) ;
|
tomwalters@0
|
491 }
|
tomwalters@0
|
492 if ( isempty( val2 ) ) *b = *a ; /* single object */
|
tomwalters@0
|
493 else if ( ismin( val2 ) ) *b = 0 ;
|
tomwalters@0
|
494 else if ( ismax( val2 ) ) *b = (-1) ;
|
tomwalters@0
|
495 else if ( ( *b = to_p( val2, samplerate ) ) < 0 ) {
|
tomwalters@0
|
496 return ( 0 ) ;
|
tomwalters@0
|
497 }
|
tomwalters@0
|
498 if ( *b >= 0 && ( *a < 0 || *a > *b ) )
|
tomwalters@0
|
499 return ( 0 ) ;
|
tomwalters@0
|
500
|
tomwalters@0
|
501 return ( 1 ) ;
|
tomwalters@0
|
502 }
|
tomwalters@0
|
503
|
tomwalters@0
|
504
|
tomwalters@0
|
505 /*
|
tomwalters@0
|
506 Seek n items of size bytes from current position in stream.
|
tomwalters@0
|
507 (Unlike fseek, this works even when fp is stdin).
|
tomwalters@0
|
508 Return the number of items actually read.
|
tomwalters@0
|
509 Example: seekstart( n, sizeof(short), fp );
|
tomwalters@0
|
510 Datatype "ASCII" is a special case for which 0 is returned by the databytes
|
tomwalters@0
|
511 routine, so bytes==0 is taken to mean seek n ascii lines. In general use:
|
tomwalters@0
|
512 seekstart( n, databytes( typestr ), fp )
|
tomwalters@0
|
513 */
|
tomwalters@0
|
514
|
tomwalters@0
|
515 seekstart( n, bytes, fp )
|
tomwalters@0
|
516 int n, bytes ;
|
tomwalters@0
|
517 FILE *fp ;
|
tomwalters@0
|
518 {
|
tomwalters@0
|
519 int i ;
|
tomwalters@0
|
520 char *buf ;
|
tomwalters@0
|
521 char *line ;
|
tomwalters@0
|
522
|
tomwalters@0
|
523 if ( bytes == 0 ) { /* special case meaning ascii lines */
|
tomwalters@0
|
524 line = (char *)malloc( LINE_LENGTH ) ;
|
tomwalters@0
|
525 for ( i = 0 ; i < n && fgets( line, LINE_LENGTH, fp ) != (char *)0 ; i++ )
|
tomwalters@0
|
526 ;
|
tomwalters@0
|
527 free( line ) ;
|
tomwalters@0
|
528 return ( i ) ;
|
tomwalters@0
|
529 }
|
tomwalters@0
|
530
|
tomwalters@0
|
531 if ( fp != stdin ) {
|
tomwalters@0
|
532 if ( fseek( fp, (long)( n * bytes ), 1 ) == 0 )
|
tomwalters@0
|
533 return n ; /* if improper, look for any input */
|
tomwalters@0
|
534 }
|
tomwalters@0
|
535
|
tomwalters@0
|
536 if ( ( buf = (char *)malloc( bytes ) ) == (char *)0 ) {
|
tomwalters@0
|
537 fprintf( stderr, "seekstart: cannot allocate %d bytes\n", bytes ) ;
|
tomwalters@0
|
538 exit( 1 ) ;
|
tomwalters@0
|
539 }
|
tomwalters@0
|
540
|
tomwalters@0
|
541 for ( i = 0 ; i < n && fread( buf, bytes, 1, fp ) ; i++ )
|
tomwalters@0
|
542 ;
|
tomwalters@0
|
543 free( buf ) ;
|
tomwalters@0
|
544
|
tomwalters@0
|
545 return ( i ) ;
|
tomwalters@0
|
546 }
|
tomwalters@0
|
547
|
tomwalters@0
|
548
|
tomwalters@0
|
549 /*
|
tomwalters@0
|
550 Seek n items of of given type from current position in stream.
|
tomwalters@0
|
551 This seekstart version takes a `type' arg instead of a size in `bytes'.
|
tomwalters@0
|
552 The `type' is an index to the datatype list in options.h, obtained for
|
tomwalters@0
|
553 example using: typeindex( typestr ).
|
tomwalters@0
|
554 */
|
tomwalters@0
|
555
|
tomwalters@0
|
556 seektype( n, type, fp )
|
tomwalters@0
|
557 int n, type ;
|
tomwalters@0
|
558 FILE *fp ;
|
tomwalters@0
|
559 {
|
tomwalters@0
|
560 return ( seekstart( n, typebytes( type ), fp ) ) ;
|
tomwalters@0
|
561 }
|
tomwalters@0
|
562
|
tomwalters@0
|
563
|
tomwalters@0
|
564 /*
|
tomwalters@0
|
565 Read the next n items of `type' from the given stream.
|
tomwalters@0
|
566 The `type' is an index to the datatype list in options.h, obtained for
|
tomwalters@0
|
567 example using: typeindex( typestr ).
|
tomwalters@0
|
568 Assign the item as a float in address `y', and return 1.
|
tomwalters@0
|
569 Return 0 if eof or error.
|
tomwalters@0
|
570 This can replace fread, eg:
|
tomwalters@0
|
571 fread( &p, sizeof(short), 1, fp ) ( with short p )
|
tomwalters@0
|
572 becomes:
|
tomwalters@0
|
573 readitem( &y, typeindex( "short" ), 1, fp ) ( with float y )
|
tomwalters@0
|
574 */
|
tomwalters@0
|
575
|
tomwalters@0
|
576 readitem( y, type, n, fp )
|
tomwalters@0
|
577 float *y ;
|
tomwalters@0
|
578 int type ;
|
tomwalters@0
|
579 int n ;
|
tomwalters@0
|
580 FILE *fp ;
|
tomwalters@0
|
581 {
|
tomwalters@0
|
582 char c ; short s ; int i ; float f ; double d ;
|
tomwalters@0
|
583 int j ;
|
tomwalters@0
|
584 static char *line ;
|
tomwalters@0
|
585 static int first = 1 ;
|
tomwalters@0
|
586
|
tomwalters@0
|
587 switch ( type ) {
|
tomwalters@0
|
588 case 0 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
589 if ( fread( &c, sizeof(char), 1, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
590 *y++ = (float)c ;
|
tomwalters@0
|
591 }
|
tomwalters@0
|
592 break ;
|
tomwalters@0
|
593 case 1 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
594 if ( fread( &s, sizeof(short), 1, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
595 *y++ = (float)s ;
|
tomwalters@0
|
596 }
|
tomwalters@0
|
597 break ;
|
tomwalters@0
|
598 case 2 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
599 if ( fread( &i, sizeof(int), 1, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
600 *y++ = (float)i ;
|
tomwalters@0
|
601 }
|
tomwalters@0
|
602 break ;
|
tomwalters@0
|
603 case 3 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
604 if ( fread( &f, sizeof(float), 1, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
605 *y++ = (float)f ;
|
tomwalters@0
|
606 }
|
tomwalters@0
|
607 break ;
|
tomwalters@0
|
608 case 4 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
609 if ( fread( &d, sizeof(double), 1, fp ) == 0 ) return 0 ;
|
tomwalters@0
|
610 *y++ = (float)d ;
|
tomwalters@0
|
611 }
|
tomwalters@0
|
612 break ;
|
tomwalters@0
|
613 case 5 :
|
tomwalters@0
|
614 case 6 : if ( first ) {
|
tomwalters@0
|
615 line = (char *)malloc( LINE_LENGTH ) ;
|
tomwalters@0
|
616 first = 0 ;
|
tomwalters@0
|
617 }
|
tomwalters@0
|
618 for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
619 if ( fgets( line, LINE_LENGTH, fp ) == (char *)0 ) return 0 ;
|
tomwalters@0
|
620 *y++ = atof( line ) ;
|
tomwalters@0
|
621 }
|
tomwalters@0
|
622 break ;
|
tomwalters@0
|
623 }
|
tomwalters@0
|
624 return 1 ;
|
tomwalters@0
|
625 }
|
tomwalters@0
|
626
|
tomwalters@0
|
627
|
tomwalters@0
|
628 /*
|
tomwalters@0
|
629 Write the given n items of `type' onto the given stream.
|
tomwalters@0
|
630 The `type' is an index to the datatype list in options.h, (obtained for
|
tomwalters@0
|
631 example using: typeindex( typestr ) ).
|
tomwalters@0
|
632 */
|
tomwalters@0
|
633
|
tomwalters@0
|
634 writeitem( y, type, n, fp )
|
tomwalters@0
|
635 float *y ;
|
tomwalters@0
|
636 int type ;
|
tomwalters@0
|
637 int n ;
|
tomwalters@0
|
638 FILE *fp ;
|
tomwalters@0
|
639 {
|
tomwalters@0
|
640 char c ; short s ; int i ; float f ; double d ;
|
tomwalters@0
|
641 int j ;
|
tomwalters@0
|
642
|
tomwalters@0
|
643 switch ( type ) {
|
tomwalters@0
|
644 case 0 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
645 c = (char) *y++ ;
|
tomwalters@0
|
646 fwrite( &c, sizeof(char), 1, fp ) ;
|
tomwalters@0
|
647 }
|
tomwalters@0
|
648 break ;
|
tomwalters@0
|
649 case 1 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
650 s = (short) *y++ ;
|
tomwalters@0
|
651 fwrite( &s, sizeof(short), 1, fp ) ;
|
tomwalters@0
|
652 }
|
tomwalters@0
|
653 break ;
|
tomwalters@0
|
654 case 2 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
655 i = (int) *y++ ;
|
tomwalters@0
|
656 fwrite( &i, sizeof(int), 1, fp ) ;
|
tomwalters@0
|
657 }
|
tomwalters@0
|
658 break ;
|
tomwalters@0
|
659 case 3 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
660 f = (float) *y++ ;
|
tomwalters@0
|
661 fwrite( &f, sizeof(float), 1, fp ) ;
|
tomwalters@0
|
662 }
|
tomwalters@0
|
663 break ;
|
tomwalters@0
|
664 case 4 : for ( j = 0 ; j < n ; j++ ) {
|
tomwalters@0
|
665 d = (double) *y++ ;
|
tomwalters@0
|
666 fwrite( &d, sizeof(double), 1, fp ) ;
|
tomwalters@0
|
667 }
|
tomwalters@0
|
668 break ;
|
tomwalters@0
|
669 case 5 :
|
tomwalters@0
|
670 case 6 : for ( j = 0 ; j < n ; j++ )
|
tomwalters@0
|
671 fprintf( fp, "%*.*f\n", FIELDWIDTH, PRECISION, *y++ ) ;
|
tomwalters@0
|
672 break ;
|
tomwalters@0
|
673 }
|
tomwalters@0
|
674 }
|
tomwalters@0
|
675
|
tomwalters@0
|
676
|
tomwalters@0
|
677 /*
|
tomwalters@0
|
678 Read the next n items of `type' from the given stream within inclusive range
|
tomwalters@0
|
679 limits `a' and `b', (found using, eg: range( rangestr, &a, &b, samplerate ) ).
|
tomwalters@0
|
680 This is a version of readitem which incorporates the intial seek and handles
|
tomwalters@0
|
681 range=max correctly.
|
tomwalters@0
|
682 The `type' is an index to the datatype list in options.h, obtained for
|
tomwalters@0
|
683 example using: typeindex( typestr ).
|
tomwalters@0
|
684 Assign the item as a float in address `y', and return the number of items
|
tomwalters@0
|
685 read. Return 0 if eof or error.
|
tomwalters@0
|
686 */
|
tomwalters@0
|
687
|
tomwalters@0
|
688 nextitem( y, type, n, fp, a, b )
|
tomwalters@0
|
689 float *y ;
|
tomwalters@0
|
690 int type ;
|
tomwalters@0
|
691 int n ;
|
tomwalters@0
|
692 FILE *fp ;
|
tomwalters@0
|
693 int a, b ;
|
tomwalters@0
|
694 {
|
tomwalters@0
|
695 static int count = 0 ; /* total items read over all calls */
|
tomwalters@0
|
696 int num ; /* number items read this call */
|
tomwalters@0
|
697 float x ;
|
tomwalters@0
|
698
|
tomwalters@0
|
699 if ( count == 0 ) {
|
tomwalters@0
|
700
|
tomwalters@0
|
701 if ( a == (-1) ) { /* range=max or range=max-max */
|
tomwalters@0
|
702 if ( n == 1 && readitem( &x, type, 1, fp ) ) {
|
tomwalters@0
|
703 *y = x ;
|
tomwalters@0
|
704 while ( readitem( &x, type, 1, fp ) )
|
tomwalters@0
|
705 *y = x ;
|
tomwalters@0
|
706 num = 1 ;
|
tomwalters@0
|
707 }
|
tomwalters@0
|
708 else num = 0 ;
|
tomwalters@0
|
709 }
|
tomwalters@0
|
710
|
tomwalters@0
|
711 else {
|
tomwalters@0
|
712 if ( seektype( a, type, fp ) < a )
|
tomwalters@0
|
713 num = 0 ;
|
tomwalters@0
|
714 else {
|
tomwalters@0
|
715 if ( b >= 0 && n > b-a+1 ) /* n restricted by upper limit */
|
tomwalters@0
|
716 n = b-a+1 ;
|
tomwalters@0
|
717 for ( num = 0 ; num < n && readitem( &x, type, 1, fp ) ; num++ )
|
tomwalters@0
|
718 y[num] = x ;
|
tomwalters@0
|
719 }
|
tomwalters@0
|
720 }
|
tomwalters@0
|
721
|
tomwalters@0
|
722 count += num ;
|
tomwalters@0
|
723 }
|
tomwalters@0
|
724
|
tomwalters@0
|
725 else {
|
tomwalters@0
|
726 if ( b >= 0 && count >= b-a+1 )
|
tomwalters@0
|
727 num = 0 ;
|
tomwalters@0
|
728 else {
|
tomwalters@0
|
729 if ( b >= 0 && n > b-a+1 - count ) /* n restricted by upper limit */
|
tomwalters@0
|
730 n = b-a+1 - count ;
|
tomwalters@0
|
731 for ( num = 0 ; num < n && readitem( &x, type, 1, fp ) ; num++ )
|
tomwalters@0
|
732 y[num] = x ;
|
tomwalters@0
|
733 }
|
tomwalters@0
|
734
|
tomwalters@0
|
735 count += num ;
|
tomwalters@0
|
736 }
|
tomwalters@0
|
737
|
tomwalters@0
|
738 return num ;
|
tomwalters@0
|
739 }
|
tomwalters@0
|
740
|
tomwalters@0
|
741
|
tomwalters@0
|
742
|
tomwalters@0
|
743
|
tomwalters@0
|
744 /*
|
tomwalters@0
|
745 Return the type index (to the datatype list in options.h) of the given type
|
tomwalters@0
|
746 string. String matching allows for abbreviations.
|
tomwalters@0
|
747 If the given type string is in error then return an error code (less than 0):
|
tomwalters@0
|
748 -1 type string not found in datatype list.
|
tomwalters@0
|
749 -2 type string is ambiguous.
|
tomwalters@0
|
750 */
|
tomwalters@0
|
751
|
tomwalters@0
|
752 int typeindex( typestr )
|
tomwalters@0
|
753 char *typestr ;
|
tomwalters@0
|
754 {
|
tomwalters@0
|
755 return ( listindex( datatype, typestr ) ) ;
|
tomwalters@0
|
756 }
|
tomwalters@0
|
757
|
tomwalters@0
|
758
|
tomwalters@0
|
759 /*
|
tomwalters@0
|
760 Return a number of bytes for a given type index (to the datatype list in
|
tomwalters@0
|
761 options.h). Datatype "ASCII" is a special case for which 0 is returned.
|
tomwalters@0
|
762 */
|
tomwalters@0
|
763
|
tomwalters@0
|
764 int typebytes( type )
|
tomwalters@0
|
765 int type ;
|
tomwalters@0
|
766 {
|
tomwalters@0
|
767 int bytes ;
|
tomwalters@0
|
768
|
tomwalters@0
|
769 switch ( type ) {
|
tomwalters@0
|
770 case 0 : bytes = sizeof( char ) ; break ;
|
tomwalters@0
|
771 case 1 : bytes = sizeof( short ) ; break ;
|
tomwalters@0
|
772 case 2 : bytes = sizeof( int ) ; break ;
|
tomwalters@0
|
773 case 3 : bytes = sizeof( float ) ; break ;
|
tomwalters@0
|
774 case 4 : bytes = sizeof( double ) ; break ;
|
tomwalters@0
|
775 case 5 : /* ASCII */
|
tomwalters@0
|
776 case 6 : bytes = 0 ; break ; /* ascii */
|
tomwalters@0
|
777 }
|
tomwalters@0
|
778 return ( bytes ) ;
|
tomwalters@0
|
779 }
|
tomwalters@0
|
780
|
tomwalters@0
|
781
|
tomwalters@0
|
782
|
tomwalters@0
|
783 /*
|
tomwalters@0
|
784 Return a number of bytes for a given type string.
|
tomwalters@0
|
785 The string can be a number (of bytes), or a token from the `datatype' list,
|
tomwalters@0
|
786 (see options.h) with which it is matched, allowing for abbreviations.
|
tomwalters@0
|
787 Datatype "ASCII" or "ascii" is a special case for which 0 is returned.
|
tomwalters@0
|
788 If the given type string is in error then return an error code (less than 0):
|
tomwalters@0
|
789 -1 type string not found in datatype list.
|
tomwalters@0
|
790 -2 type string is ambiguous.
|
tomwalters@0
|
791 -3 type string is a negative number.
|
tomwalters@0
|
792 */
|
tomwalters@0
|
793
|
tomwalters@0
|
794 int databytes( typestr )
|
tomwalters@0
|
795 char *typestr ;
|
tomwalters@0
|
796 {
|
tomwalters@0
|
797 int type, bytes ;
|
tomwalters@0
|
798
|
tomwalters@0
|
799 if ( isnumber( typestr ) ) { /* case of bytes number string */
|
tomwalters@0
|
800 if ( ( bytes = atoi( typestr ) ) < 0 )
|
tomwalters@0
|
801 return ( -3 ) ;
|
tomwalters@0
|
802 else return bytes ;
|
tomwalters@0
|
803 }
|
tomwalters@0
|
804
|
tomwalters@0
|
805 if ( ( type = typeindex( typestr ) ) < 0 )
|
tomwalters@0
|
806 return type ;
|
tomwalters@0
|
807
|
tomwalters@0
|
808 return ( typebytes( type ) ) ;
|
tomwalters@0
|
809 }
|
tomwalters@0
|
810
|
tomwalters@0
|
811
|
tomwalters@0
|
812 /*
|
tomwalters@0
|
813 Check for over or underflow when the given float is scaled and cast into the
|
tomwalters@0
|
814 given data type (an index to the datatype list in options.h).
|
tomwalters@0
|
815 Return a more appropriate scale factor, or a scale factor of 1 if no over
|
tomwalters@0
|
816 or underflow. The returned scale factor is the minimum scale factor over
|
tomwalters@0
|
817 a succession of calls to check_overflow.
|
tomwalters@0
|
818 */
|
tomwalters@0
|
819
|
tomwalters@0
|
820 float check_overflow( p, scale, type )
|
tomwalters@0
|
821 float p, scale ;
|
tomwalters@0
|
822 int type ;
|
tomwalters@0
|
823 {
|
tomwalters@0
|
824 float f, p1 = p * scale ;
|
tomwalters@0
|
825 static float first = 1 ;
|
tomwalters@0
|
826 static float max, newscale ;
|
tomwalters@0
|
827
|
tomwalters@0
|
828 if ( type >= 3 ) return ( 1. ) ;
|
tomwalters@0
|
829
|
tomwalters@0
|
830 if ( first ) {
|
tomwalters@0
|
831
|
tomwalters@0
|
832 switch ( type ) {
|
tomwalters@0
|
833 case 0 : max = pow( 2., 8.*sizeof(char)-1 ) - 1 ; break ;
|
tomwalters@0
|
834 case 1 : max = pow( 2., 8.*sizeof(short)-1 ) - 1 ; break ;
|
tomwalters@0
|
835 case 2 : max = pow( 2., 8.*sizeof(int)-1 ) - 1 ; break ;
|
tomwalters@0
|
836 }
|
tomwalters@0
|
837
|
tomwalters@0
|
838 newscale = 1. ;
|
tomwalters@0
|
839 first = 0 ;
|
tomwalters@0
|
840 }
|
tomwalters@0
|
841
|
tomwalters@0
|
842 if ( p1 > max ) f = max / p ;
|
tomwalters@0
|
843 else if ( p1 < (-max) ) f = -( max / p ) ;
|
tomwalters@0
|
844 else f = 1. ;
|
tomwalters@0
|
845
|
tomwalters@0
|
846 if ( f < newscale )
|
tomwalters@0
|
847 newscale = f ;
|
tomwalters@0
|
848
|
tomwalters@0
|
849 return ( newscale ) ;
|
tomwalters@0
|
850 }
|
tomwalters@0
|
851
|
tomwalters@0
|
852
|
tomwalters@0
|
853
|
tomwalters@0
|
854 /*
|
tomwalters@0
|
855 Some particular string tests.
|
tomwalters@0
|
856 */
|
tomwalters@0
|
857
|
tomwalters@0
|
858
|
tomwalters@0
|
859 /*
|
tomwalters@0
|
860 Test for "on" or any <number> string other than "0".
|
tomwalters@0
|
861 */
|
tomwalters@0
|
862
|
tomwalters@0
|
863 int ison( s )
|
tomwalters@0
|
864 char *s ;
|
tomwalters@0
|
865 {
|
tomwalters@0
|
866 return ( strcmp( "on", s ) == 0 || ( isnumber( s ) && strcmp( "0", s ) != 0 ) ) ;
|
tomwalters@0
|
867 }
|
tomwalters@0
|
868
|
tomwalters@0
|
869 /*
|
tomwalters@0
|
870 Test for "off" or "0".
|
tomwalters@0
|
871 */
|
tomwalters@0
|
872
|
tomwalters@0
|
873 int isoff( s )
|
tomwalters@0
|
874 char *s ;
|
tomwalters@0
|
875 {
|
tomwalters@0
|
876 return ( strcmp( "off", s ) == 0 || strcmp( "0", s ) == 0 ) ;
|
tomwalters@0
|
877 }
|
tomwalters@0
|
878
|
tomwalters@0
|
879 /*
|
tomwalters@0
|
880 Test for "min".
|
tomwalters@0
|
881 */
|
tomwalters@0
|
882
|
tomwalters@0
|
883 int ismin( s )
|
tomwalters@0
|
884 char *s ;
|
tomwalters@0
|
885 {
|
tomwalters@0
|
886 return ( strcmp( "min", s ) == 0 ) ;
|
tomwalters@0
|
887 }
|
tomwalters@0
|
888
|
tomwalters@0
|
889 /*
|
tomwalters@0
|
890 Test for "max".
|
tomwalters@0
|
891 */
|
tomwalters@0
|
892
|
tomwalters@0
|
893 int ismax( s )
|
tomwalters@0
|
894 char *s ;
|
tomwalters@0
|
895 {
|
tomwalters@0
|
896 return ( strcmp( "max", s ) == 0 ) ;
|
tomwalters@0
|
897 }
|
tomwalters@0
|
898
|
tomwalters@0
|
899
|
tomwalters@0
|
900
|
tomwalters@0
|
901
|
tomwalters@0
|
902 /*************************************************************************/
|
tomwalters@0
|
903
|
tomwalters@0
|
904 /*
|
tomwalters@0
|
905 Print help for user
|
tomwalters@0
|
906 help=on or -help gets standard help for all except SILENT options.
|
tomwalters@0
|
907 help=all gets standard help for all options.
|
tomwalters@0
|
908 help=syntax gets help with syntax instead of comment for all except SILENT.
|
tomwalters@0
|
909 help=<name> gets help for the named option (which can be abbreviated).
|
tomwalters@0
|
910 */
|
tomwalters@0
|
911
|
tomwalters@0
|
912
|
tomwalters@0
|
913 /*
|
tomwalters@0
|
914 types of helpopts (see defines in options.h)
|
tomwalters@0
|
915
|
tomwalters@0
|
916 helpopts standard usage, exit when done
|
tomwalters@0
|
917 helpopts1 standard usage, supplied function for exit or additional help
|
tomwalters@0
|
918 helpopts2 supplied usage and function for exit or additional help
|
tomwalters@0
|
919 helpopts3 supplied usage, exit when done
|
tomwalters@0
|
920 */
|
tomwalters@0
|
921
|
tomwalters@0
|
922
|
tomwalters@0
|
923 gethelp( helpstr, prog, applic, usage, option, tail )
|
tomwalters@0
|
924 char *helpstr ;
|
tomwalters@0
|
925 char *prog ;
|
tomwalters@0
|
926 char *applic ;
|
tomwalters@0
|
927 char *usage ;
|
tomwalters@0
|
928 Options *option ;
|
tomwalters@0
|
929 int (*tail)() ; /* function for exit or additional help */
|
tomwalters@0
|
930 {
|
tomwalters@0
|
931 int i, index[64], span[64] ;
|
tomwalters@0
|
932
|
tomwalters@0
|
933 if ( isempty( helpstr ) || ison( helpstr ) || isstr( helpstr, "all" ) || isstr( helpstr, "syntax" ) )
|
tomwalters@0
|
934 help( prog, applic, usage, option, isstr( helpstr, "all" ), isstr( helpstr, "syntax" ) ) ;
|
tomwalters@0
|
935 else {
|
tomwalters@0
|
936 i = whichopt( option, helpstr, index, span ) ;
|
tomwalters@0
|
937 if ( i == 0 )
|
tomwalters@0
|
938 fprintf(stderr,"%s: unknown option [%s]\n", prog, helpstr ) ;
|
tomwalters@0
|
939 else if ( i > 1 )
|
tomwalters@0
|
940 fprintf(stderr,"%s: ambiguous option [%s]\n", prog, helpstr ) ;
|
tomwalters@0
|
941 else
|
tomwalters@0
|
942 helpshot( option[*index] ) ; /* single-line help i'th option */
|
tomwalters@0
|
943 }
|
tomwalters@0
|
944 (*tail)() ;
|
tomwalters@0
|
945 }
|
tomwalters@0
|
946
|
tomwalters@0
|
947
|
tomwalters@0
|
948
|
tomwalters@0
|
949 help( prog, applic, usage, option, all, syntax )
|
tomwalters@0
|
950 char *prog, *applic, *usage ;
|
tomwalters@0
|
951 Options *option ;
|
tomwalters@0
|
952 int all, syntax ;
|
tomwalters@0
|
953 {
|
tomwalters@0
|
954 int i ;
|
tomwalters@0
|
955 char *which_syntax();
|
tomwalters@0
|
956
|
tomwalters@0
|
957 if ( usage == (char *)0 ) /* a standard usage */
|
tomwalters@0
|
958 printf( "%s: %s\nUsage: %s [arguments] [file]\n", prog, applic, prog );
|
tomwalters@0
|
959 else
|
tomwalters@0
|
960 printf( "%s: %s\nUsage: %s\n", prog, applic, usage );
|
tomwalters@0
|
961
|
tomwalters@0
|
962 if ( num_printed_opts( option, all ) > 0 ) {
|
tomwalters@0
|
963 printf("name default comment\n");
|
tomwalters@0
|
964 printf("---------- ---------- --------.... \n");
|
tomwalters@0
|
965 }
|
tomwalters@0
|
966 for (i=0 ; option[i].name != (char *)0 ; i++) {
|
tomwalters@0
|
967 if ( !bitset( option[i].type, SILENT ) || all ) {
|
tomwalters@0
|
968 if ( syntax )
|
tomwalters@0
|
969 syntaxline( option[i] ) ;
|
tomwalters@0
|
970 else
|
tomwalters@0
|
971 helpline( option[i] ) ;
|
tomwalters@0
|
972 }
|
tomwalters@0
|
973 }
|
tomwalters@0
|
974 }
|
tomwalters@0
|
975
|
tomwalters@0
|
976
|
tomwalters@0
|
977 helpline( option )
|
tomwalters@0
|
978 Options option ;
|
tomwalters@0
|
979 {
|
tomwalters@0
|
980 printf("%-10s ", option.name );
|
tomwalters@0
|
981 printf("%-10s ", option.dflt );
|
tomwalters@0
|
982 printf("%s\n" , option.help );
|
tomwalters@0
|
983 }
|
tomwalters@0
|
984
|
tomwalters@0
|
985 syntaxline( option )
|
tomwalters@0
|
986 Options option ;
|
tomwalters@0
|
987 {
|
tomwalters@0
|
988 char *which_syntax();
|
tomwalters@0
|
989
|
tomwalters@0
|
990 printf("%-10s ", option.name );
|
tomwalters@0
|
991 printf("%-10s ", option.dflt );
|
tomwalters@0
|
992 printf("%s\n" , which_syntax( option.type ) );
|
tomwalters@0
|
993 }
|
tomwalters@0
|
994
|
tomwalters@0
|
995
|
tomwalters@0
|
996 helpshot( option )
|
tomwalters@0
|
997 Options option ;
|
tomwalters@0
|
998 {
|
tomwalters@0
|
999 char *which_syntax();
|
tomwalters@0
|
1000
|
tomwalters@0
|
1001 printf("name: %s\n", option.name );
|
tomwalters@0
|
1002 printf("default: %s\n", option.dflt );
|
tomwalters@0
|
1003 printf("syntax: %s\n", which_syntax( option.type ) );
|
tomwalters@0
|
1004 printf("comment: %s\n", option.help );
|
tomwalters@0
|
1005 }
|
tomwalters@0
|
1006
|
tomwalters@0
|
1007
|
tomwalters@0
|
1008 /*
|
tomwalters@0
|
1009 Return the number of options which will get printed by help
|
tomwalters@0
|
1010 */
|
tomwalters@0
|
1011
|
tomwalters@0
|
1012 int num_printed_opts( option, all )
|
tomwalters@0
|
1013 Options *option ;
|
tomwalters@0
|
1014 int all ;
|
tomwalters@0
|
1015 {
|
tomwalters@0
|
1016 int i, j=0 ;
|
tomwalters@0
|
1017
|
tomwalters@0
|
1018 for (i=0 ; option[i].name != (char *)0 ; i++)
|
tomwalters@0
|
1019 if ( !bitset( option[i].type, SILENT ) )
|
tomwalters@0
|
1020 j++ ;
|
tomwalters@0
|
1021 if ( all ) return ( i ) ; /* num all options */
|
tomwalters@0
|
1022 else return ( j ) ; /* num non-SILENT options */
|
tomwalters@0
|
1023 }
|
tomwalters@0
|
1024
|
tomwalters@0
|
1025
|
tomwalters@0
|
1026 char *which_syntax( type )
|
tomwalters@0
|
1027 int type ;
|
tomwalters@0
|
1028 {
|
tomwalters@0
|
1029 if ( bitsset( type, ALL_SYNTAX ) ) return (char *)( All_Syntax ) ;
|
tomwalters@0
|
1030 if ( bitsset( type, VAL_SYNTAX ) ) return (char *)( Val_Syntax ) ;
|
tomwalters@0
|
1031 if ( bitsset( type, TOGGLE_SYNTAX ) ) return (char *)( Toggle_Syntax ) ;
|
tomwalters@0
|
1032 if ( bitsset( type, ONOFF_SYNTAX ) ) return (char *)( Onoff_Syntax ) ;
|
tomwalters@0
|
1033 if ( bitsset( type, EQ_SYNTAX ) ) return (char *)( Eq_Syntax ) ;
|
tomwalters@0
|
1034 if ( bitsset( type, ARG_SYNTAX ) ) return (char *)( Arg_Syntax ) ;
|
tomwalters@0
|
1035 if ( bitsset( type, FLAG_SYNTAX ) ) return (char *)( Flag_Syntax ) ;
|
tomwalters@0
|
1036 }
|
tomwalters@0
|
1037
|
tomwalters@0
|
1038
|