home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- ** ^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:
- ** 11/21/91 Brad Appleton <brad@ssd.csd.harris.com>
- ** - added Mike Levins fix to is_cmdline() to check for 0 length
- ** returned by lib$get_foreign.
- ** - added check of ps_NOTCMDLINE state-flag before calling is_cmdline()
- ** - fixed problem in vms_parse() where ARGVALGIVEN was getting set in
- ** place of ARGGIVEN.
- **
- ** 08/27/91 Earl Chew <cechew@bruce.cs.monash.edu.au>
- ** - Use ProgNameLen when accessing ProgName
- ** - Use get_argdesc() to access description
- **
- ** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com> Created
- ***^^**********************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
- #include <useful.h>
-
- #ifdef vms
- # include <descrip.h>
- #endif
-
- #include "strfuncs.h"
- #include "pgopen.h"
- #include "exit_codes.h"
-
- #define PARSEARGS_PRIVATE /* include private definitions */
- #include "parseargs.h"
-
- 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));
-
- VERSIONID("$Header: vms_args.c,v 1.1 90/08/23 18:00:00 brad Exp $");
-
- /***************************************************************************
- ** ^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;
-
-
- #define MAXCMDLINE 255
- #define VNULL (VOID *) 0
-
- #define TOGGLE(flag) flag = (flag) ? FALSE : TRUE
-
- /* define mappings */
- #define c_SPACE '\001' /* whitespace */
- #define c_QUAL '\002' /* qualifier-delimiter */
- #define c_EQUAL '\003' /* qualifier-argument separator */
- #define c_COLON '\004' /* qualifier-argument separator */
- #define c_PLUS '\005' /* list-item separator character */
- #define c_COMMA '\006' /* list-item separator character */
-
-
- typedef enum {
- Parameter, /* token is a parameter */
- Qualifier, /* token is a qualifier */
- EndOfLine /* NUL-token (signifies end of tokens) */
- } dcl_arg_t;
-
-
- typedef struct {
- dcl_arg_t type; /* token type */
- char *token; /* token value */
- } dcl_token_t;
-
-
-
- /***************************************************************************
- ** ^FUNCTION: is_cmdline - retrieve the original command-line
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static BOOL is_cmdline( argv, result )
- /*
- ** ^PARAMETERS:
- */
- char *argv[];
- /* -- array of strings
- */
- char **result;
- /* -- pointer to resultant command-line
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** *result is assigned to either the concatenated argv string or the
- ** original command-line. The result should 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__
- static BOOL is_cmdline( const char *argv[], char **result )
- #endif
- {
- register CONST char *avstr;
- #ifdef vms
- unsigned long int stat;
- unsigned short int len;
- register CONST char *aptr, *sptr;
- static char str[ MAXCMDLINE ];
- static BOOL got_cmd_line = FALSE;
- $DESCRIPTOR(str_d, str);
- #endif
-
- /* make a single string out of argv */
- avstr = strjoin( argv, " " );
-
- #ifndef vms
- *result = (char *)avstr;
- return FALSE;
-
- #else
- /* get the original command-line */
- if ( ! got_cmd_line ) {
- stat = lib$get_foreign( &str_d, VNULL, &len, VNULL );
- str[len] = '\0';
- got_cmd_line = TRUE;
- if (! (stat & 1)) exit( stat );
- }
-
- /* if we didnt have a command-line, dont bother comparing */
- if ( !*str ) {
- *result = (char *)avstr;
- return FALSE;
- }
-
- /* compare the two */
- for ( aptr = avstr, sptr = str ; *aptr && *sptr ; sptr++ ) {
- if ( toupper(*sptr) == toupper(*aptr) ) {
- ++aptr;
- }
- else if ( *sptr != '"' ) {
- *result = (char *)avstr;
- return FALSE;
- }
- }
-
- *result = strdup( str );
- free( avstr );
- return TRUE;
- #endif
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: dcl_strxlat - translate a string according to DCL syntax
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static char *dcl_strxlat( str )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to translate.
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** <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__
- static char *dcl_strxlat( char *str )
- #endif
- {
- register char c, *pread = str, *pwrite = str;
- BOOL quoted = FALSE;
-
- /*
- ** pass1 - scan forward, removing all whitespace after unquoted "/:=+,("
- */
- while ( c = *pwrite++ = *pread++ ) {
- if ( c == '"' ) TOGGLE(quoted);
- if ( !quoted && strchr("/:=+,(", c) )
- while( isspace(*pread) ) ++pread;
- }
- *--pwrite = '\0'; /* NUL terminate */
-
- /*
- ** pass2 - scan backward, removing all whitespace before unquoted "/:=+,)"
- */
- pread = --pwrite; /* set to last NON-NUL char */
- quoted = FALSE;
- while ( pread >= str ) {
- c = *pwrite-- = *pread--;
- if ( c == '"' ) TOGGLE(quoted);
- if ( !quoted && strchr("/:=+,)", c) )
- while( isspace(*pread) ) --pread;
- }
- strcpy(str, ++pwrite); /* reset BOS */
-
- /*
- ** pass3 - 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'
- */
- pread = pwrite = str;
- quoted = FALSE;
- while ( c = *pread++ ) {
- if ( c == '"' )
- TOGGLE(quoted);
- else if ( !quoted && isspace(c) ) {
- *pwrite++ = c_SPACE;
- while( isspace(*pread) ) ++pread;
- }
- else if ( !quoted && (c == '(' || c == ')') )
- continue;
- else if ( !quoted && c == '/' )
- *pwrite++ = c_QUAL;
- else if ( !quoted && c == ':' )
- *pwrite++ = c_COLON;
- else if ( !quoted && c == '=' )
- *pwrite++ = c_EQUAL;
- else if ( !quoted && c == '+' )
- *pwrite++ = c_PLUS;
- else if ( !quoted && c == ',' )
- *pwrite++ = c_COMMA;
- else
- *pwrite++ = c;
- }/*while*/
-
- *pwrite = '\0'; /* NUL-terminate */
- return str;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: dcl_split - split a string up into a vector of DCL tokens
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static dcl_token_t *dcl_split( str )
- /*
- ** ^PARAMETERS:
- */
- char *str;
- /* -- the string to split up into tokens
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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__
- static dcl_token_t *dcl_split( char *str )
- #endif
- {
- int tokc = 1; /* number of tokens */
- dcl_token_t *tokv = (dcl_token_t *)NULL; /* vector of tokens */
- register char *pread, c;
- register int i;
-
- if ( !str || !(*str) ) return (dcl_token_t *)NULL;
-
- /* 1st pass (left-to-right) : count tokens */
- pread = ( *str == c_QUAL ) ? (str + 1) : str;
- while ( c = *pread++ ) {
- if ( c == c_QUAL || c == c_SPACE ) ++tokc;
- if ( c == c_QUAL ) {
- /* replace "p1.1/qual,p1.2" with "p1.1/qual p1.2" */
- char *p, delims[5];
-
- sprintf( delims, "%c%c%c%c", c_EQUAL, c_PLUS, c_QUAL, c_SPACE );
- if ( (p = strpbrk((str + 1), delims)) &&
- ((*p == c_PLUS) || (*p == c_COMMA)) )
- *p == c_SPACE;
- }
- }
-
-
- /* allocate vector */
- tokv = (dcl_token_t *)malloc( (tokc + 1) * sizeof(dcl_token_t) );
- if ( tokv == (dcl_token_t *)NULL ) {
- syserr( "malloc() failed in dcl_split()" );
- }
- tokv[ tokc ].type = EndOfLine;
- tokv[ tokc ].token = CHARNULL;
-
- /* 2nd pass (right-to-left) : assign tokens to strings */
- for ( i = 1, --pread ; pread >= str ; pread-- ) {
- if ( *pread == c_SPACE || *pread == c_QUAL ) {
- tokv[ tokc - i ].token = pread + 1;
- tokv[ tokc - i ].type = ( *pread == c_QUAL ) ? Qualifier : Parameter;
- *pread = '\0';
- ++i;
- }
- }
-
- if ( *str ) { /* then 1st char could NOT have been '/' */
- tokv -> token = str;
- tokv -> type = Parameter;
- }
-
- return tokv;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: dcl_restore - restore the `escaped' characters in a token
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static char *dcl_restore( tokstr )
- /*
- ** ^PARAMETERS:
- */
- char *tokstr;
- /* -- the token string to restore
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- static char *dcl_restore( char *tokstr )
- #endif
- {
- register char *str = tokstr;
-
- if ( !str || !*str ) return str;
-
- for ( ; *str ; str++ ) {
- switch( *str ) {
- case c_SPACE : *str = ' '; break;
- case c_QUAL : *str = '/'; break;
- case c_EQUAL : *str = '='; break;
- case c_COLON : *str = ':'; break;
- case c_PLUS : *str = '+'; break;
- case c_COMMA : *str = ','; break;
- default : break;
- }
- }
-
- return tokstr;
- }
-
-
-
-
- /***************************************************************************
- ** ^FUNCTION: split_list - function to handle ARGLISTs and ARGVECs
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static BOOL split_list( ad, vp, cmd )
- /*
- ** ^PARAMETERS:
- */
- ARGDESC *ad;
- /* -- the argument which takes multiple values
- */
- char *vp;
- /* -- the string of values for the argument
- */
- ARGDESC *cmd;
- /* -- the command to which the argument belongs
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** 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__
- static BOOL split_list( ARGDESC *ad, char *vp, ARGDESC *cmd )
- #endif
- {
- char **arg_vec = (char **)NULL;
- int i, arg_num = 0;
- BOOL err = FALSE;
- char delims[3];
-
- /* set-up delimiter string */
- *delims = c_PLUS;
- *(delims + 1) = c_COMMA;
- *(delims + 2) = '\0';
-
- /* break string up into to tokens and handle each one */
- arg_num = strsplit( &arg_vec, vp, delims );
- for ( i = 0 ; i < arg_num ; i++ ) {
- vp = arg_vec[i];
-
- /* try to convert the type */
- if ( !HANDLE(ad, dcl_restore(vp), cmd_flags(cmd)) ) err = TRUE;
- }
- if ( !err ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
-
- if ( ARG_isPOSITIONAL(ad) ) {
- cmd_list(cmd) = ad;
- }
- else {
- cmd_list(cmd) = ARGDESCNULL;
- }
-
- free( arg_vec );
-
- return !err;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: vms_parse - parse VMS/DCL arg-vectors
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- int vms_parse( argv, argd )
- /*
- ** ^PARAMETERS:
- */
- char *argv[];
- /* -- the vector of string arguments from the command-line
- */
- ARGDESC argd[];
- /* -- the programmer description of the command and its args
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** 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__
- int vms_parse( char *argv[], ARGDESC argd[] )
- #endif
- {
- register ARGDESC *ad, *args, *cmd;
- register char *p;
- char *avstr;
- BOOL is_match = FALSE;
- int parse_error = pe_SUCCESS;
- dcl_token_t *tok, *tokvec;
- argName_t keyword;
- argMask_t saveflags, flags;
-
- if ( !argd ) return parse_error;
-
- /* initialize command-structure */
- if ( !CMD_isINIT(argd) ) init_args( argd );
- cmd = argd;
- saveflags = cmd_flags(cmd);
-
- if ( !argv || !*argv ) return parse_error;
-
- if ( !BTEST(cmd_state(cmd), ps_NOTCMDLINE) ) {
- (VOID) is_cmdline( (CONST char **)argv, &avstr );
- }
- else {
- avstr = strjoin( argv, " " );
- }
-
- BSET( cmd_flags(cmd), pa_COPYF );
- (VOID) dcl_strxlat( avstr );
- if ( !avstr || !*avstr ) return parse_error;
- tokvec = dcl_split( avstr );
-
- /* run through the token vector */
- for ( tok = tokvec ; (p = tok -> token) ; tok++ ) {
-
- if ( tok -> type == Qualifier && !BTEST(cmd_state(cmd), ps_NOFLAGS) ) {
- char c = '\0', *s, delims[3];
-
- /* set-up delimiter string */
- *delims = c_EQUAL;
- *(delims + 1) = c_COLON;
- *(delims + 2) = '\0';
-
- /* skip past qualifier prefix and look for possible argument */
- s = strpbrk(p, delims);
- if (s) {
- c = *s;
- *s++ = '\0';
- }
-
- is_match = FALSE;
- for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) {
- for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
- if (arg_type(ad) == argDummy) continue;
-
- if (!ARG_isPOSONLY(ad) && match(p, arg_sname(ad)) == 0) {
- is_match = TRUE;
- break;
- }/*if*/
- }
- }
-
- if (c) *(s-1) = c; /* restore the equal sign */
-
- if ( !is_match ) {
- if (s) *(s-1) = '\0';
- usrerr( "undefined qualifier %s", s_KWD_PFX, p );
- if (s) *(s-1) = c;
- parse_error = pe_SYNTAX;
- continue;
- }
-
- /* end-qualifiers */
- if ( arg_type(ad) == argEnd ) {
- BSET( cmd_state(cmd), ps_NOFLAGS );
- continue;
- }
- /* if usage - just print usage and exit */
- if ( arg_type(ad) == argUsage ) {
- Usage_Requested = TRUE;
- usage( argd );
- free( avstr );
- if ( tokvec ) free( tokvec );
- cmd_flags(cmd) = saveflags;
- exit(exit_USAGE);
- }
- /* reset the argument flags - if this arg was already given, some
- ** of its flags may be set to indicate how it was given before.
- ** we need to know how it was given now (but save the old ones
- ** just in case the new one fails).
- */
- flags = arg_flags(ad);
- if ( ARG_isGIVEN(ad) ) {
- BCLEAR( arg_flags(ad), ARGVALSEP );
- if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- }
-
- /* ARGNOVALs are special, having no value */
- if ( ! ARG_isVALTAKEN(ad) ) {
- if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
- else {
- BSET( arg_flags(ad), ARGGIVEN );
- ad = ARGDESCNULL;
- }
- continue;
- }/*if ARGNOVAL*/
-
- /* now get the real value */
- if ( !s || !(*s) ) {
- if ( ARG_isVALOPTIONAL(ad) ) {
- BSET( arg_flags(ad), ARGGIVEN );
- }
- else {
- (VOID) get_kwdname( arg_sname(ad), keyword );
- usrerr("qualifier %s requires an argument", keyword);
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
- continue;
- }/*if*/
-
- if( ARG_isMULTIVAL(ad) ) {
- if( !split_list(ad, s, cmd) ) {
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
- else {
- BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- }
- continue;
- }/*if list*/
-
- /* try to convert the type */
- if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
- else {
- BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- }
-
- continue;
- }/*if qual*/
- else {
- /* parsing a vector of arguments */
- if ( cmd_list(cmd) ) {
- ad = cmd_list(cmd);
- flags = arg_flags(ad);
- if ( ARG_isGIVEN(ad) ) {
- BCLEAR( arg_flags(ad), ARGVALSEP );
- }
-
- BSET( arg_flags(ad), ARGVALSEP );
-
- if( ARG_isMULTIVAL(ad) ) {
- if( !split_list(ad, p, cmd) ) parse_error = pe_SYNTAX;
- }
- else if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
-
- if ( !parse_error ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
-
- continue;
- }
- /* positional argument */
- is_match = FALSE;
- for ( args = argd ; args && !is_match ; args = cmd_defargs(args) ) {
- for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
- if (arg_type(ad) == argDummy) continue;
-
- if ( ARG_isPOSITIONAL(ad) &&
- (!ARG_isGIVEN(ad) || ARG_isMULTIVAL(ad)) ) {
- is_match = TRUE;
- break;
- }/*if*/
- }
- }
-
- if ( !is_match ) {
- usrerr("too many arguments");
- parse_error = pe_SYNTAX;
- continue;
- }
-
- /* if FLAGS1ST is set then first positional marks end-of-flags */
- if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
- BSET( cmd_state(cmd), ps_NOFLAGS );
- }
-
- /* reset the argument flags - if this arg was already given, some
- ** of its flags may be set to indicate how it was given before.
- ** we need to know how it was given now (but save the old ones
- ** just in case the new one fails).
- */
- flags = arg_flags(ad);
- if ( ARG_isGIVEN(ad) ) {
- BCLEAR( arg_flags(ad), ARGVALSEP );
- if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- }
-
- BSET( arg_flags(ad), ARGVALSEP );
-
- if( ARG_isMULTIVAL(ad) ) {
- if( !split_list(ad, p, cmd) ) {
- arg_flags(ad) = flags;
- parse_error = pe_SYNTAX;
- }
- else {
- BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- }
- continue;
- }/*if list*/
-
- /* try to convert */
- if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
- arg_flags(ad) = flags;
- parse_error = TRUE;
- }
- else {
- BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- }
-
- }/*if parameter*/
- }/*while*/
-
- free( avstr );
- if ( tokvec ) free( tokvec );
- cmd_flags(cmd) = saveflags;
- return parse_error;
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: fmtarg - format command-argument syntax
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- static int fmtarg( ad, buf )
- /*
- ** ^PARAMETERS:
- */
- ARGDESC *ad;
- /* -- pointer to the argument to format
- */
- char *buf;
- /* -- character buffer to hold the formatted result
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** 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__
- static int fmtarg( const ARGDESC *ad, char *buf )
- #endif
- {
- /* buf must already be large enough */
- char * pos;
- argName_t keyword, name;
-
- (VOID) get_argname( arg_sname(ad), name );
-
- if (ARG_isPOSITIONAL(ad)) {
- sprintf( buf, "<%s>", name );
- }
- else {
- (VOID) get_kwdname( arg_sname(ad), keyword );
- sprintf( buf, "%c%s", *s_KWD_PFX, keyword );
- pos = buf + strlen(buf);
-
- if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
- if ( ARG_isVALOPTIONAL(ad)) {
- sprintf( pos, "[%c<%s>]", *s_ARG_SEP, name );
- }
- else {
- sprintf( pos, "%c<%s>", *s_ARG_SEP, name );
- }
- }/*if*/
- }/*else*/
-
- return (int) strlen(buf);
- }
-
-
- /***************************************************************************
- ** ^FUNCTION: vms_usage - print a usage message
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- VOID vms_usage( argd, usage_flags )
- /*
- ** ^PARAMETERS:
- */
- ARGDESC *argd;
- /* -- the command-descriptor array
- */
- argMask_t usage_flags;
- /* -- flags set by $USAGECNTL
- */
- #endif /* !__ANSI_C__ */
-
- /* ^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-EFFECTS:
- ** 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__
- void vms_usage( const ARGDESC *argd, argMask_t usage_flags )
- #endif
- {
- register CONST ARGDESC *ad, *args, *cmd;
- int max_cols = 80, max_lines = 24;
- int margin, ll, pl, qualifiers, longest, positionals;
- BOOL first = TRUE;
- FILE *fp;
-
- if ( !argd ) return;
-
- /* initialize command-structure */
- if ( !CMD_isINIT(argd) ) init_args( (ARGDESC *)argd );
- cmd = argd;
-
- /* get screen size */
- get_winsize( fileno(stderr), &max_lines, &max_cols );
-
- /* force verbose-mode if requested */
- if ( Usage_Requested ) BSET( usage_flags, usg_VERBOSE );
-
- if ( BTEST(usage_flags, usg_NONE) ) return;
-
- fp = ( BTEST(usage_flags, usg_PAGED) )
- ? pgopen( stderr, getenv("USAGE_PAGER") )
- : stderr;
-
- /* allow null argument descriptor */
- fprintf(fp, "Format: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
-
- ll = ProgNameLen + 8;
- margin = ll + 1;
- longest = 0;
-
- for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
- for ( args = argd ; args ; args = cmd_defargs(args) ) {
- for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
- argName_t buf, name;
-
- /* don't display hidden arguments */
- if ( ARG_isHIDDEN(ad) ) continue;
- if ( !positionals && ARG_isPOSITIONAL(ad) ) continue;
- if ( positionals && !ARG_isPOSITIONAL(ad) ) continue;
-
- /* figure out how wide this parameter is (for printing) */
- pl = fmtarg(ad, buf);
-
- if ( pl > longest ) longest = pl;
-
-
- if ( ARG_isMULTIVAL(ad) ) {
- (VOID) get_argname( arg_sname(ad), name );
- strcat(buf, "[,<");
- strcat(buf, name);
- strcat(buf, ">...]");
- pl += 8 + strlen(name);
- }
- if ( !ARG_isREQUIRED(ad) ) {
- pl += 2; /* [] */
- }
-
- /* see if this will fit */
- if ( (ll + pl + 1) > (max_cols - first) ) {
- /* no... start a new line */
- fprintf(fp, "\n%*s", margin, "");
- ll = margin;
- }
- else {
- /* yes... just throw in a space */
- fputc(' ', fp);
- ++ll;
- }
- ll += pl;
-
- /* show the argument */
- if ( !ARG_isREQUIRED(ad) ) fputc('[', fp);
- fprintf(fp, buf);
- if ( !ARG_isREQUIRED(ad) ) fputc(']', fp);
-
- first = FALSE; /* not first line anymore */
- }/*for each ad */
- }/* for each argd */
- }/* for each parm-type */
-
- fputc('\n', fp);
-
- if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
- CONST char *description = cmd_description(cmd);
-
- if ( description && *description ) {
- fprintf( fp, "Description:\n" );
- indent_para(fp, max_cols, 8, "", 0, description, 0);
- fputc( '\n', fp );
- }
- }/*if*/
-
- if ( !BTEST(usage_flags, usg_VERBOSE) ) {
- if ( pgactive(fp) ) (VOID) pgclose( fp );
- return;
- }
-
- qualifiers = 0;
- for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
- for ( args = argd ; args ; args = cmd_defargs(args) ) {
- for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
- argName_t buf;
- char *desc;
- int desclen;
-
- /* don't display hidden arguments */
- if ( ARG_isHIDDEN(ad) ) continue;
- if ( !positionals && ARG_isPOSITIONAL(ad) ) continue;
- if ( positionals && !ARG_isPOSITIONAL(ad) ) continue;
-
- if ( !qualifiers++ ) fprintf(fp, "Qualifiers/Parameters:\n");
- (VOID) fmtarg(ad, buf);
- desc = get_argdesc(arg_description(ad), &desclen);
- indent_para(fp, max_cols, 8, buf, longest+2, desc, desclen );
- }/*for each ad */
- }/* for each argd */
- }/* for each parm-type */
-
- if ( pgactive(fp) ) (VOID) pgclose( fp );
- }
-
-