Mercurial > hg > aim92
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/options.c Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,1038 @@ + +#include <stdio.h> +#include <math.h> +#include "options.h" +#include "strmatch.h" +#include "units.h" + + +/* +Defaults for i/o parameters. +These are declared externally in options.h so they may be overridden by +option assignment. +*/ + +int LINE_LENGTH = 256 ; /* max length of line for ascii data. */ +int FIELDWIDTH = 0 ; /* field width for printf. */ + /* (FIELDWIDTH=0 sets no extra fieldwidth. */ + /* Positive integer fieldwidth sets right-justified */ + /* columns, negative integer fieldwidth sets left- */ + /* justified columns). */ +int PRECISION = 3 ; /* precision (num decimal places) for printf, */ + /* (PRECISION=0 sets integer output). */ + + + +/* +Return a file pointer to a file `name' opened to read. +If `name' is `-' then return stdin. +If file `name' is not found return null pointer. +*/ + +FILE *fropen( name ) +char *name ; +{ + FILE *fopen() ; + + if ( isstr( name, "-" ) ) return stdin ; + else return ( fopen( name, "r" ) ) ; +} + + +/* +Generic options handler and file opener. +Return a file pointer to an opened file, either stdin (if no args remained on +command line after scanning) or the first name left on the command line. +*/ + +FILE *openopts( option, argc, argv ) +Options *option ; +int argc ; +char *argv[] ; +{ + FILE *fp ; + int i ; + + if ( ( i = getopts( option, argc, argv ) ) == 0 ) + return stdin ; + if ( ( fp = fropen( argv[argc-i] ) ) == (FILE *)0 ) { + fprintf(stderr, "%s: can't open %s\n", argv[0], argv[argc-i] ) ; + exit( 1 ) ; + } + return ( fp ) ; +} + + +/* +Options handler and two file opener. +If one file is on command line after scanning options, then the first file +fp1 is assumed to be the stdin. Otherwise two files are expected. +Return 0 if incorrect number of files, otherwise return 1. +(Note: fp1 and fp2 are pts to file ptrs, so pass them as &fp1, &fp2 if +originally declared as file ptrs). +*/ + +open2opts( option, argc, argv, fp1, fp2 ) +Options *option ; +int argc ; +char *argv[] ; +FILE **fp1 ; +FILE **fp2 ; +{ + switch ( getopts( option, argc, argv ) ) { + + case 1 : + *fp1 = stdin; + if ( ( *fp2 = fropen( argv[argc-1] ) ) == (FILE *)0 ) { + fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-1] ) ; + exit( 1 ) ; + } + break ; + case 2 : + if ( ( *fp1 = fropen( argv[argc-2] ) ) == (FILE *)0 ) { + fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-2] ) ; + exit( 1 ) ; + } + if ( ( *fp2 = fropen( argv[argc-1] ) ) == (FILE *)0 ) { + fprintf( stderr,"%s: can't open %s\n", argv[0], argv[argc-1] ) ; + exit( 1 ) ; + } + break ; + default : + return ( 0 ) ; + } + return ( 1 ) ; +} + + + +/* + Build an options table. + First assign all the option values with the defaults given in the table. + Then scan the command line for arguments to overwrite corresponding vals. + + Argument syntax is one of the following three types (or combinations). + Each syntax must contain either a leading '-' char or an embedded '=' char, + to distinguish arguments from possible filenames. + + + 1) -<name> FLAG_SYNTAX + 2) -<name>[=]<value> ARG_SYNTAX + 3) [-]<name>=<value> EQ_SYNTAX + + FLAG_SYNTAX takes no value. (The returned value is the empty string). + + ARG_SYNTAX takes a value after an optional '=' char. + If the '=' char is not found, then the <value> is whatever follows the + longest matching <name> string. Otherwise the <value> is whatever follows + the '=' char. (The value is not allowed to be empty). + + EQ_SYNTAX takes a value which is whatever follows the '=' char. + (The value is not allowed to be empty). + + It is assumed that all args remaining on the command line after an arg with + invalid syntax must be filenames. These remain unscanned. + Return argc, the number of args remaining unscanned on the command line, + (argc=0 if no args left). + To scan the remainder of the command line, and (eg) print the filenames:- + + if ( ( i = getopts( option, argc, argv, ) ) == 0 ) + printf("stdin\n" ); + else + for ( ; i>0 ; i--) + printf("[%s]\n", argv[argc-i] ); + +*/ + + +int getopts( option, argc, argv ) +Options *option ; +int argc ; +char *argv[] ; +{ + char *prog, *val ; + int i, n, index[64], span[64] ; + + /* Assign option vals using the defaults */ + + for (i=0 ; option[i].name != (char *)0 ; i++) + *(option[i].val) = option[i].dflt ; + + /* Overwrite option vals with corresponding vals found on command line */ + + prog = *argv ; + while ( --argc > 0 && ++argv ) { + + /* find list of options all with longest matching name span */ + /* returning if none, with argc args remaining */ + if ( ( n = whichopt( option, *argv, index, span ) ) == 0 ) + return ( argc ) ; + + /* check arg syntax, returning if invalid with argc args remaining */ + for ( i=0 ; i<n && ( val = checksyntax( *argv, span[i], option[index[i]].type ) ) == (char *)0 ; i++ ) + ; + if ( val == (char *)0 ) + return ( argc ) ; + + /* if whichopt was ambiguous, yet an arg is valid, then its an */ + /* ambiguous option, (and not a possible filename). */ + if ( n > 1 ) { + fprintf(stderr,"%s: ambiguous option [%s]\n", prog, *argv ) ; + exit ( 1 ) ; + } + + /* do operation */ + operate( option, *index, val ) ; + side_effect( option, *index ) ; + + } + return argc ; +} + + +/* +Find the default value of the first option whose name unambiguously matches +`s' (possibly abbreviated). +Return a ptr to the default value of the matching option. +Otherwise return the null ptr if a matching name is not found or is ambiguous. +*/ + +char *optdflt( option, s ) +Options *option ; +char *s ; +{ + int i ; + + if ( ( i = optindex( option, s ) ) < 0 ) + return ( (char *)0 ) ; + return ( option[i].dflt ) ; +} + +/* +Find the option whose name unambiguously matches `s' (possibly abbreviated). +Return the option list index of the matching option. +Otherwise return -1 if a matching name is not found, or -2 if the name is +ambiguous. +*/ + +int optindex( option, s ) +Options *option ; +char *s ; +{ + int i, n, index[64], span[64] ; + + if ( ( n = whichopt( option, s, index, span ) ) == 0 ) + return (-1) ; /* option not found */ + if ( n > 1 ) + return (-2) ; /* option name ambiguous */ + return ( *index ) ; +} + + +/* +Find the option whose name has the longest matching span with the head of `s' +(the argument string, possibly abbreviated or with trailing value parts). +Pass the option list index of the matching option back via arg `index'. +Pass the length of the matching span back via arg `span'. +Return the number of options found which have an equal longest matching span. +(Any `-' at the head of `s' is skipped before matching). +If there is an exact match (ie the longest matching span equals the length of +the option name) then return an unambiguous match. +*/ + +int whichopt( option, s, index, span ) +Options *option ; +char *s ; +int *index, *span ; +{ + int i, j, n = 0, jmax = 0 ; + + if ( *s == '-' ) s++ ; /* Skip leading hyphen */ + + for ( i = 0 ; option[i].name != (char *)0 ; i++ ) { + + if ( ( j = streqspn( s, option[i].name ) ) > jmax ) { + jmax = j ; /* a new longest matching span */ + n = 0 ; + index[n] = i ; + span[n++] = j ; + } + else if ( j > 0 && j == jmax ) { /* ambiguous name with same matching span */ + index[n] = i ; + span[n++] = j ; + } + } + + for ( i = 0 ; i < n ; i++ ) /* check for an exact match */ + if ( span[i] == strlen( option[index[i]].name ) ) { + index[0] = index[i] ; + span[0] = span[i] ; + return 1 ; + } + + return n ; +} + + +/* +Check arg syntax and return a pointer to the value part, (or a pointer to the +terminating null if the value part is empty). +Return a NULL pointer if the syntax is invalid. It is assumed then that the +current arg (and all remaining) is a filename. +Print a warning if the syntax is an error rather than a possible filename, +(the filename will not be found in this case). + +The check is arranged so that different option syntax types can be OR'd. +*/ + +char *checksyntax( s, span, type ) +char *s ; +int span, type ; +{ + int i ; + char *v, *val = (char *)0 ; + + if ( bitset( type, FLAG_SYNTAX ) ) { /* -<name> */ + if ( *s == '-' && *(v = s+1 + span) == '\0' ) + val = v ; + } + + if ( bitset( type, ARG_SYNTAX ) ) { /* -<name>[=]<value> */ + if ( *s == '-' ) { + if ( *(v = s+1 + span) == '=' ) v++ ; + if ( *v != '\0' ) val = v ; + } + } + + if ( bitset( type, EQ_SYNTAX ) ) { /* [-]<name>=<value> */ + if ( *s == '-' ) s++ ; + if ( *(v = s + span) == '=' && *++v != '\0' ) + val = v ; + } + + return ( val ) ; +} + + +/* +Return 1 if string s a possible option, (ie. a string which is not a <number>, +and contains either an embedded '=' or a leading '-'). +Otherwise return 0. +*/ + +int isopt( s ) +char *s ; +{ + if ( isnumber( s ) ) return 0 ; + if ( *s == '-' ) return 1 ; + if ( strchr( s, '=' ) != (char *)0 ) return 1 ; + return 0 ; +} + + +operate( option, i, val ) +Options *option ; +int i ; +char *val ; +{ + if ( bitset( option[i].type, LATCH ) ) /* LATCH */ + *(option[i].val) = val ; + + else if ( bitset( option[i].type, AND ) ) /* AND */ + *(option[i].val) = offstr ; + + else if ( bitset( option[i].type, OR ) ) /* OR */ + *(option[i].val) = onstr ; + + else if ( bitset( option[i].type, TOGGLE ) ) { /* TOGGLE */ + if ( isempty( val ) ) { + if ( ison( *(option[i].val) ) ) + *(option[i].val) = offstr ; + else + *(option[i].val) = onstr ; + } + else *(option[i].val) = val ; + } +} + + +/* +Side-effects of options type specifiers. +*/ + +side_effect( option, j ) +Options *option ; +int j ; +{ + int i ; + char *exstr ; + + if ( bitset( option[j].type, EXCLUDE ) ) { /* EXCLUDE */ + if ( ison( *(option[j].val) ) ) + exstr = offstr ; + else + exstr = onstr ; + for ( i=0; option[i].name != (char *)0 ; i++) + if ( i != j && bitset( option[i].type, EXCLUDE ) ) + *(option[i].val) = exstr ; + } +} + + + +/* +Separate an option value string `optval' into two string tokens at the first +occurrence of a separator character `sep'. (Given as a string of one char). +Return the tokens via the pointers `val1' and `val2' (which could be passed +as the addresses of string pointers). +Return BADVAL if the option value string is bad (meaning that either `optval' was +null or empty, or the separator char was found but the 2nd token was missing). +Return 1 if the option value string is good (meaning that either two tokens +were found, or only the 1st token with no separator char, in which case `val2' +will be a ptr to an empty string). (See routine strpsep()). +*/ + +int getvals( optval, val1, val2, sep ) +char *optval ; +char **val1, **val2 ; +char *sep ; +{ + *val1 = optval ; + if ( isnull( *val2 = strsep( optval, sep ) ) ) + return BADVAL ; + return 1 ; +} + + +/* +Parse a range selector of the form: a[-b] +Return 0 if bad selectors, otherwise return 1. +Items are numbered 1,2,...,max, (where max is 0 by convention). +When either limit is "min", then set the respective value to 1. +When either limit is "max", then set the respective value to 0. +When `b' is missing, then set b=a. + +If (a==0) then seek eof and process the final item. +Else seek past (a-1) items, and then process the next (b-a+1) items +(or all items until eof if (b==0)). +Eg: + seekstart( a-1, bytes, fp ) ; + for ( i = 0 ; ( b == 0 || i < b-a+1 ) ; i++ ) + do process + +*/ + +int selector( s, a, b ) +char *s ; +int *a, *b ; +{ + char *val1, *val2 ; + + if ( getvals( s, &val1, &val2, "-" ) == BADVAL ) + return ( 0 ) ; + if ( ismin( val1 ) ) *a = 1 ; /* first object */ + else if ( ismax( val1 ) ) *a = 0 ; /* last object */ + else if ( ( *a = atoi( val1 ) ) <= 0 ) { /* intermediate object */ + if ( *a == 0 ) fprintf( stderr,"warning: selected items are numbered 1,...,max\n" ) ; + return ( 0 ) ; + } + if ( isempty( val2 ) ) *b = *a ; /* single object */ + else if ( ismin( val2 ) ) *b = 1 ; + else if ( ismax( val2 ) ) *b = 0 ; + else if ( ( *b = atoi( val2 ) ) <= 0 ) { + return ( 0 ) ; + } + if ( *b > 0 && ( *a == 0 || *a > *b ) ) + return ( 0 ) ; + + return ( 1 ) ; +} + + +/* +Parse a time range selector of the form: a[-b] +The range is returned as limits meaning: start==a duration==b-a+1. +(Note: when range=max or range=max-max then a==b==(-1) and duration==1). +Return 0 if bad selectors, otherwise return 1. +Time is numbered 0,2,...,max, (where max is (-1) by convention). +When either limit is "min", then set the respective value to 0. +When either limit is "max", then set the respective value to (-1). +When `b' is missing, then set b=a. +Time is specified as <number>[<units>], where <units> = {p, ms, s}. +Empty units are interpreted as `p' (ie sample points). +Convert `a' and `b' to sample points using the given samplerate. + +(Note: this is like selector() but using to_p() instead of atoi(), and +numbering from 0 instead of 1). + +If (a<0) then seek eof and process the final item. +Else seek past (a) items, and then process the next (b-a+1) items +(or all items until eof if (b==-1)). +Eg: + seekstart( a, bytes, fp ) ; + for ( i = 0 ; ( b < 0 || i < b-a+1 ) ; i++ ) + do process + +*/ + +int range( s, a, b, samplerate ) +char *s ; +int *a, *b ; +int samplerate ; +{ + char *val1, *val2 ; + + if ( getvals( s, &val1, &val2, "-" ) == BADVAL ) + return ( 0 ) ; + if ( ismin( val1 ) ) *a = 0 ; /* first object */ + else if ( ismax( val1 ) ) *a = (-1) ; /* last object */ + else if ( ( *a = to_p( val1, samplerate ) ) < 0 ) { + return ( 0 ) ; + } + if ( isempty( val2 ) ) *b = *a ; /* single object */ + else if ( ismin( val2 ) ) *b = 0 ; + else if ( ismax( val2 ) ) *b = (-1) ; + else if ( ( *b = to_p( val2, samplerate ) ) < 0 ) { + return ( 0 ) ; + } + if ( *b >= 0 && ( *a < 0 || *a > *b ) ) + return ( 0 ) ; + + return ( 1 ) ; +} + + +/* +Seek n items of size bytes from current position in stream. +(Unlike fseek, this works even when fp is stdin). +Return the number of items actually read. +Example: seekstart( n, sizeof(short), fp ); +Datatype "ASCII" is a special case for which 0 is returned by the databytes +routine, so bytes==0 is taken to mean seek n ascii lines. In general use: + seekstart( n, databytes( typestr ), fp ) +*/ + +seekstart( n, bytes, fp ) +int n, bytes ; +FILE *fp ; +{ + int i ; + char *buf ; + char *line ; + + if ( bytes == 0 ) { /* special case meaning ascii lines */ + line = (char *)malloc( LINE_LENGTH ) ; + for ( i = 0 ; i < n && fgets( line, LINE_LENGTH, fp ) != (char *)0 ; i++ ) + ; + free( line ) ; + return ( i ) ; + } + + if ( fp != stdin ) { + if ( fseek( fp, (long)( n * bytes ), 1 ) == 0 ) + return n ; /* if improper, look for any input */ + } + + if ( ( buf = (char *)malloc( bytes ) ) == (char *)0 ) { + fprintf( stderr, "seekstart: cannot allocate %d bytes\n", bytes ) ; + exit( 1 ) ; + } + + for ( i = 0 ; i < n && fread( buf, bytes, 1, fp ) ; i++ ) + ; + free( buf ) ; + + return ( i ) ; +} + + +/* +Seek n items of of given type from current position in stream. +This seekstart version takes a `type' arg instead of a size in `bytes'. +The `type' is an index to the datatype list in options.h, obtained for +example using: typeindex( typestr ). +*/ + +seektype( n, type, fp ) +int n, type ; +FILE *fp ; +{ + return ( seekstart( n, typebytes( type ), fp ) ) ; +} + + +/* +Read the next n items of `type' from the given stream. +The `type' is an index to the datatype list in options.h, obtained for +example using: typeindex( typestr ). +Assign the item as a float in address `y', and return 1. +Return 0 if eof or error. +This can replace fread, eg: + fread( &p, sizeof(short), 1, fp ) ( with short p ) +becomes: + readitem( &y, typeindex( "short" ), 1, fp ) ( with float y ) +*/ + +readitem( y, type, n, fp ) +float *y ; +int type ; +int n ; +FILE *fp ; +{ + char c ; short s ; int i ; float f ; double d ; + int j ; + static char *line ; + static int first = 1 ; + + switch ( type ) { + case 0 : for ( j = 0 ; j < n ; j++ ) { + if ( fread( &c, sizeof(char), 1, fp ) == 0 ) return 0 ; + *y++ = (float)c ; + } + break ; + case 1 : for ( j = 0 ; j < n ; j++ ) { + if ( fread( &s, sizeof(short), 1, fp ) == 0 ) return 0 ; + *y++ = (float)s ; + } + break ; + case 2 : for ( j = 0 ; j < n ; j++ ) { + if ( fread( &i, sizeof(int), 1, fp ) == 0 ) return 0 ; + *y++ = (float)i ; + } + break ; + case 3 : for ( j = 0 ; j < n ; j++ ) { + if ( fread( &f, sizeof(float), 1, fp ) == 0 ) return 0 ; + *y++ = (float)f ; + } + break ; + case 4 : for ( j = 0 ; j < n ; j++ ) { + if ( fread( &d, sizeof(double), 1, fp ) == 0 ) return 0 ; + *y++ = (float)d ; + } + break ; + case 5 : + case 6 : if ( first ) { + line = (char *)malloc( LINE_LENGTH ) ; + first = 0 ; + } + for ( j = 0 ; j < n ; j++ ) { + if ( fgets( line, LINE_LENGTH, fp ) == (char *)0 ) return 0 ; + *y++ = atof( line ) ; + } + break ; + } + return 1 ; +} + + +/* +Write the given n items of `type' onto the given stream. +The `type' is an index to the datatype list in options.h, (obtained for +example using: typeindex( typestr ) ). +*/ + +writeitem( y, type, n, fp ) +float *y ; +int type ; +int n ; +FILE *fp ; +{ + char c ; short s ; int i ; float f ; double d ; + int j ; + + switch ( type ) { + case 0 : for ( j = 0 ; j < n ; j++ ) { + c = (char) *y++ ; + fwrite( &c, sizeof(char), 1, fp ) ; + } + break ; + case 1 : for ( j = 0 ; j < n ; j++ ) { + s = (short) *y++ ; + fwrite( &s, sizeof(short), 1, fp ) ; + } + break ; + case 2 : for ( j = 0 ; j < n ; j++ ) { + i = (int) *y++ ; + fwrite( &i, sizeof(int), 1, fp ) ; + } + break ; + case 3 : for ( j = 0 ; j < n ; j++ ) { + f = (float) *y++ ; + fwrite( &f, sizeof(float), 1, fp ) ; + } + break ; + case 4 : for ( j = 0 ; j < n ; j++ ) { + d = (double) *y++ ; + fwrite( &d, sizeof(double), 1, fp ) ; + } + break ; + case 5 : + case 6 : for ( j = 0 ; j < n ; j++ ) + fprintf( fp, "%*.*f\n", FIELDWIDTH, PRECISION, *y++ ) ; + break ; + } +} + + +/* +Read the next n items of `type' from the given stream within inclusive range +limits `a' and `b', (found using, eg: range( rangestr, &a, &b, samplerate ) ). +This is a version of readitem which incorporates the intial seek and handles +range=max correctly. +The `type' is an index to the datatype list in options.h, obtained for +example using: typeindex( typestr ). +Assign the item as a float in address `y', and return the number of items +read. Return 0 if eof or error. +*/ + +nextitem( y, type, n, fp, a, b ) +float *y ; +int type ; +int n ; +FILE *fp ; +int a, b ; +{ + static int count = 0 ; /* total items read over all calls */ + int num ; /* number items read this call */ + float x ; + + if ( count == 0 ) { + + if ( a == (-1) ) { /* range=max or range=max-max */ + if ( n == 1 && readitem( &x, type, 1, fp ) ) { + *y = x ; + while ( readitem( &x, type, 1, fp ) ) + *y = x ; + num = 1 ; + } + else num = 0 ; + } + + else { + if ( seektype( a, type, fp ) < a ) + num = 0 ; + else { + if ( b >= 0 && n > b-a+1 ) /* n restricted by upper limit */ + n = b-a+1 ; + for ( num = 0 ; num < n && readitem( &x, type, 1, fp ) ; num++ ) + y[num] = x ; + } + } + + count += num ; + } + + else { + if ( b >= 0 && count >= b-a+1 ) + num = 0 ; + else { + if ( b >= 0 && n > b-a+1 - count ) /* n restricted by upper limit */ + n = b-a+1 - count ; + for ( num = 0 ; num < n && readitem( &x, type, 1, fp ) ; num++ ) + y[num] = x ; + } + + count += num ; + } + + return num ; +} + + + + +/* +Return the type index (to the datatype list in options.h) of the given type +string. String matching allows for abbreviations. +If the given type string is in error then return an error code (less than 0): + -1 type string not found in datatype list. + -2 type string is ambiguous. +*/ + +int typeindex( typestr ) +char *typestr ; +{ + return ( listindex( datatype, typestr ) ) ; +} + + +/* +Return a number of bytes for a given type index (to the datatype list in +options.h). Datatype "ASCII" is a special case for which 0 is returned. +*/ + +int typebytes( type ) +int type ; +{ + int bytes ; + + switch ( type ) { + case 0 : bytes = sizeof( char ) ; break ; + case 1 : bytes = sizeof( short ) ; break ; + case 2 : bytes = sizeof( int ) ; break ; + case 3 : bytes = sizeof( float ) ; break ; + case 4 : bytes = sizeof( double ) ; break ; + case 5 : /* ASCII */ + case 6 : bytes = 0 ; break ; /* ascii */ + } + return ( bytes ) ; +} + + + +/* +Return a number of bytes for a given type string. +The string can be a number (of bytes), or a token from the `datatype' list, +(see options.h) with which it is matched, allowing for abbreviations. +Datatype "ASCII" or "ascii" is a special case for which 0 is returned. +If the given type string is in error then return an error code (less than 0): + -1 type string not found in datatype list. + -2 type string is ambiguous. + -3 type string is a negative number. +*/ + +int databytes( typestr ) +char *typestr ; +{ + int type, bytes ; + + if ( isnumber( typestr ) ) { /* case of bytes number string */ + if ( ( bytes = atoi( typestr ) ) < 0 ) + return ( -3 ) ; + else return bytes ; + } + + if ( ( type = typeindex( typestr ) ) < 0 ) + return type ; + + return ( typebytes( type ) ) ; +} + + +/* +Check for over or underflow when the given float is scaled and cast into the +given data type (an index to the datatype list in options.h). +Return a more appropriate scale factor, or a scale factor of 1 if no over +or underflow. The returned scale factor is the minimum scale factor over +a succession of calls to check_overflow. +*/ + +float check_overflow( p, scale, type ) +float p, scale ; +int type ; +{ + float f, p1 = p * scale ; + static float first = 1 ; + static float max, newscale ; + + if ( type >= 3 ) return ( 1. ) ; + + if ( first ) { + + switch ( type ) { + case 0 : max = pow( 2., 8.*sizeof(char)-1 ) - 1 ; break ; + case 1 : max = pow( 2., 8.*sizeof(short)-1 ) - 1 ; break ; + case 2 : max = pow( 2., 8.*sizeof(int)-1 ) - 1 ; break ; + } + + newscale = 1. ; + first = 0 ; + } + + if ( p1 > max ) f = max / p ; + else if ( p1 < (-max) ) f = -( max / p ) ; + else f = 1. ; + + if ( f < newscale ) + newscale = f ; + + return ( newscale ) ; +} + + + +/* +Some particular string tests. +*/ + + +/* +Test for "on" or any <number> string other than "0". +*/ + +int ison( s ) +char *s ; +{ + return ( strcmp( "on", s ) == 0 || ( isnumber( s ) && strcmp( "0", s ) != 0 ) ) ; +} + +/* +Test for "off" or "0". +*/ + +int isoff( s ) +char *s ; +{ + return ( strcmp( "off", s ) == 0 || strcmp( "0", s ) == 0 ) ; +} + +/* +Test for "min". +*/ + +int ismin( s ) +char *s ; +{ + return ( strcmp( "min", s ) == 0 ) ; +} + +/* +Test for "max". +*/ + +int ismax( s ) +char *s ; +{ + return ( strcmp( "max", s ) == 0 ) ; +} + + + + +/*************************************************************************/ + +/* + Print help for user + help=on or -help gets standard help for all except SILENT options. + help=all gets standard help for all options. + help=syntax gets help with syntax instead of comment for all except SILENT. + help=<name> gets help for the named option (which can be abbreviated). +*/ + + +/* + types of helpopts (see defines in options.h) + +helpopts standard usage, exit when done +helpopts1 standard usage, supplied function for exit or additional help +helpopts2 supplied usage and function for exit or additional help +helpopts3 supplied usage, exit when done +*/ + + +gethelp( helpstr, prog, applic, usage, option, tail ) +char *helpstr ; +char *prog ; +char *applic ; +char *usage ; +Options *option ; +int (*tail)() ; /* function for exit or additional help */ +{ + int i, index[64], span[64] ; + + if ( isempty( helpstr ) || ison( helpstr ) || isstr( helpstr, "all" ) || isstr( helpstr, "syntax" ) ) + help( prog, applic, usage, option, isstr( helpstr, "all" ), isstr( helpstr, "syntax" ) ) ; + else { + i = whichopt( option, helpstr, index, span ) ; + if ( i == 0 ) + fprintf(stderr,"%s: unknown option [%s]\n", prog, helpstr ) ; + else if ( i > 1 ) + fprintf(stderr,"%s: ambiguous option [%s]\n", prog, helpstr ) ; + else + helpshot( option[*index] ) ; /* single-line help i'th option */ + } + (*tail)() ; +} + + + +help( prog, applic, usage, option, all, syntax ) +char *prog, *applic, *usage ; +Options *option ; +int all, syntax ; +{ + int i ; + char *which_syntax(); + + if ( usage == (char *)0 ) /* a standard usage */ + printf( "%s: %s\nUsage: %s [arguments] [file]\n", prog, applic, prog ); + else + printf( "%s: %s\nUsage: %s\n", prog, applic, usage ); + + if ( num_printed_opts( option, all ) > 0 ) { + printf("name default comment\n"); + printf("---------- ---------- --------.... \n"); + } + for (i=0 ; option[i].name != (char *)0 ; i++) { + if ( !bitset( option[i].type, SILENT ) || all ) { + if ( syntax ) + syntaxline( option[i] ) ; + else + helpline( option[i] ) ; + } + } +} + + +helpline( option ) +Options option ; +{ + printf("%-10s ", option.name ); + printf("%-10s ", option.dflt ); + printf("%s\n" , option.help ); +} + +syntaxline( option ) +Options option ; +{ + char *which_syntax(); + + printf("%-10s ", option.name ); + printf("%-10s ", option.dflt ); + printf("%s\n" , which_syntax( option.type ) ); +} + + +helpshot( option ) +Options option ; +{ + char *which_syntax(); + + printf("name: %s\n", option.name ); + printf("default: %s\n", option.dflt ); + printf("syntax: %s\n", which_syntax( option.type ) ); + printf("comment: %s\n", option.help ); +} + + +/* +Return the number of options which will get printed by help +*/ + +int num_printed_opts( option, all ) +Options *option ; +int all ; +{ + int i, j=0 ; + + for (i=0 ; option[i].name != (char *)0 ; i++) + if ( !bitset( option[i].type, SILENT ) ) + j++ ; + if ( all ) return ( i ) ; /* num all options */ + else return ( j ) ; /* num non-SILENT options */ +} + + +char *which_syntax( type ) +int type ; +{ + if ( bitsset( type, ALL_SYNTAX ) ) return (char *)( All_Syntax ) ; + if ( bitsset( type, VAL_SYNTAX ) ) return (char *)( Val_Syntax ) ; + if ( bitsset( type, TOGGLE_SYNTAX ) ) return (char *)( Toggle_Syntax ) ; + if ( bitsset( type, ONOFF_SYNTAX ) ) return (char *)( Onoff_Syntax ) ; + if ( bitsset( type, EQ_SYNTAX ) ) return (char *)( Eq_Syntax ) ; + if ( bitsset( type, ARG_SYNTAX ) ) return (char *)( Arg_Syntax ) ; + if ( bitsset( type, FLAG_SYNTAX ) ) return (char *)( Flag_Syntax ) ; +} + +