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