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   ) ;
+}
+
+