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