brad@hcx1.ssd.csd.harris.com (Brad Appleton) (03/18/91)
Submitted-by: Brad Appleton <brad@hcx1.ssd.csd.harris.com> Posting-number: Volume 17, Issue 56 Archive-name: parseargs/part11 This is part 11 of parseargs #!/bin/sh # this is Part.11 (part 11 of a multipart archive) # do not concatenate these parts, unpack them in order with /bin/sh # file parseargs/useful.h continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 11; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping parseargs/useful.h' else echo 'x - continuing file parseargs/useful.h' sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/useful.h' && X EXTERN ARBPTR memcpy ARGS(( ARBPTR, const ARBPTR, int )); X EXTERN ARBPTR memmove ARGS(( ARBPTR, const ARBPTR, int )); X EXTERN ARBPTR memset ARGS(( ARBPTR, int, int )); # endif /* MEMORY_H */ X # else # define memcmp(b1,b2,n) bcmp(b1,b2,n) # define memcpy(b1,b2,n) bcopy(b2,b1,n) # ifndef BSTRING_H # define BSTRING_H X EXTERN VOID bcopy ARGS(( const ARBPTR, ARBPTR, int )); X EXTERN int bcmp ARGS(( const ARBPTR, const ARBPTR, int )); X EXTERN VOID bzero ARGS(( ARBPTR, int )); X EXTERN int ffs ARGS(( int )); # endif /* BSTRING_H */ # endif /* !BSD */ #endif /* STRING_H */ X EXTERN ARBPTR malloc ARGS(( size_t )); EXTERN ARBPTR ckalloc ARGS(( size_t )); EXTERN ARBPTR realloc ARGS(( ARBPTR, size_t )); EXTERN ARBPTR free ARGS(( ARBPTR )); EXTERN VOID exit ARGS(( int )); X #define MAXINPUTLINE 200 /* maximum string input line */ #define MAXWORDLEN 100 /* maximum word (token) length */ X #endif /* _USEFUL_H_ */ SHAR_EOF echo 'File parseargs/useful.h is complete' && chmod 0664 parseargs/useful.h || echo 'restore of parseargs/useful.h failed' Wc_c="`wc -c < 'parseargs/useful.h'`" test 7432 -eq "$Wc_c" || echo 'parseargs/useful.h: original size 7432, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= parseargs/vms_args.c ============== if test -f 'parseargs/vms_args.c' -a X"$1" != X"-c"; then echo 'x - skipping parseargs/vms_args.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting parseargs/vms_args.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'parseargs/vms_args.c' && /************************************************************************* ** ^FILE: vms_args.c - parse VMS/DCL argument vectors ** ** ^DESCRIPTION: ** This file contains the routines used to parse VMS/DCL argument ** vectors and to print VMS/DCL usage messages. ** ** ^HISTORY: ** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com> Created ***^^**********************************************************************/ X #include <stdio.h> #include <ctype.h> #include <useful.h> X #ifdef vms # include <descrip.h> #endif X #include "strfuncs.h" #include "pgopen.h" X #define PARSEARGS_PRIVATE /* include private definitions */ #include "parseargs.h" X EXTERN VOID syserr ARGS((const char *, ...)); EXTERN VOID usrerr ARGS((const char *, ...)); EXTERN VOID get_winsize ARGS((int, int *, int *)); EXTERN BOOL argInput ARGS((ARGDESC *, char *, BOOL)); EXTERN BOOL argOutput ARGS((ARGDESC *, char *, BOOL)); X VERSIONID("$Header: vms_args.c,v 1.1 90/08/23 18:00:00 brad Exp $"); X /*************************************************************************** ** ^GLOBAL-VARIABLE: Usage_Requested ** ** ^VISIBILITY: ** static-global (visible to all functions in this file). ** ** ^DESCRIPTION: ** Indicates whether a usage message was requested by the user ** (as opposed to triggerred by a syntax error). If the message ** is requested by the user then it is always printed in verbose ** mode and does not return an error-status-code. ***^^**********************************************************************/ static BOOL Usage_Requested = FALSE; X X #define MAXCMDLINE 255 #define VNULL (VOID *) 0 X #define TOGGLE(flag) flag = (flag) ? FALSE : TRUE X X /* define mappings */ #define c_SPACE '\001' /* whitespace */ #define c_QUAL '\002' /* qualifier-delimiter */ #define c_QSEP '\003' /* qualifier-argument separator */ #define c_LSEP '\004' /* list-item separator character */ X X typedef enum { X Parameter, /* token is a parameter */ X Qualifier, /* token is a qualifier */ X EndOfLine /* NUL-token (signifies end of tokens) */ } dcl_arg_t; X X typedef struct { X dcl_arg_t type; /* token type */ X char *token; /* token value */ } dcl_token_t; X X X /*************************************************************************** ** ^FUNCTION: is_cmdline - retrieve the original command-line ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static BOOL is_cmdline( argv, result ) /* ** ^PARAMETERS: */ X char *argv[]; /* -- array of strings */ X char **result; /* -- pointer to resultant command-line */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Is_cmdline will compare the given vector of strings to the actual ** string given on the command-line. If the two are approximately ** equivalent (modulo quotes and case) then the original command-line ** is copied to result, otherwise all the elements of argv are concat- ** enated together (in order and separated by whitespace) and assigned ** to *result. ** ** ^REQUIREMENTS: ** argv must be non-null ** ** ^SIDE-EFECTS: ** *result is assigned to either the concatenated argv string or the ** original command-line. The result shoub be freed using free(). ** ** ^RETURN-VALUE: ** FALSE if the argv given is different from the command-line; ** TRUE otherwise. ** ** ^CAVEATS: ** The comparison is case blind and double quotes are ignored in the ** command-line. This is because lib$get_foreign returns double quotes ** intact, while VAX-C strips them off. ** ** ^ACKNOWLEDGEMENTS: ** Thanx to Jim Barbour for writing most of this code. --BDA ** ** ^ALGORITHM: ** - Make a single string out of argv ** - compare the "big" string to the command-line ** - IF they are "equivalent" assign command-line to result & return TRUE. ** ELSE assign the "big" string to result and return FALSE. ***^^**********************************************************************/ #ifdef __ANSI_C__ X static BOOL is_cmdline( const char *argv[], char **result ) #endif { X unsigned long int stat; X unsigned short int len; X register CONST char *aptr, *sptr, *avstr; X static char str[ MAXCMDLINE ] = "" ; #ifdef vms X $DESCRIPTOR(str_d, str); #endif X X /* make a single string out of argv */ X avstr = strjoin( argv, " " ); X #ifndef vms X *result = (char *)avstr; X return FALSE; X #else X /* get the original command-line */ X if ( !*str ) { X stat = lib$get_foreign( &str_d, VNULL, &len, VNULL ); X str[len] = '\0'; X if (! (stat & 1)) exit( stat ); X } X X /* compare the two */ X for ( aptr = avstr, sptr = str ; *aptr && *sptr ; sptr++ ) { X if ( toupper(*sptr) == toupper(*aptr) ) { X ++aptr; X } X else if ( *sptr != '"' ) { X *result = (char *)avstr; X return FALSE; X } X } X X *result = strdup( str ); X free( avstr ); X return TRUE; #endif } X X /*************************************************************************** ** ^FUNCTION: dcl_strxlat - translate a string according to DCL syntax ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static char *dcl_strxlat( str ) /* ** ^PARAMETERS: */ X char *str; /* -- the string to translate. */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Dcl_strxlat will attempt to convert the given string to canonical ** form by escaping any unquoted special characters, and removing any ** unquoted whitespace around special characters (such as '=' and '/'). ** Since the special characters are replaced with special codes, quotes ** are also removed. ** ** ^REQUIREMENTS: ** <str> should be non-null and non-empty ** ** ^SIDE-EFECTS: ** <str> is "trimmed" to canonical form and special characters are mapped ** to a unique code. ** ** ^RETURN-VALUE: ** The address of the translated string. ** ** ^ALGORITHM: ** - remove all unquoted whitespace following any unquoted "/:=+(" ** - remove all unquoted whitespace preceding any unquoted "/:=+)" ** - compress all unquoted whitespace, ** - remove all unquoted parentheses, ** - re-map all other unquoted special characters and remove quotes. ** use the following mapping: ** whitespace ==> '\001' ** '/' ==> '\002' ** ':' & '=' ==> '\003' ** ',' & '+' ==> '\004' ***^^**********************************************************************/ #ifdef __ANSI_C__ X static char *dcl_strxlat( char *str ) #endif { X register char c, *pread = str, *pwrite = str; X BOOL quoted = FALSE; X X /* X ** pass1 - scan forward, removing all whitespace after unquoted "/:=+,(" X */ X while ( c = *pwrite++ = *pread++ ) { X if ( c == '"' ) TOGGLE(quoted); X if ( !quoted && strchr("/:=+,(", c) ) X while( isspace(*pread) ) ++pread; X } X *--pwrite = '\0'; /* NUL terminate */ X X /* X ** pass2 - scan backward, removing all whitespace before unquoted "/:=+,)" X */ X pread = --pwrite; /* set to last NON-NUL char */ X quoted = FALSE; X while ( pread >= str ) { X c = *pwrite-- = *pread--; X if ( c == '"' ) TOGGLE(quoted); X if ( !quoted && strchr("/:=+,)", c) ) X while( isspace(*pread) ) --pread; X } X strcpy(str, ++pwrite); /* reset BOS */ X X /* X ** pass3 - compress all unquoted whitespace, X ** remove all unquoted parentheses, X ** re-map all other unquoted special characters and remove quotes. X ** use the following mapping: X ** whitespace -> '\001' X ** '/' -> '\002' X ** ':' & '=' -> '\003' X ** ',' & '+' -> '\004' X */ X pread = pwrite = str; X quoted = FALSE; X while ( c = *pread++ ) { X if ( c == '"' ) X TOGGLE(quoted); X else if ( !quoted && isspace(c) ) { X *pwrite++ = c_SPACE; X while( isspace(*pread) ) ++pread; X } X else if ( !quoted && (c == '(' || c == ')') ) X continue; X else if ( !quoted && c == '/' ) X *pwrite++ = c_QUAL; X else if ( !quoted && (c == ':' || c == '=') ) X *pwrite++ = c_QSEP; X else if ( !quoted && (c == ',' || c == '+') ) X *pwrite++ = c_LSEP; X else X *pwrite++ = c; X }/*while*/ X X *pwrite = '\0'; /* NUL-terminate */ X return str; } X X /*************************************************************************** ** ^FUNCTION: dcl_split - split a string up into a vector of DCL tokens ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static dcl_token_t *dcl_split( str ) /* ** ^PARAMETERS: */ X char *str; /* -- the string to split up into tokens */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Dcl_split will split a string up into tokens (according to DCL grammar ** rules) and will additionally associate each token with a type (namely: ** a qualifier, a positional paramater, or the End-of-Tokens symbol). ** ** ^REQUIREMENTS: ** Assume dcl_strxlat(str) has already been performed. ** ** ^SIDE-EFFECTS: ** <str> is modified in much the same manner as it would have ** been modified if it were passed as the vector_string to strsplit(). ** ** ^RETURN-VALUE: ** A vector of dcl_tokens. ** ** ^ALGORITHM: ** - first count the number of tokens and also try to interpret stuff ** like "parm1.1/qual1,parm1.2" by replacing the comma with a space. ** - allocate space for the vector of DCL tokens. ** - assign the approriate value and type for each token. ** ** ^CAVEATS: ** Does not treate "/qual=(val1,val2/str,..)" as illegal ** ( parses it as if it were "/qual=(val1,val2)/str" ) ** ** Replaces "parm1.1/qual,parm1.2" with "parm1.1/qual parm1.2" ** which works only because parseargs requires a VMS ** positional list to be comma OR whitespace separated ** (not just comma separated). ***^^**********************************************************************/ #ifdef __ANSI_C__ X static dcl_token_t *dcl_split( char *str ) #endif { X int tokc = 1; /* number of tokens */ X dcl_token_t *tokv = (dcl_token_t *)NULL; /* vector of tokens */ X register char *pread, c; X register int i; X X if ( !str || !(*str) ) return (dcl_token_t *)NULL; X X /* 1st pass (left-to-right) : count tokens */ X pread = ( *str == c_QUAL ) ? (str + 1) : str; X while ( c = *pread++ ) { X if ( c == c_QUAL || c == c_SPACE ) ++tokc; X if ( c == c_QUAL ) { X /* replace "p1.1/qual,p1.2" with "p1.1/qual p1.2" */ X char *p, delims[5]; X X sprintf( delims, "%c%c%c%c", c_QSEP, c_LSEP, c_QUAL, c_SPACE ); X if ( (p = strpbrk((str + 1), delims)) && (*p == c_LSEP) ) X *p == c_SPACE; X } X } X X X /* allocate vector */ X tokv = (dcl_token_t *)malloc( (tokc + 1) * sizeof(dcl_token_t) ); X if ( tokv == (dcl_token_t *)NULL ) { X syserr( "malloc() failed in dcl_split()" ); X } X tokv[ tokc ].type = EndOfLine; X tokv[ tokc ].token = CHARNULL; X X /* 2nd pass (right-to-left) : assign tokens to strings */ X for ( i = 1, --pread ; pread >= str ; pread-- ) { X if ( *pread == c_SPACE || *pread == c_QUAL ) { X tokv[ tokc - i ].token = pread + 1; X tokv[ tokc - i ].type = ( *pread == c_QUAL ) ? Qualifier : Parameter; X *pread = '\0'; X ++i; X } X } X X if ( *str ) { /* then 1st char could NOT have been '/' */ X tokv -> token = str; X tokv -> type = Parameter; X } X X return tokv; } X X /*************************************************************************** ** ^FUNCTION: dcl_restore - restore the `escaped' characters in a token ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static char *dcl_restore( tokstr ) /* ** ^PARAMETERS: */ X char *tokstr; /* -- the token string to restore */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Dcl_restore will attempt to restore any DCL special characters (such as ** '/' and '=') that may have been escaped by dcl_strxlat(). ** ** ^REQUIREMENTS: ** tokstr should be non-null and non-empty ** ** ^SIDE-EFFECTS: ** Any escape characters (such as c_QUAL) are restored to their ascii ** representation. ** ** ^RETURN-VALUE: ** The address of the restored string ** ** ^ALGORITHM: ** - for each character in tokstr ** - if it is special then replace it with its ascii code ** end-if ** end-for ** ** ^CAVEATS: ** The string is not restored to way it was before it was processed by ** dcl_strxlat(). Any characters that were removed are still missing. ** Furthermore, characters such as ':' and '=' which map to the same ** code are not always restored to what they were before but are always ** restored to one of the characters (e.g. c_QSEP is always restored to ** an '=' character even though it could have been '=' OR ':'). ***^^**********************************************************************/ #ifdef __ANSI_C__ X static char *dcl_restore( char *tokstr ) #endif { X register char *str = tokstr; X X if ( !str || !*str ) return str; X X for ( ; *str ; str++ ) { X switch( *str ) { X case c_SPACE : *str = ' '; break; X case c_QUAL : *str = '/'; break; X case c_QSEP : *str = '='; break; X case c_LSEP : *str = ','; break; X default : break; X } X } X X return tokstr; } X X X X /*************************************************************************** ** ^FUNCTION: split_list - function to handle ARGLISTs and ARGVECs ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static BOOL split_list( ad, vp, cmd ) /* ** ^PARAMETERS: */ X ARGDESC *ad; /* -- the argument which takes multiple values */ X char *vp; /* -- the string of values for the argument */ X ARGDESC *cmd; /* -- the command to which the argument belongs */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Split_list will split the string containing the set of values into ** a set of tokens and will then attempt to convert each token (in the ** order given) using the ad_type function of the argument structure. ** ** ^REQUIREMENTS: ** <vp> must already be preprocessed by dcl_strxlat to escape any quoted ** characters and to map special characters to their corresponding values. ** ** ^SIDE-EFECTS: ** Ad has some of its flags modified as well as any modifications that ** are made by the ad_type function. ** ** <vp> is modified by strsplit(). ** ** ^RETURN-VALUE: ** TRUE if all is hunky-dory; FALSE otherwise ** ** ^ALGORITHM: ** - Split vp into a vector of tokens ** - foreach token ** - call ad_type(ad, token, copyf) ** end-if ** - set the ARGGIVEN and ARGVALGIVEN flags accordingly ***^^**********************************************************************/ #ifdef __ANSI_C__ X static BOOL split_list( ARGDESC *ad, char *vp, ARGDESC *cmd ) #endif { X char **arg_vec = (char **)NULL; X int i, arg_num = 0; X BOOL err = FALSE; X char delims[2]; X X /* set-up delimiter string */ X *delims = c_LSEP; X *(delims + 1) = '\0'; X X /* break string up into to tokens and handle each one */ X arg_num = strsplit( &arg_vec, vp, delims ); X for ( i = 0 ; i < arg_num ; i++ ) { X vp = arg_vec[i]; X X /* try to convert the type */ X if ( !HANDLE(ad, dcl_restore(vp), cmd_flags(cmd)) ) err = TRUE; X } X if ( !err ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X X if ( ARG_isPOSITIONAL(ad) ) { X cmd_list(cmd) = ad; X } X else { X cmd_list(cmd) = ARGDESCNULL; X } X X free( arg_vec ); X X return !err; } X X /*************************************************************************** ** ^FUNCTION: vms_parse - parse VMS/DCL arg-vectors ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X int vms_parse( argv, argd ) /* ** ^PARAMETERS: */ X char *argv[]; /* -- the vector of string arguments from the command-line */ X ARGDESC argd[]; /* -- the programmer description of the command and its args */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Vms_parse will parse the arguments in the given vector of strings, ** assign the corresponding values to the command-line arguments specified ** in argd, and check the syntax of the command-line. ** ** ^REQUIREMENTS: ** The final element in argv must be a NULL pointer. ** ** ^SIDE-EFECTS: ** argd is modified according to the command-line description and parameters ** ** ^RETURN-VALUE: ** pe_SUCCESS (0) if no errors are encountered ** pe_SYSTEM (-1) if a system error is encountered ** pe_SYNTAX if a syntax error is encountered ** ** ^ALGORITHM: ** - compare argv to the command-line (use the command-line if equal) ** - put argv back into a single string and translate it using dcl_strxlat ** - reparse the string into DCL tokens using dcl_strsplit ** - for each DCL token ** - attempt to match the token as a qualifier ** - if it is a qualifier ** - record and convert its value (if any) ** - else it is a positional parameter ** - record and convert its value (if any) ** - else there are too many arguments ** - return pe_SYNTAX ** end-if ** end-for ***^^**********************************************************************/ #ifdef __ANSI_C__ X int vms_parse( char *argv[], ARGDESC argd[] ) #endif { X register ARGDESC *ad, *args, *cmd; X register char *p; X char *avstr; X BOOL is_match = FALSE; X int parse_error = pe_SUCCESS; X dcl_token_t *tok, *tokvec; X argName_t keyword; X argMask_t saveflags, flags; X X if ( !argd ) return parse_error; X X /* initialize command-structure */ X if ( !CMD_isINIT(argd) ) init_args( argd ); X cmd = argd; X saveflags = cmd_flags(cmd); X X if ( !argv || !*argv ) return parse_error; X X (VOID) is_cmdline( (CONST char **)argv, &avstr ); X BSET( cmd_flags(cmd), pa_COPYF ); X (VOID) dcl_strxlat( avstr ); X if ( !avstr || !*avstr ) return parse_error; X tokvec = dcl_split( avstr ); X X /* run through the token vector */ X for ( tok = tokvec ; (p = tok -> token) ; tok++ ) { X X if ( tok -> type == Qualifier && !BTEST(cmd_state(cmd), ps_NOFLAGS) ) { X char c = '\0', *s, delims[2]; X X /* set-up delimiter string */ X *delims = c_QSEP; X *(delims + 1) = '\0'; X X /* skip past qualifier prefix and look for possible argument */ X s = strpbrk(p, delims); X if (s) { X c = *s; X *s++ = '\0'; X } X X is_match = FALSE; X for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) { X for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) { X if (arg_type(ad) == argDummy) continue; X X if (!ARG_isPOSONLY(ad) && match(p, arg_sname(ad)) == 0) { X is_match = TRUE; X break; X }/*if*/ X } X } X X if (c) *(s-1) = c; /* restore the equal sign */ X X if ( !is_match ) { X usrerr("qualifier %s unknown", p); X parse_error = pe_SYNTAX; X continue; X } X X /* end-qualifiers */ X if ( arg_type(ad) == argEnd ) { X BSET( cmd_state(cmd), ps_NOFLAGS ); X continue; X } X /* if usage - just print usage and exit */ X if ( arg_type(ad) == argUsage ) { X Usage_Requested = TRUE; X usage( argd ); X free( avstr ); X if ( tokvec ) free( tokvec ); X cmd_flags(cmd) = saveflags; X exit(1); X } X /* have we seen this one before */ X flags = arg_flags(ad); X if ( ARG_isGIVEN(ad) ) X BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP ); X X /* ARGNOVALs are special, having no value */ X if ( ! ARG_isVALTAKEN(ad) ) { X if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) { X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X else { X BSET( arg_flags(ad), ARGGIVEN ); X ad = ARGDESCNULL; X } X continue; X }/*if ARGNOVAL*/ X X /* now get the real value */ X if ( !s || !(*s) ) { X if ( ARG_isVALOPTIONAL(ad) ) { X BSET( arg_flags(ad), ARGVALGIVEN ); X } X else { X (VOID) get_keyword( arg_sname(ad), keyword ); X usrerr("qualifier %s requires an argument", keyword); X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X continue; X }/*if*/ X X if( ARG_isMULTIVAL(ad) ) { X if( !split_list(ad, s, cmd) ) { X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X else { X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X } X continue; X }/*if list*/ X X /* try to convert the type */ X if ( !HANDLE(ad, s, cmd_flags(cmd)) ) { X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X else { X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X } X X continue; X }/*if qual*/ X else { X /* parsing a vector of arguments */ X if ( cmd_list(cmd) ) { X ad = cmd_list(cmd); X flags = arg_flags(ad); X if ( ARG_isGIVEN(ad) ) X BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP ); X X BSET( arg_flags(ad), ARGVALSEP ); X X if( ARG_isMULTIVAL(ad) ) { X if( !split_list(ad, p, cmd) ) parse_error = pe_SYNTAX; X } X else if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) { X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X X if ( !parse_error ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X X continue; X } X /* positional argument */ X is_match = FALSE; X for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) { X for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) { X if (arg_type(ad) == argDummy) continue; X X if ( ARG_isPOSITIONAL(ad) && X (!ARG_isGIVEN(ad) || ARG_isMULTIVAL(ad)) ) { X is_match = TRUE; X break; X }/*if*/ X } X } X X if ( !is_match ) { X usrerr("too many arguments"); X parse_error = pe_SYNTAX; X continue; X } X X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) { X BSET( cmd_state(cmd), ps_NOFLAGS ); X } X flags = arg_flags(ad); X if ( ARG_isGIVEN(ad) ) X BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP ); X X BSET( arg_flags(ad), ARGVALSEP ); X X if( ARG_isMULTIVAL(ad) ) { X if( !split_list(ad, p, cmd) ) { X arg_flags(ad) = flags; X parse_error = pe_SYNTAX; X } X else { X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X } X continue; X }/*if list*/ X X /* try to convert */ X if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) { X arg_flags(ad) = flags; X parse_error = TRUE; X } X else { X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN ); X } X X }/*if parameter*/ X }/*while*/ X X free( avstr ); X if ( tokvec ) free( tokvec ); X cmd_flags(cmd) = saveflags; X return parse_error; } X X /*************************************************************************** ** ^FUNCTION: fmtarg - format command-argument syntax ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static int fmtarg( ad, buf ) /* ** ^PARAMETERS: */ X ARGDESC *ad; /* -- pointer to the argument to format */ X char *buf; /* -- character buffer to hold the formatted result */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Fmtarg will determine the proper command-line syntax for the ** given argument and write the result to the given buffer. ** ** ^REQUIREMENTS: ** buf must be large enough to hold the formatted result (100 characters ** should do the trick). ** ** ^SIDE-EFECTS: ** buf is overwritten. ** ** ^RETURN-VALUE: ** The number of printable characters in the argument-syntax-string ** ** ^ALGORITHM: ** Print argument usage based on whether or not the argument is ** positional, hidden, multi-valued (list or vector), etc .... ** Optional arguments and values are enclosed in square braces. ***^^**********************************************************************/ #ifdef __ANSI_C__ X static int fmtarg( const ARGDESC *ad, char *buf ) #endif { X /* buf must already be large enough */ X char * pos; X argName_t keyword, name; X X (VOID) get_name( arg_sname(ad), name ); X X if (ARG_isPOSITIONAL(ad)) { X sprintf( buf, "<%s>", name ); X } X else { X (VOID) get_keyword( arg_sname(ad), keyword ); X sprintf( buf, "%c%s", *s_KWD_PFX, keyword ); X pos = buf + strlen(buf); X X if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) { X if ( ARG_isVALOPTIONAL(ad)) { X sprintf( pos, "[%c<%s>]", *s_ARG_SEP, name ); X } X else { X sprintf( pos, "%c<%s>", *s_ARG_SEP, name ); X } X }/*if*/ X }/*else*/ X X return (int) strlen(buf); } X X /*************************************************************************** ** ^FUNCTION: vms_usage - print a usage message ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X VOID vms_usage( argd, usage_flags ) /* ** ^PARAMETERS: */ X ARGDESC *argd; /* -- the command-descriptor array */ X argMask_t usage_flags; /* -- flags set by $USAGECNTL */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Vms_usage will print the VMS/DCL command-line usage of the given ** command on standard diagnostic output (stderr). The content of the ** usage message is controlled by the bitmasks in usage_flags which ** correspond to the settings in the user's USAGECNTL symbol. ** ** ^REQUIREMENTS: ** argd should be a non-null command-line argument-descriptor array ** ** ^SIDE-EFECTS: ** Prints on stderr. ** ** ^RETURN-VALUE: ** None. ** ** ^ALGORITHM: ** - if no usage is desired then exit ** - if paging is requested print to the pager instead of stderr ** - print the command-line syntax ** - if the description is requested print it ** - if verbose mode is requested, print the description of each argument ***^^**********************************************************************/ #ifdef __ANSI_C__ X void vms_usage( const ARGDESC *argd, argMask_t usage_flags ) #endif { X register CONST ARGDESC *ad, *args, *cmd; X int max_cols = 80, max_lines = 24; X int margin, ll, pl, qualifiers, longest, positionals; X BOOL first = TRUE; X FILE *fp; X X if ( !argd ) return; X X /* initialize command-structure */ X if ( !CMD_isINIT(argd) ) init_args( (ARGDESC *)argd ); X cmd = argd; X X /* get screen size */ X get_winsize( fileno(stderr), &max_lines, &max_cols ); X X /* force verbose-mode if requested */ X if ( Usage_Requested ) BSET( usage_flags, usg_VERBOSE ); X X if ( BTEST(usage_flags, usg_NONE) ) return; X X fp = ( BTEST(usage_flags, usg_PAGED) ) X ? pgopen( stderr, getenv("USAGE_PAGER") ) X : stderr; X X /* allow null argument descriptor */ X fprintf(fp, "Format: %s", ProgName); X X ll = strlen( ProgName ) + 8; X margin = ll + 1; X longest = 0; X X for ( positionals = 0 ; positionals < 2 ; positionals++ ) { X for ( args = argd ; args ; args = cmd_defargs(args) ) { X for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) { X argName_t buf, name; X X /* don't display hidden arguments */ X if ( ARG_isHIDDEN(ad) ) continue; X if ( !positionals && ARG_isPOSITIONAL(ad) ) continue; X if ( positionals && !ARG_isPOSITIONAL(ad) ) continue; X X /* figure out how wide this parameter is (for printing) */ X pl = fmtarg(ad, buf); X X if ( pl > longest ) longest = pl; X X X if ( ARG_isMULTIVAL(ad) ) { X (VOID) get_name( arg_sname(ad), name ); X strcat(buf, "[,<"); X strcat(buf, name); X strcat(buf, ">...]"); X pl += 8 + strlen(name); X } X if ( !ARG_isREQUIRED(ad) ) { X pl += 2; /* [] */ X } X X /* see if this will fit */ X if ( (ll + pl + 1) > (max_cols - first) ) { X /* no... start a new line */ X fprintf(fp, "\n%*s", margin, ""); X ll = margin; X } X else { X /* yes... just throw in a space */ X fputc(' ', fp); X ++ll; X } X ll += pl; X X /* show the argument */ X if ( ARG_isREQUIRED(ad) ) fputc('[', fp); X fprintf(fp, buf); X if ( ARG_isREQUIRED(ad) ) fputc(']', fp); X X first = FALSE; /* not first line anymore */ X }/*for each ad */ X }/* for each argd */ X }/* for each parm-type */ X X fputc('\n', fp); X X if ( BTEST(usage_flags, usg_DESCRIPTION) ) { X CONST char *description = cmd_description(cmd); X X if ( description && *description ) { X fprintf( fp, "Description:\n" ); X indent_para(fp, max_cols, 8, "", 0, description); X fputc( '\n', fp ); X } X }/*if*/ X X if ( !BTEST(usage_flags, usg_VERBOSE) ) { X if ( pgactive(fp) ) (VOID) pgclose( fp ); X return; X } X X qualifiers = 0; X for ( positionals = 0 ; positionals < 2 ; positionals++ ) { X for ( args = argd ; args ; args = cmd_defargs(args) ) { X for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) { X argName_t buf; X X /* don't display hidden arguments */ X if ( ARG_isHIDDEN(ad) ) continue; X if ( !positionals && ARG_isPOSITIONAL(ad) ) continue; X if ( positionals && !ARG_isPOSITIONAL(ad) ) continue; X X if ( !qualifiers++ ) fprintf(fp, "Qualifiers/Parameters:\n"); X (VOID) fmtarg(ad, buf); X indent_para(fp, max_cols, 8, buf, longest+2, arg_description(ad) ); X }/*for each ad */ X }/* for each argd */ X }/* for each parm-type */ X X if ( pgactive(fp) ) (VOID) pgclose( fp ); } X SHAR_EOF chmod 0664 parseargs/vms_args.c || echo 'restore of parseargs/vms_args.c failed' Wc_c="`wc -c < 'parseargs/vms_args.c'`" test 30360 -eq "$Wc_c" || echo 'parseargs/vms_args.c: original size 30360, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= parseargs/vprintf.c ============== if test -f 'parseargs/vprintf.c' -a X"$1" != X"-c"; then echo 'x - skipping parseargs/vprintf.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting parseargs/vprintf.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'parseargs/vprintf.c' && /* Portable vsprintf by Robert A. Larson <blarson@skat.usc.edu> */ X /* Copyright 1989 Robert A. Larson. X * Distribution in any form is allowed as long as the author X * retains credit, changes are noted by their author and the X * copyright message remains intact. This program comes as-is X * with no warentee of fitness for any purpose. X * X * Thanks to Doug Gwyn, Chris Torek, and others who helped clarify X * the ansi printf specs. X * X * Please send any bug fixes and improvements to blarson@skat.usc.edu . X * The use of goto is NOT a bug. X */ X /* Feb 7, 1989 blarson First usenet release */ /* Oct 20, 1990 Brad Appleton -- enclosed in #ifdef BSD for parseargs */ /* Oct 21, 1990 Brad Appleton -- added test in #ifdef VPRINTF_TEST */ /* Feb 25, 1990 Brad Appleton -- #included "useful.h" and added #ifdefs X * to compile for ANSI-C as well as K&R X */ X X /* This code implements the vsprintf function, without relying on X * the existance of _doprint or other system specific code. X * X * Define NOVOID if void * is not a supported type. X * X * Two compile options are available for efficency: X * INTSPRINTF should be defined if sprintf is int and returns X * the number of chacters formated. X * LONGINT should be defined if sizeof(long) == sizeof(int) X * X * They only make the code smaller and faster, they need not be X * defined. X * X * UNSIGNEDSPECIAL should be defined if unsigned is treated differently X * than int in argument passing. If this is definded, and LONGINT is not, X * the compiler must support the type unsingned long. X * X * Most quirks and bugs of the available sprintf fuction are duplicated, X * however * in the width and precision fields will work correctly X * even if sprintf does not support this, as will the n format. X * X * Bad format strings, or those with very long width and precision X * fields (including expanded * fields) will cause undesired results. X */ X X /* Parseargs only needs this stuff for BSD Unix -- Brad Appleton */ #include <useful.h> X #ifdef BSD #include <stdio.h> #include <ctype.h> X #ifdef OSK /* os9/68k can take advantage of both */ # define LONGINT # define INTSPRINTF #endif X /* This must be a typedef not a #define! */ #ifdef NOVOID X typedef char *pointer; #else X typedef void *pointer; #endif X #ifdef INTSPRINTF # define Sprintf(string,format,arg) (sprintf((string),(format),(arg))) #else # define Sprintf(string,format,arg) (\ X sprintf((string),(format),(arg)),\ X strlen(string)\ ) #endif X typedef int *intp; X #ifdef __ANSI_C__ X int vsprintf(char *dest, register const char *format, va_list args) #else X int vsprintf(dest, format, args) X char *dest; X register char *format; X va_list args; #endif { X register char *dp = dest; X register char c; X register char *tp; X char tempfmt[64]; #ifndef LONGINT X int longflag; #endif X X tempfmt[0] = '%'; X while( (c = *format++) != 0) { X if(c=='%') { X tp = &tempfmt[1]; #ifndef LONGINT X longflag = 0; #endif continue_format: X switch(c = *format++) { X case 's': X *tp++ = c; X *tp = '\0'; X dp += Sprintf(dp, tempfmt, VA_ARG(args, char *)); X break; X case 'u': X case 'x': X case 'o': X case 'X': #ifdef UNSIGNEDSPECIAL X *tp++ = c; X *tp = '\0'; #ifndef LONGINT X if(longflag) X dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned long)); X else #endif X dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned)); X break; #endif X case 'd': X case 'c': X case 'i': X *tp++ = c; X *tp = '\0'; #ifndef LONGINT X if(longflag) X dp += Sprintf(dp, tempfmt, VA_ARG(args, long)); X else #endif X dp += Sprintf(dp, tempfmt, VA_ARG(args, int)); X break; X case 'f': X case 'e': X case 'E': X case 'g': X case 'G': X *tp++ = c; X *tp = '\0'; X dp += Sprintf(dp, tempfmt, VA_ARG(args, double)); X break; X case 'p': X *tp++ = c; X *tp = '\0'; X dp += Sprintf(dp, tempfmt, VA_ARG(args, pointer)); X break; X case '-': X case '+': X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X case '.': X case ' ': X case '#': X case 'h': X *tp++ = c; X goto continue_format; X case 'l': #ifndef LONGINT X longflag = 1; X *tp++ = c; #endif X goto continue_format; X case '*': X tp += Sprintf(tp, "%d", VA_ARG(args, int)); X goto continue_format; X case 'n': X *VA_ARG(args, intp) = dp - dest; X break; X case '%': X default: X *dp++ = c; X break; X } X } else *dp++ = c; X } X *dp = '\0'; X return dp - dest; } X X #ifdef __ANSI_C__ X int vfprintf(FILE *dest, register const char *format, va_list args) #else X int vfprintf(dest, format, args) X FILE *dest; X register char *format; X va_list args; #endif { X register char c; X register char *tp; X register int count = 0; X char tempfmt[64]; #ifndef LONGINT X int longflag; #endif X X tempfmt[0] = '%'; X while(c = *format++) { X if(c=='%') { X tp = &tempfmt[1]; #ifndef LONGINT X longflag = 0; #endif continue_format: X switch(c = *format++) { X case 's': X *tp++ = c; X *tp = '\0'; X count += fprintf(dest, tempfmt, VA_ARG(args, char *)); X break; X case 'u': X case 'x': X case 'o': X case 'X': #ifdef UNSIGNEDSPECIAL X *tp++ = c; X *tp = '\0'; #ifndef LONGINT X if(longflag) X count += fprintf(dest, tempfmt, VA_ARG(args, unsigned long)); X else #endif X count += fprintf(dest, tempfmt, VA_ARG(args, unsigned)); X break; #endif X case 'd': X case 'c': X case 'i': X *tp++ = c; X *tp = '\0'; #ifndef LONGINT X if(longflag) X count += fprintf(dest, tempfmt, VA_ARG(args, long)); X else #endif X count += fprintf(dest, tempfmt, VA_ARG(args, int)); X break; X case 'f': X case 'e': X case 'E': X case 'g': X case 'G': X *tp++ = c; X *tp = '\0'; X count += fprintf(dest, tempfmt, VA_ARG(args, double)); X break; X case 'p': X *tp++ = c; X *tp = '\0'; X count += fprintf(dest, tempfmt, VA_ARG(args, pointer)); X break; X case '-': X case '+': X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X case '.': X case ' ': X case '#': X case 'h': X *tp++ = c; X goto continue_format; X case 'l': #ifndef LONGINT X longflag = 1; X *tp++ = c; #endif X goto continue_format; X case '*': X tp += Sprintf(tp, "%d", VA_ARG(args, int)); X goto continue_format; X case 'n': X *VA_ARG(args, intp) = count; X break; X case '%': X default: X putc(c, dest); X count++; X break; X } X } else { X putc(c, dest); X count++; X } X } X return count; } X #ifdef __ANSI_C__ X int vprintf(const char *format, va_list args) #else X int vprintf(format, args) X char *format; X va_list args; #endif { X return vfprintf(stdout, format, args); } #endif /* BSD Unix ONLY */ X X /* use a VERY SIMPLE test case to test this out -- Brad Appleton */ #ifdef VPRINTF_TEST X /*VARARGS1*/ #ifdef __ANSI_C__ X int vtest( char *fmt, ... ) #else X int vtest( fmt, va_alist ) X char *fmt; X va_dcl #endif { X va_list ap; X int rc; X X VA_START(ap, fmt); X rc = vprintf( fmt, ap ); X VA_END(ap); X X return rc; } X void main() { X printf( "its a %s %% day in the %d neighborhood for %*s\n", X "pitiful", 4, 8, "fun" ); X X vtest( "its a %s %% day in the %d neighborhood for %*s\n", X "pitiful", 4, 8, "fun" ); } X #endif /* VPRINTF_TEST */ SHAR_EOF chmod 0664 parseargs/vprintf.c || echo 'restore of parseargs/vprintf.c failed' Wc_c="`wc -c < 'parseargs/vprintf.c'`" test 8146 -eq "$Wc_c" || echo 'parseargs/vprintf.c: original size 8146, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= parseargs/winsize.c ============== if test -f 'parseargs/winsize.c' -a X"$1" != X"-c"; then echo 'x - skipping parseargs/winsize.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting parseargs/winsize.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'parseargs/winsize.c' && /************************************************************************* ** ^FILE: winsize.c - implement the routine get_winsize() ** ** ^DESCRIPTION: ** Implement the get_winsize() function for various windowing and ** operating systems. ** ** ^HISTORY: ** 10/01/90 Brad Appleton <brad@ssd.csd.harris.com> Created ***^^**********************************************************************/ X X /*************************************************************************** ** ^FUNCTION: get_winsize - get the current window size ** ** ^SYNOPSIS: ** void get_winsize( fd, nrows, ncols ) ** ** ^PARAMETERS: ** int fd; ** -- file-descriptor associated with the "output-window" ** ** int *nrows; ** -- pointer to number of rows in window ** ** int *ncols; ** -- pointer to number of columns in window ** ** ^DESCRIPTION: ** Get_winsize will attempt to determine the maximum number of ** rows and colums that will fit on one screen-full of the associated ** output device. If it fails to do this, it will assume the "window" ** is a 24x80 (rows by columns) display. ** ** ^REQUIREMENTS: ** fd must correspond to a valid output device. ** ** ^SIDE-EFFECTS: ** The memory addressed by nrows and ncols is assigned the corresponding ** appropriate value(s). ** ** ^RETURN-VALUE: ** None. ** ** ^ALGORITHM: ** System dependent. ***^^**********************************************************************/ X #if ( defined(__STDC__) || defined(c_plusplus) || defined(__cplusplus) ) # define GET_WINSIZE(fd,nrows,ncols) \ X void get_winsize( int fd, int *nrows, int *ncols ) #else # define GET_WINSIZE(fd,nrows,ncols) \ X void get_winsize( fd, nrows, ncols ) \ X int fd, *nrows, *ncols; /* nrows and ncols are passed by reference */ #endif X #include <stdio.h> #include <useful.h> X #define DEFAULT_ROWS 24 #define DEFAULT_COLS 80 X #ifdef vms X #include <stdio.h> #include <iodef.h> #include <ssdef.h> #include <descrip.h> X X /* structure to contain terminal characteristics */ typedef struct { X short garb1, cols; X char garb2, garb3, garb4, rows; } termchar_t; X int sys$assign(); int sys$qiow(); int sys$dassgn(); X GET_WINSIZE( fd, nrows, ncols ) { X int c, charlen = 8; X termchar_t termchar; X int chan; X $DESCRIPTOR( devnam,"SYS$COMMAND" ); X X sys$assign( &devnam, &chan, 0, 0 ); X sys$qiow( 0, chan, IO$_SENSEMODE, 0, 0, 0, &termchar, &charlen, 0, 0, 0, 0 ); X sys$dassgn( chan ); X X *nrows = ( termchar.rows > 0 ) ? (int) termchar.rows : DEFAULT_ROWS; X *ncols = ( termchar.cols > 0 ) ? (int) termchar.cols : DEFAULT_COLS; } X #else #ifdef unix X X /* X ** we will either try to access terminfo through the termcap-interface X ** in the curses library (which would require linking with -lcurses) X ** or use termcap directly (which would require linking with -ltermcap) X */ #ifndef USE_TERMCAP #if ( defined(USE_TERMINFO) || defined(USE_CURSES) ) #define USE_TERMCAP #endif #endif X X #ifdef USE_TERMCAP # define TERMBUFSIZ 1024 # define UNKNOWN_TERM "unknown" # define DUMB_TERMBUF "dumb:co#80:hc:" extern int tgetent(); extern int tgetnum(); #endif X X X /* try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */ #include <termios.h> #if ( !defined(TIOCGWINSZ) && !defined(TIOCGSIZE) && !defined(WIOCGETD) ) #include <sys/ioctl.h> #endif X X /* if still dont have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */ #if ( !defined(TIOCGWINSZ) && !defined(TIOCGSIZE) && !defined(WIOCGETD) ) #include <sgtty.h> #endif X /* ** get_winsize() -- determine # of rows/columns that will fit on the screen. ** ** The environment variables $LINES and $COLUMNS will be used if they exist. ** If not, then the TIOCGWINSZ call to ioctl() is used (if it is defined). ** If not, then the TIOCGSIZE call to ioctl() is used (if it is defined). ** If not, then the WIOCGETD call to ioctl() is used (if it is defined). ** If not, then get the info from terminfo/termcap (if it is there) ** Otherwise, assume we have a 24x80 screen. */ X extern int ioctl(); extern int isatty(); extern long atol(); extern char *getenv(); X GET_WINSIZE( fd, nrows, ncols ) { X char *lines_env, *cols_env; X long lrow = 0, lcol = 0; X int lines = 0, cols = 0; #ifdef USE_TERMCAP X char term_buf[ TERMBUFSIZ ], *term_env; #endif #ifdef TIOCGWINSZ X struct winsize win; #else #ifdef TIOCGSIZE X struct ttysize win; #else #ifdef WIOCGETD X struct uwdata win; #endif #endif #endif X X /* make sure that fd corresponds to a terminal */ X if ( !isatty( fd ) ) { X *nrows = DEFAULT_ROWS; X *ncols = DEFAULT_COLS; X return; X } X X /* LINES & COLUMNS environment variables override everything else */ X lines_env = getenv( "LINES" ); X if ( lines_env && (lrow = atol(lines_env)) > 0 ) { X *nrows = lines = (int) lrow; X } X X cols_env = getenv( "COLUMNS" ); X if ( cols_env && (lcol = atol(cols_env)) > 0 ) { X *ncols = cols = (int) lcol; X } X #ifdef TIOCGWINSZ X /* see what ioctl() has to say (overrides terminfo & termcap) */ X if ( (!lines || !cols) && ioctl(fd, TIOCGWINSZ, &win) != -1 ) { X if ( !lines && win.ws_row > 0 ) { X *nrows = lines = (int) win.ws_row; X } X X if ( !cols && win.ws_col > 0 ) { X *ncols = cols = (int) win.ws_col; X } X }/*if*/ #else #ifdef TIOCGSIZE X /* see what ioctl() has to say (overrides terminfo & termcap) */ X if ( (!lines || !cols) && ioctl(fd, TIOCGSIZE, &win) != -1 ) { X if ( !lines && win.ts_lines > 0 ) X *nrows = lines = (int) win.ts_lines; X X if ( !cols && win.ts_cols > 0 ) X *ncols = cols = (int) win.ts_cols; X }/*if*/ #else #ifdef WIOCGETD X /* see what ioctl() has to say (overrides terminfo & termcap) */ X if ( (!lines || !cols) && ioctl(fd, WIOCGETD, &win) != -1 ) { X if ( !lines && win.uw_height > 0 ) X *nrows = lines = (int) (win.uw_height / win.uw_vs); X X if ( !cols && win.uw_width > 0 ) X *ncols = cols = (int) (win.uw_width / win.uw_hs); X }/*if*/ #endif #endif #endif X #ifdef USE_TERMCAP X /* see what terminfo/termcap has to say */ X if ( !lines || !cols ) { X if ( !(term_env = getenv("TERM")) ) X term_env = UNKNOWN_TERM; X X if ( (tgetent(term_buf, term_env) <= 0) ) X strcpy( term_buf, DUMB_TERMBUF ); X X if ( !lines && (lrow = tgetnum("li")) > 0 ) X *nrows = lines = (int) lrow; X X if ( !cols && (lcol = tgetnum("co")) > 0 ) X *ncols = cols = (int) lcol; X } #endif X X /* use 80x24 if all else fails */ X if ( !lines ) *nrows = DEFAULT_ROWS; X if ( !cols ) *ncols = DEFAULT_COLS; X }/*get_winsize()*/ X #else X GET_WINSIZE( fd, nrows, ncols ) { X /* just use 80x24 */ X *nrows = DEFAULT_ROWS; X *ncols = DEFAULT_COLS; } X #endif /* not a vms system */ #endif /* not a unix-system */ X #ifdef WINSIZE_TEST X /* test get_winsize to see if it works */ main() { X int rows, cols; X X get_winsize( fileno(stderr), &rows, &cols ); X printf( "Output will be %d rows by %d columns\n", rows, cols ); X exit( 0 ); } X #endif SHAR_EOF chmod 0664 parseargs/winsize.c || echo 'restore of parseargs/winsize.c failed' Wc_c="`wc -c < 'parseargs/winsize.c'`" test 7121 -eq "$Wc_c" || echo 'parseargs/winsize.c: original size 7121, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= parseargs/xparse.c ============== if test -f 'parseargs/xparse.c' -a X"$1" != X"-c"; then echo 'x - skipping parseargs/xparse.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting parseargs/xparse.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'parseargs/xparse.c' && /************************************************************************* ** ^FILE: xparse.c - library functions for the parsargs(3) package ** ** ^DESCRIPTION: ** This file implements the following functions in the parseargs library: ** ** init_args() -- constructor for a command-object ** usage() -- pretty-print the command-usage ** parsecntl() -- control parsing, get/set command-attributes ** parseargs() -- parse argumenst from a string vector ** fparseargs() -- parse arguments from a file pointer ** lparseargs() -- parse arguments from an arglist ** sparseargs() -- parse arguyments in a string ** vparseargs() -- parse arguments from a variable argument list ** ** It should be noted that sparseargs() splits the given string up into ** a whitespace separated series of tokens, whereas vparseargs assumes ** that each parameter is already a single token (hence performs no ** token splitting). ** ** Each of these functions returns 0 upon success and non-zero otherwise ** (except for usage() & init_args, which have no return value). ** ** ^FILES: ** <useful.h> ** <parseargs.h> ** ** ^SEE_ALSO: ** argtype(3), parseargs(1), parseargs(3), parsecntl(3), ** ** ^CAVEATS: ** Because of the way argument parsing is implemented under UNIX, MS-DOS ** and OS/2, option arguments which contain a leading dash (`-') (or ** whatever the option prefix character is defined to be) may not be ** specified as a separate argument on the command line, it must be part ** of the same argument. That is to say that if a program has a -f option ** that requires a string argument, then the following: ** -f-arg ** ** will properly assign the string "-arg" to the option whereas the ** following: ** -f -arg ** ** will be interpreted by parseargs as two option strings: the first of ** which ("-f") is missing a required argument and the second of which ** ("-arg") will most likely be flagged as an invalid option. ** ** Similarly, if the user requires an ARGLIST option to take multiple ** arguments with leading dashes then the following method must be used: ** It is a "feature" of parseargs that ARGLIST arguments are always ** appended to the current list of arguments for the given option. Thus, ** if "-f" is an option taking a list of arguments, then the following ** are all equivalent: ** -farg1 arg2 ** -f arg1 arg2 ** -farg1 -farg2 ** -f arg1 -f arg2 ** ** Hence multiple "leading dash" arguments may specified as follows: ** -f-dash_arg1 -f-dash_arg2 ... ** ** ^BUGS: ** When a non-multivalued argument appears more than once on the ** command-line then only the last value supplied is used. A problem ** occurs however in the following scenario: suppose `-s' is an option ** that takes an optional string argument (nd suppose `-x' is some ** boolean flag). Then if the following command-line is issued: ** ** command -s string -x -s ** ** then, the argument flags will properly correspond to the second ** instance of the `-s' option (namely ARGGIVEN will be set but ARGVAL- ** GIVEN will be unset) but the value associated with the option will be ** "string" (because the first instance overwrote the default). ** Because of this, it may be safest to reassign the default value if ** ARGGIVEN is set but ARGVALGIVEN is unset. ** ** ^HISTORY: ** 01/02/91 Brad Appleton <brad@ssd.csd.harris.com> Created ***^^**********************************************************************/ X #include <stdio.h> #include <ctype.h> #include <useful.h> #include "strfuncs.h" X #define PARSEARGS_PRIVATE /* include private definitions */ #define PARSEARGS_NEXTERNS /* exclude external declarations */ #include "parseargs.h" X #ifdef amiga_style # define pa_DEFAULTS 0x000 # define parse_argv_style amiga_parse # define print_usage_style amiga_usage X EXTERN int amiga_parse ARGS(( char **, ARGDESC * )); X EXTERN VOID amiga_usage ARGS(( const ARGDESC *, argMask_t )); #endif #ifdef ibm_style # define pa_DEFAULTS pa_ANYCASE # define parse_argv_style ibm_parse # define print_usage_style ibm_usage X EXTERN int ibm_parse ARGS(( char **, ARGDESC * )); X EXTERN VOID ibm_usage ARGS(( const ARGDESC *, argMask_t )); #endif #ifdef unix_style # define pa_DEFAULTS pa_FLAGS1ST # define parse_argv_style unix_parse # define print_usage_style unix_usage X EXTERN int unix_parse ARGS(( char **, ARGDESC * )); X EXTERN VOID unix_usage ARGS(( const ARGDESC *, argMask_t )); #endif #ifdef vms_style # define pa_DEFAULTS pa_PROMPT # define parse_argv_style vms_parse # define print_usage_style vms_usage X EXTERN int vms_parse ARGS(( char **, ARGDESC * )); X EXTERN VOID vms_usage ARGS(( const ARGDESC *, argMask_t )); #endif X X #if vms # define USER_VARIABLE "symbol" #else # define USER_VARIABLE "environment variable" #endif X X /*************************************************************************** ** ^MACRO: SYNTAX_ERROR - check for syntax errors & missing required arguments ** ** ^SYNOPSIS: ** SYNTAX_ERROR(status, argd) ** ** ^PARAMETERS: ** status ** -- current parsing status returned by last xparsexxx() call ** ** argd ** --argdesc-array ** ** ^RETURN-VALUE: ** Evaluates to TRUE if need to exit, FALSE otherwise ** ** ^ALGORITHM: ** - if (!pa_NOCHECK) and (verify_argreqs == error) then return TRUE ** - else return FALSE ***^^**********************************************************************/ #define SYNTAX_ERROR(status, argd) ( !verify_argreqs(argd, &status) ) X X /*************************************************************************** ** ^GLOBAL-VARIABLE: ProgName ** ** ^VISIBILITY: ** external global (visible to functions in all files) ** ** ^DESCRIPTION: ** ProgName (which is initially NULL) will be used to point to the ** command-name (specified on the command-line) of the command that ** has most recently invoked a function in the parseargs library. ***^^**********************************************************************/ CONST char *ProgName = (char *)NULL; X EXTERN VOID syserr ARGS((const char *, ...)); EXTERN VOID usrerr ARGS((const char *, ...)); EXTERN VOID eprintf ARGS((const char *, ...)); X #ifdef vms_style X EXTERN BOOL argInput ARGS((ARGDESC *, char *, BOOL)); X EXTERN BOOL argOutput ARGS((ARGDESC *, char *, BOOL)); #endif X #define MAXLINE 256 X X /* override argument descriptor, if none given by user */ static ARGDESC Empty_ArgDesc[] = { START_ARGUMENTS, END_ARGUMENTS }; X /*************************************************************************** ** ^SECTION: DEFAULT-ARGUMENTS ** Each argdesc-array has an initial default argument list (which may be ** reset using the pc_DEFARGS function code with parsecntl). This initial ** default argument-list contains `?' and `H' which may be used as single ** character keywords to display command-usage for all command-line ** styles. Similarly, "?", "H", and "Help" may be used as long-keywords ** to display command-usage for all command-line styles. In Addition, ** for VMS style commands, the qualifiers /INPUT=file, /OUTPUT=file, and ** /ERROR=file, may be used to redirect stdin, stdout, and stderr ** (respectively) to a file. For AmigaDOS style commands, the keyword ** "ENDKWDS" may be used to disable parsing for any more keywords on ** the command-line. ***^^**********************************************************************/ static ARGDESC Default_ArgDesc[] = { X START_ARGUMENTS, X /* <name> <flags> <type> <valp> <prompt> */ X { '?', ARGHIDDEN, argUsage, __ NULL, "? (print usage and exit)" }, X { 'H', ARGHIDDEN, argUsage, __ NULL, "Help (print usage and exit)" }, X #ifdef amiga_style X { '-', ARGHIDDEN, argEnd, __ NULL, "ENDKeyWorDS" }, #endif X #ifdef vms_style X { '<', ARGHIDDEN, argInput, __ stdin, "INPUT (redirect SYS$INPUT)" }, X { '>', ARGHIDDEN, argOutput, __ stdout, "OUTPUT (redirect SYS$OUTPUT)" }, X { '%', ARGHIDDEN, argOutput, __ stderr, "ERROR (redirect SYS$ERROR)" }, #endif X X END_ARGUMENTS }; X X #ifdef AmigaDOS # define getenv(s) CHARNULL # define envfree(s) s = CHARNULL #endif X #if ( defined(MSDOS) || defined(OS2) ) X EXTERN char *getenv ARGS(( const char * )); # define envfree(s) s = CHARNULL #endif X #ifdef unix X EXTERN char *getenv ARGS(( const char * )); # define envfree(s) s = CHARNULL #endif X #ifdef vms # define getenv(s) getsymbol(s) # define envfree(s) (s) = ( !(s) ) ? CHARNULL : (free(s), CHARNULL) # include <descrip.h> # include <libdef.h> X # define MAXLEN 255 X X /*************************************************************************** X ** ^FUNCTION: get_symbol - retrieve the value of a VMS symbol X ** X ** ^SYNOPSIS: X */ # ifndef __ANSI_C__ X char *get_symbol( sym_name ) X /* X ** ^PARAMETERS: X */ X char *sym_name; X /* -- name of the symbol to retrieve X */ # endif /* !__ANSI_C__ */ X X /* ^DESCRIPTION: X ** Get_symbol will lookup the named symbol and return its value X ** as a string. X ** X ** ^REQUIREMENTS: X ** sym_name should correspond to the name of a pre-defined symbol. X ** X ** ^SIDE-EFECTS: X ** None. X ** X ** ^RETURN-VALUE: X ** NULL if the symbol is not found, otherwise it copies the symbol X ** value and returns the address of the copy (which may later be X ** deallocated using free()). X ** X ** ^ACKNOWLEDGEMENTS: X ** Thanx to Jim Barbour for writing most of this code. --BDA X ** X ** ^ALGORITHM: X ** Trivial - just use the LIB$GET_SYMBOL system service. X ***^^**********************************************************************/ # ifdef __ANSI_C__ X char *get_symbol( const char *sym_name ) # endif X { X unsigned long stat, lib$get_symbol(); X unsigned short buflen; X char sym_value[ MAXLEN ]; X $DESCRIPTOR( sym_name_d, sym_name ); X $DESCRIPTOR( sym_value_d, sym_value ); X X sym_value_d.dsc$w_length = MAXLEN; X sym_name_d.dsc$w_length = strlen( sym_name ); X stat = lib$get_symbol( &sym_name_d, &sym_value_d, &buflen, (void *)0 ); X if ( stat == LIB$_NOSUCHSYM ) { X return CHARNULL; X } X else if ( ! (stat & 1) ) { X exit(stat); X } X sym_value[ buflen ] = '\0'; X return strdup( sym_value ); X } #endif /* vms */ X X /*************************************************************************** ** ^FUNCTION: is_interactive - determine if a stream is "interactive" ** ** ^SYNOPSIS: */ #ifndef __ANSI_C__ X static BOOL is_interactive( fd ) /* ** ^PARAMETERS: */ X int fd; /* -- file descriptor associated with the input stream */ #endif /* !__ANSI_C__ */ X /* ^DESCRIPTION: ** Is_interactive determines whether or not the given i/o stream is ** associated with a terminal. ** ** ^REQUIREMENTS: ** Fd must correspond to a valid, open, file-descriptor. SHAR_EOF true || echo 'restore of parseargs/xparse.c failed' fi echo 'End of part 11' echo 'File parseargs/xparse.c is continued in part 12' echo 12 > _shar_seq_.tmp exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.