home *** CD-ROM | disk | FTP | other *** search
- From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
- Newsgroups: comp.sources.misc
- Subject: v17i050: parseargs - functions to parse command line arguments, Part05/12
- Message-ID: <1991Mar17.200712.17928@sparky.IMD.Sterling.COM>
- Date: 17 Mar 91 20:07:12 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: 05f305bf 9dbcc514 b4c32c2f 672882ff
-
- Submitted-by: Brad Appleton <brad@hcx1.ssd.csd.harris.com>
- Posting-number: Volume 17, Issue 50
- Archive-name: parseargs/part05
-
- This is part 5 of parseargs
-
- #!/bin/sh
- # this is Part.05 (part 5 of a multipart archive)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file parseargs/ibm_args.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 5; 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/ibm_args.c'
- else
- echo 'x - continuing file parseargs/ibm_args.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/ibm_args.c' &&
- ** an option switch on the command-line.
- **
- ** KwdPrefix contains the single character prefix used to precede
- ** a keyword switch on the command-line.
- ***^^**********************************************************************/
- static char OptPrefix='/';
- static char KwdPrefix='/';
- X
- #define isUNIXISH ( OptPrefix == '-' )
- X
- 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
- X /* macros to detect an option/keyword -- watch out for side effects!! */
- #define isOPT(s) \
- X ( !BTEST(cmd_flags(cmd), pa_KWDSONLY) && \
- X !BTEST(cmd_state(cmd), ps_NOFLAGS) && \
- X *s == OptPrefix && *(s+1) \
- X )
- X
- #define isKWD(s) \
- X ( !BTEST(cmd_flags(cmd), pa_OPTSONLY) && \
- X !BTEST(cmd_state(cmd), ps_NOFLAGS) && \
- X *s == KwdPrefix && *(s+1) \
- X )
- X
- X
- /***************************************************************************
- ** ^FUNCTION: get_prefixes - determine short and long keyword prefixes
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static VOID get_prefixes()
- #endif
- /*
- ** ^PARAMETERS:
- ** None.
- **
- ** ^DESCRIPTION:
- ** Get_prefixes will determine the prefixes to used to denote option
- ** switches and keyword switches on the command-line. The prefixes
- ** are determined by the $SWITCHAR environment varaible. The first
- ** character of the variable is the option-switch prefix and the second
- ** character is the keyword-switch prefix.
- **
- ** If The option-switch prefix is '-' then Unix-style command-line parsing
- ** is performed, otherwise MS-DOS style command-line parsing is used.
- **
- ** ^REQUIREMENTS:
- ** None.
- **
- ** ^SIDE-EFECTS:
- ** Sets the global variables "OptPrefix" and "KwdPrefix'.
- **
- ** ^RETURN-VALUE:
- ** None.
- **
- ** ^ALGORITHM:
- ** - If $SWITCHAR is NULL or empty
- ** - use the defaults ('/' and '/').
- ** - Else
- ** - set the OptPrefix to the first character in SWITCHAR
- ** End-if
- **
- ** - If there is a second character in SWITCHAR
- ** - assign it to KwdPrefix
- ** - Else if OptPrefix is '-'
- ** - then use '+' as the default KwdPrefix
- ** - Else
- ** - use '/' as the default KwdPrefix
- ** End-if
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static VOID get_prefixes( void )
- #endif
- {
- X char *prefixes = getenv( "SWITCHAR" );
- X
- X if ( prefixes && *prefixes ) {
- X OptPrefix = *prefixes;
- X KwdPrefix = *(prefixes + 1);
- X if ( !KwdPrefix ) KwdPrefix = (( OptPrefix == '-' ) ? '+' : '/');
- X }
- X else {
- X OptPrefix = '/';
- X KwdPrefix = '/';
- X }
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: ibm_parse - parse MS-DOS and OS/2 arg-vectors
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X int ibm_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:
- ** Ibm_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:
- ** - get the active option and keyword prefixes
- ** - determine whether to use Unix style or not (based on the prefixes)
- ** - for each command-line argument
- ** - attempt to match the argument as a keyword
- ** - if it is a keyword argument
- ** - record and convert its value (if any)
- ** else attempt to match the argument as an option
- ** if it is an option
- ** - 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 ibm_parse( char *argv[], ARGDESC argd[] )
- #endif
- {
- X register ARGDESC *ad, *args, *cmd;
- X register char **av = argv;
- X register char *p;
- X argName_t name;
- X argMask_t flags;
- X int parse_error = pe_SUCCESS;
- X BOOL ad_okay, is_match = FALSE;
- X
- X if ( !argd ) return parse_error;
- X
- X /* initialize command-structure */
- X if ( !CMD_isINIT(argd) ) init_args( argd );
- X cmd = argd;
- X
- X get_prefixes();
- X
- X while ( av && (p = *av++) ) {
- X if ( isKWD(p) &&
- X ( (OptPrefix != KwdPrefix) || *(p+2) && !strchr(s_ARG_SEP, *(p+2)) )
- X ) {
- X char *s, c = '\0';
- X
- X /* check for `++' to end flags */
- X if ( *(p+1) == KwdPrefix && !*(p+2) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X /* get past prefix and look for possible argument */
- X s = strpbrk(++p, s_ARG_SEP);
- 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 if ( OptPrefix == KwdPrefix ) {
- X goto MATCHOPT; /* maybe its an option (and NOT a keyword) */
- X }
- X usrerr("%c%s switch unknown", KwdPrefix, p);
- X parse_error = pe_SYNTAX;
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) )
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
- X
- X BSET( arg_flags(ad), ARGKEYWORD );
- X
- X if( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad;
- X }
- X else {
- X cmd_list(cmd) = ARGDESCNULL;
- X }
- X
- X /* if usage - just print usage and exit */
- X if ( arg_type(ad) == argUsage ) {
- X Usage_Requested = TRUE;
- X usage(argd);
- X exit(1);
- X }
- X
- X /* ARGNOVALs are special, having no value */
- X if ( ! ARG_isVALTAKEN(ad) ) {
- X ad_okay = HANDLE(ad, s, cmd_flags(cmd));
- X if ( !ad_okay ) {
- 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) {
- X if ( isUNIXISH ) s = *av++;
- X if ( !isUNIXISH || !s || isOPT(s) || isKWD(s) ) {
- X if ( ARG_isVALOPTIONAL(ad) ) {
- X BSET( arg_flags(ad), ARGGIVEN );
- X }
- X else {
- X (VOID) get_keyword( arg_sname(ad), name );
- X usrerr("%c%s switch requires an argument", KwdPrefix, name);
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X
- X if ( isUNIXISH ) av--;
- X continue;
- X }/*if arg*/
- X if ( isUNIXISH ) BSET( arg_flags(ad), ARGVALSEP );
- X }/*if empty*/
- X
- X /* try to convert the type */
- X ad_okay = HANDLE(ad, s, cmd_flags(cmd));
- X if ( !ad_okay ) {
- 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 keyword*/
- X else if ( isOPT(p) ) {
- X p++; /* skip over option prefix */
- X
- MATCHOPT:
- X /* check for `--' to end flags */
- X if ( *p == OptPrefix && !*(p+1) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X /* flag argument */
- X while (*p) {
- X
- X /* find the flag in the list */
- 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 register char c1 = arg_cname(ad);
- X register char c2 = *p;
- X
- X if ( arg_type(ad) == argDummy ) continue;
- X if ( ARG_isPOSONLY(ad) ) continue;
- X
- X if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
- X c1 = TOUPPER( c1 );
- X c2 = TOUPPER( c2 );
- X }/*if*/
- X
- X if ( c1 == c2 ) {
- X is_match = TRUE;
- X break;
- X }/*if*/
- X }
- X }
- X if ( !is_match ) {
- X usrerr("%c%c switch unknown", OptPrefix, *p++);
- X parse_error = pe_SYNTAX;
- X cmd_list(cmd) = ARGDESCNULL;
- X if ( !isUNIXISH && *p == *s_ARG_SEP ) p += strlen(p);
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X continue;
- X }/* if unknown-option */
- X
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) )
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad;
- X }
- X else {
- X cmd_list(cmd) = ARGDESCNULL;
- X }
- X
- X /* move p up to point to the (possible) value */
- X p++;
- X if ( !isUNIXISH && *p && strchr(s_ARG_SEP, *p) ) ++p;
- X
- X /* if usage - just print usage and exit */
- X if (arg_type(ad) == argUsage) {
- X Usage_Requested = TRUE;
- X usage(argd);
- X exit(1);
- X }
- X
- X /* ARGNOVALs are special, having no value */
- X if (! ARG_isVALTAKEN(ad)) {
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }/*if*/
- X else {
- X BSET( arg_flags(ad), ARGGIVEN );
- X ad = ARGDESCNULL;
- X if ( ad_okay < 0 ) p -= ad_okay;
- X }/*else*/
- X
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X continue;
- X }/*if*/
- X
- X /* now get the real value */
- X if ( !(*p) ) {
- X if ( isUNIXISH ) p = *av++;
- X if ( !isUNIXISH || !p || isOPT(p) || isKWD(p) ) {
- X if ( ARG_isVALOPTIONAL(ad) ) {
- X BSET( arg_flags(ad), ARGGIVEN );
- X }
- X else {
- X (VOID) get_name(arg_sname(ad), name);
- X usrerr( "%s required for %c%c flag",
- X name, OptPrefix, arg_cname(ad) );
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }/*else*/
- X
- X if ( isUNIXISH ) av--;
- X break;
- X }/*if arg*/
- X if ( isUNIXISH ) BSET( arg_flags(ad), ARGVALSEP );
- X }/*if empty*/
- X
- X /* try to convert the type */
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X p += strlen(p);
- X }/*if*/
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X if ( isUNIXISH && ad_okay < 0 && !ARG_isVALSEPARATE(ad) ) {
- X p -= ad_okay;
- X }
- X else {
- X p += strlen(p);
- X }
- X }/*else*/
- X
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X }/*while*/
- X }/*elif option*/
- X else {
- X /* parsing a list 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), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- 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 any arguments");
- X parse_error = pe_SYNTAX;
- X continue;
- X }
- X
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) )
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGVALGIVEN | ARGKEYWORD );
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad;
- X }
- X
- X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X }
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X /* try to convert */
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X }/*else*/
- X }/*while*/
- X
- X return parse_error;
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: fmtarg - format command-argument syntax
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static int fmtarg( ad, buf, usgflags )
- /*
- ** ^PARAMETERS:
- */
- X ARGDESC *ad;
- /* -- pointer to the argument to format
- */
- X char *buf;
- /* -- character buffer to hold the formatted result
- */
- X argMask_t usgflags;
- /* -- set of bitmasks corresponding to the value of the user's USAGECNTL
- ** environment variable
- */
- #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.
- **
- ** Any syntax biases reflected in usgflags will be used.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static int fmtarg( const ARGDESC *ad, char *buf, argMask_t usgflags )
- #endif
- {
- X /* buf must already be large enough */
- X char *pos;
- X argName_t name, keyword;
- 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
- X if ( isupper(arg_cname(ad)) && toupper(*keyword) == arg_cname(ad) ) {
- X *keyword = toupper(*keyword);
- X }
- X
- X if ( !(usgflags & usg_LONGOPTS) ) {
- X sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
- X }
- X else if ( !(usgflags & usg_OPTS) ) {
- X sprintf( buf, "%c%s", KwdPrefix, keyword );
- X }
- X else { /* use both */
- X if ( OptPrefix == KwdPrefix && *keyword == arg_cname(ad) ) {
- X if ( !*(keyword+1) )
- X sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
- X else
- X sprintf( buf, "%c%c[%s]", OptPrefix, arg_cname(ad), keyword+1 );
- X }
- X else {
- X sprintf( buf, "%c%c|%c%s", OptPrefix, arg_cname(ad),
- X KwdPrefix, keyword );
- X }
- X }
- X
- X pos = buf + strlen(buf);
- X
- X if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
- X if ( isUNIXISH ) *(pos++) = ' ';
- X if ( ARG_isVALOPTIONAL(ad) ) *(pos++) = '[';
- X if ( !isUNIXISH ) *(pos++) = *s_ARG_SEP;
- X sprintf( pos, "<%s>", name );
- X if ( ARG_isVALOPTIONAL(ad) ) strcat(pos, "]");
- X }/*if*/
- X }/*else*/
- X
- X return strlen(buf);
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: ibm_usage - print a usage message
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X VOID ibm_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:
- ** Ibm_usage will print the Unix 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 variable.
- **
- ** ^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 ibm_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 ll, margin, options, 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 /* 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 /* get screen size */
- X get_winsize( fileno(fp), &max_lines, &max_cols );
- X
- X fprintf(fp, "Usage: %s", ProgName);
- X
- X ll = strlen( ProgName ) + 7;
- X margin = ll + 1;
- X longest = 0;
- X
- X /* print Synopsis */
- 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 int pl;
- 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, usage_flags);
- X
- X if ( pl > longest) longest = pl;
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X strcat( buf, "..." );
- X pl += 3;
- 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 options = 0;
- X
- X /* print Argument descriptions */
- 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 ( !options++ ) fprintf(fp, "Options/Arguments:\n");
- X fmtarg(ad, buf, usage_flags);
- 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
- echo 'File parseargs/ibm_args.c is complete' &&
- chmod 0664 parseargs/ibm_args.c ||
- echo 'restore of parseargs/ibm_args.c failed'
- Wc_c="`wc -c < 'parseargs/ibm_args.c'`"
- test 23858 -eq "$Wc_c" ||
- echo 'parseargs/ibm_args.c: original size 23858, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= parseargs/parseargs.awk ==============
- if test -f 'parseargs/parseargs.awk' -a X"$1" != X"-c"; then
- echo 'x - skipping parseargs/parseargs.awk (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting parseargs/parseargs.awk (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'parseargs/parseargs.awk' &&
- #!/usr/bin/awk -f
- X
- ##########################################################################
- ## ^FILE: parseargs.awk - parseargs for awk programs
- ##
- ## ^DESCRIPTION:
- ## This file defines an awk function named parseargs to parse
- ## command-line arguments for awk scripts. It also contains a
- ## bare-bones template of what such an awk-script might contain.
- ##
- ## ^HISTORY:
- ## 02/21/91 Brad Appleton <brad@ssd.csd.harris.com> Created
- ###^^#####################################################################
- X
- X
- #########
- ## ^FUNCTION: parseargs - parse command-line argument vectors
- ##
- ## ^SYNOPSIS:
- ## parseargs( argc, argv, argd, arr )
- ##
- ## ^PARAMETERS:
- ## argc -- the number of elements in argv (usually ARGC-1).
- ## argv -- the vector of command-line arguments (usually ARGV).
- ## argd -- the argument-description string
- ## arr -- the associative array to assign command-line values from
- ##
- ## ^DESCRIPTION:
- ## Parseargs will invoke parseargs(1) to parse the command-line given
- ## in <argv> for the command defined by <argd>. The resulting values
- ## will be assigned to elements of the associative array given by <arr>.
- ## Values are assigned using using the syntax: arr [ "argname" ] = value;
- ## The exception to this is that if the <argname> is "ARGV" then the global
- ## array ARGV is reset to the given array (using tab separated fields).
- ##
- ## ^REQUIREMENTS:
- ## Any desired initial values for items in <arr> should be assigned BEFORE
- ## calling this function (using the syntax: arr[ "argname" ] = initial-val).
- ##
- ## The following global variables may be assigned before calling parseargs:
- ##
- ## PROGNAME -- name of the current awk script (default= ARGV[0])
- ## PARSEOPTS -- any extra options to pass toi parseargs() (default="-ul")
- ## PARSEINPUT -- input file for parseargs(1) (default=unique-name)
- ## PARSEOUTPUT -- output file for parseargs(1) (default=unique-name)
- ##
- ## ^SIDE-EFFECTS:
- ## The files PARSEINPUT and PARSEOUTPUT are created and then deleted.
- ##
- ## The return value from parseargs(1) will be stored in the global-variable
- ## named PARSESTATUS.
- ##
- ## The global variable PARSEARGS will contain the command-line used to
- ## invoke parseargs(1).
- ##
- ## ARGV and ARGC may be reset, all other values are (re)set in <arr>.
- ##
- ## ^RETURN-VALUE:
- ## The exit code returned by parseargs(1).
- ##
- ## ^BUGS:
- ## Due to the limited ability of awk, scripts using parseargs(1) cannot
- ## use short-options (with a dash '-') because awk will attempt to interpret
- ## any such arguments as options to awk and remove them from ARGV (regardless
- ## of whether or not they are valid awk-options). Keyword options (with a
- ## plus sign '+') may still be used without this difficulty. Dash-options
- ## may be successfully processed if they did not first appear on the command
- ## to the awk-script, so the full syntax of unix-style options could be
- ## provided in an array other than ARGV.
- ##
- ## ^ALGORITHM:
- ## - set defaults for PROGNAME, PARSEOPTS, PARSEINPUT, and PARSEOUTPUT.
- ## - build the parseargs command (dont forget to quote arguments).
- ## - redirect input and output of the parseargs command.
- ## - run parseargs(1)
- ## - assign the exit-code from parseargs(1) to PARSESTATUS
- ## - remove PARSEINPUT
- ## - if PARSESTATUS != 0
- ## - save RS and FS and reset RS = "" and FS = "\n"
- ## - for each record in PARSEOUTPUT
- ## - $1 is the argname and $2 is the value
- ## - if $1 is "ARGV" reset ARGV and ARGC ($2 is a tab separated array)
- ## - else assign arr[ $1 ] = $2
- ## end-for
- ## - restore RS and FS to previous values
- ## - remove PARSEOUTPUT
- ## - return PARSESTATUS
- ###^^####
- X
- function parseargs(argc, argv, argd, arr) {
- X ## set defaults -- use $$ to get a unique suffix string
- X if ( ! PROGNAME ) PROGNAME = ARGV[0];
- X if ( ! PARSEOPTS ) PARSEOPTS = "-u -l";
- X
- X "echo ${TMP:-/tmp}/parseargs.${$}_" | getline TMPFILE;
- X if ( ! PARSEINPUT ) PARSEINPUT = TMPFILE "in";
- X if ( ! PARSEOUTPUT ) PARSEOUTPUT = TMPFILE "out";
- X
- X ## build the options and required arguments for parseargs(1)
- X PARSEARGS = sprintf( "parseargs -s awk %s -- '%s'", PARSEOPTS, PROGNAME );
- X
- X ## quote each elemnt in argv and append it to the parseargs-command
- X for ( i = 1 ; i <= argc ; i++ ) {
- X arg = argv[i];
- X gsub( /'/, "'\\''", arg );
- X PARSEARGS = PARSEARGS " '" arg "'";
- X }
- X
- X ## set up i/o redirection
- X PARSEARGS = PARSEARGS " <" PARSEINPUT " >" PARSEOUTPUT;
- X print argd > PARSEINPUT;
- X
- X ## invoke parseargs(1) and save the status
- X PARSESTATUS = system( PARSEARGS );
- X system( "/bin/rm -f " PARSEINPUT ); ## dont need input anymore
- X
- X ## if successful status, read the result
- X if ( PARSESTATUS == 0 ) {
- X save_RS = RS; save_FS = FS;
- X RS = ""; FS = "\n";
- X while ( getline < PARSEOUTPUT > 0 ) {
- X gsub( /\034/, "\n" );
- X if ( $1 == "ARGV" ) {
- X ARGC = 1 + split( $2, ARGV, "\t" );
- X ARGV[0] = PROGNAME;
- X }
- X else arr[ $1 ] = $2;
- X }
- X RS = save_RS; FS = save_FS;
- X }
- X system( "/bin/rm -f " PARSEOUTPUT );
- X
- X return PARSESTATUS;
- }
- X
- X
- BEGIN {
- X PROGNAME = "test.awk";
- X ARGD = sprintf( "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
- X "'?', ARGHIDDEN, argUsage, NULL, 'Help : print usage and exit'" ,
- X "'S', ARGVALOPT, argStr, string, 'STRing : optional string arg'" ,
- X "'g', ARGLIST, argStr, groups, 'newsGROUPS : groups to test'" ,
- X "'r', ARGOPT, argInt, count, 'REPcount : group repeat count'" ,
- X "'d', ARGOPT, argStr, dirname, 'DIRectory : working directory'" ,
- X "'x', ARGOPT, argBool, xflag, 'Xflag : turn on X-mode'" ,
- X "'y', ARGOPT, argUBool, yflag, 'Yflag : turn off Y-mode'" ,
- X "'s', ARGOPT, argChar, sepch, 'SEPchar : field separator'" ,
- X "'f', ARGLIST, argStr, files, 'files : files to process'" ,
- X "' ', ARGREQ, argStr, name, 'name : name to use'" ,
- X "' ', ARGLIST, argStr, argv, 'argv : any remaining arguments'" ,
- X "ENDOFARGS" );
- X
- X Args[ "count" ] = 1;
- X Args[ "dirname" ] = ".";
- X Args[ "sepch" ] = ",";
- X Args[ "yflag" ] = "TRUE";
- X
- X rc = parseargs( ARGC-1, ARGV, ARGD, Args );
- X if ( rc != 0 ) exit( rc );
- X
- X ## print the parsed arguments (use defaults if not defined)
- X print "ARGUMENTS:";
- X print "==========";
- X
- X for ( i in Args )
- X printf( "Args[\"%s\"] = \"%s\"\n", i, Args[i] );
- X
- X argc = split( Args[ "argv" ], argv, "\t" );
- X for ( i = 1 ; i <= argc ; i++ )
- X printf( "argv[%d] = \"%s\"\n", i, argv[i] );
- X
- }
- SHAR_EOF
- chmod 0664 parseargs/parseargs.awk ||
- echo 'restore of parseargs/parseargs.awk failed'
- Wc_c="`wc -c < 'parseargs/parseargs.awk'`"
- test 6648 -eq "$Wc_c" ||
- echo 'parseargs/parseargs.awk: original size 6648, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= parseargs/parseargs.c ==============
- if test -f 'parseargs/parseargs.c' -a X"$1" != X"-c"; then
- echo 'x - skipping parseargs/parseargs.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting parseargs/parseargs.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'parseargs/parseargs.c' &&
- /*************************************************************************
- ** ^FILE: parseargs.c - command line interface to parseargs()
- **
- ** ^DESCRIPTION:
- ** This file implements the command-line interface to the parseargs
- ** library. Under Unix, the user may use parseargs(1) (this program)
- ** to parse command-line arguments for shell scripts. At the present,
- ** time, VMS/DCL is not yet supported (nor are MS-DOS Batch-files).
- **
- ** Given a command name, a vector of string-valued arguments such as that
- ** passed to a shell script, and a specification string describing the
- ** possible arguments, parseargs matches actual arguments to possible
- ** arguments, converts values to the desired type, and diagnoses problems
- ** such as missing arguments, extra arguments, and argument values that
- ** are syntactically incorrect. Other behavior such as prompting the
- ** user for missing arguments and ignoring as command-line syntax may be
- ** specified on the command-line through the use of various options, or
- ** through the use of the "PARSECNTL" environment variable.
- **
- ** Given the command name and the argument specification string,
- ** parsearg -U
- ** prints a reasonably friendly version of the usage of the
- ** calling program on standard diagnostic output. The "verbosity" of
- ** the usage message may be controlled through the use of the
- ** "USAGECNTL" environment variable.
- **
- ** Given the command name and the argument specification string,
- ** parsearg -M
- ** prints a template of the command-syntax on standard output that is
- ** suitable for input to nroff or troff using the -man macro package.
- **
- ** ^SEE_ALSO:
- ** argtype(3), parseargs(1), parseargs(3), parsecntl(3),
- ** parseargs.pl, parseargs.awk
- ** test.sh, test.csh, test.ksh, test.rc, test.awk, test.pl
- **
- ** ^BUGS:
- ** It does not make sense to use any arguments of type argTBool since
- ** parseargs currently has no way of knowing what the initial value of
- ** the variable is. For this reason, argTBool is not recognized as a
- ** valid argument type (even though it is used by parseargs(3)). By the
- ** same token, since the user cannot create their own arguments types on
- ** the fly from a shell-script, ARGNOVAL is not recognized as a valid
- ** argument flag.
- **
- ** Commas will not be interpreted properly if any field in the argument
- ** specification string contains double quotes that are nested inside of
- ** double quotes, or single quotes that are nested inside of single quotes.
- **
- ** Inside the argument specification string, any repeated string of
- ** commas that does not appear inside of double or single quotes will
- ** be treated as a single comma.
- **
- ** Text descriptions for argument entries are automatically formatted in
- ** usage messages. Any attempt by the user to include tabs and/or newlines
- ** in the description will cause it to be formatted improperly.
- **
- ** Parseargs cannot properly preserve any newlines in shell variables if
- ** the eval command is used to read its output (this is a shortcoming of
- ** the eval command, not of parseargs). If the user is concerned about
- ** this particular case, then the user should redirect the output from
- ** parseargs to a temporary file and use the source command in csh or the
- ** dot command (`.') in sh and ksh, to interpret the results; otherwise,
- ** newlines will be translated into spaces, or characters following a
- ** newline may be lost, in any variables that are set by parseargs.
- **
- ** Parseargs(1) is subject to the same caveats as parseargs(3).
- ** Refer to the CAVEATS section of the parseargs(3) for more information.
- **
- ** ^HISTORY:
- ** 07/18/90 Brad Appleton <brad@ssd.csd.harris.com> Created
- ***^^**********************************************************************/
- X
- #include <fcntl.h>
- #include <stdio.h>
- #include <useful.h>
- #include "strfuncs.h"
- X
- #define PARSEARGS_PRIVATE /* include private definitions */
- #include "parseargs.h"
- X
- /*************************************************************************
- ** ^SECTION: RETURN-CODES
- **
- ** Parseargs may return any of the following status-codes:
- */
- #define e_SYSTEM -1
- /* -- A system error occurred
- */
- #define e_SUCCESS 0
- /* -- No errors, success!!
- */
- #define e_USAGE 1
- /* -- No errors were encountered. A usage-message (or manual-page-template)
- ** was explicitly requested (and printed) by the user.
- */
- #define e_SYNTAX 2
- /* -- A syntax error was encountered on the command-line. The error may
- ** be in the argument(s) intended for parseargs(1) or in the argument(s)
- ** for the invoking shell-script.
- */
- #define e_NOENV 3
- /* -- The user specified that the argument description was to be found in
- ** an environment variable, however the environment variable in question
- ** is unset or empty.
- */
- #define e_ARGD 4
- /* -- An error was encountered in the string that describes the arguments
- ** for the given command.
- */
- /**^^**********************************************************************/
- X
- X /* default shell variable values for a boolean argument */
- static CONST char Default_StrTrue[] = "TRUE";
- static CONST char Default_StrFalse[] = "";
- X
- X /* define character sets */
- static CONST char WhiteSpace[] = " \t\n\v\r\f\"'";
- static CONST char ArgTableDelims[] = ",";
- static CONST char ArgFlagsDelims[] = "|+ \t\n\v\r\f";
- X
- X /* macros to improve readability of string tests */
- #define strEQ(s1,s2) !strcmp(s1, s2)
- #define strnEQ(s1,s2,n) !strncmp(s1, s2, n)
- X
- #define BUFFER_SIZE 1024 /* start off with 1k buffer & resize it */
- #define ESCAPED_COMMA '\001' /* character to replace commas with */
- X
- X /* determine the beginning and end of a struct */
- #define c_BEGIN_STRUCT '{'
- #define c_END_STRUCT '}'
- X
- X /* determine beginning-of-arg-table string */
- #define s_START_ARGS "STARTOFARGS"
- #define isSTART_ARGS(s) strnEQ(s, s_START_ARGS, 5)
- X
- X /* determine end-of-arg-table string */
- #define s_END_ARGS "ENDOFARGS"
- #define isEND_ARGS(s) strnEQ(s, s_END_ARGS, 3)
- X
- X /* define #of entries per arg-descriptor */
- #define NFIELDS 5
- X
- X
- /**************************************************************************
- ** ^SECTION: SHELLS
- ** After the command line has been parsed, parseargs will print on stan-
- ** dard output, a script to set the shell variables which correspond to
- ** arguments that were present on the command-line. This script may be
- ** evaluated by redirecting it to a file and then executing the file,
- ** or by directly evaluating the output from parseargs (under most UNIX
- ** shells, this could be done using eval). If any arguments on the com-
- ** mand line contained any special characters that needed to be escaped
- ** from the shell, these characters will remain intact (not be evaluated
- ** by the shell) in the corresponding shell variable.
- **
- ** The -s shell option may be used to tell parseargs which shell syntax
- ** to use. At present, parseargs only recognizes "sh", "csh", "ksh",
- ** "tcsh", "bash", "rc", "awk", and "perl" as valid command interpreters.
- ** Awk output is slightly different from that of the other shells in that
- ** the actual variable setting are not printed but each line of an
- ** associative array is printed (the first field is the array index, the
- ** second is the value for that index). If no shell is specified, then
- ** the Bourne shell ("sh") will be assumed.
- **
- ** If the user wishes to use a value other than "TRUE" for a boolean
- ** flag that is true, this may be done using the "-T string" option.
- ** The same may also be done for a boolean flag that is false using the
- ** "-F string" option.
- **
- ** Parseargs will only set the values of variables that correspond to
- ** arguments that were given on the command line. If a particular argu-
- ** ment was not supplied on the command line, then no assignment is made
- ** for the corresponding shell variable and it will have the same value
- ** that it had before parseargs was invoked. The only exception to this
- ** is that if the -u option is specified, then the positional parameters
- ** are unset before any shell variable assignments (which may reset the
- ** positional parameters) are made.
- ***^^*********************************************************************/
- X
- X /* #defines for possible shell names and corresponding types */
- typedef short shell_t;
- #define BASH ((shell_t) 0)
- #define TCSH ((shell_t) 1)
- #define CSH ((shell_t) 2)
- #define KSH ((shell_t) 3)
- #define SH ((shell_t) 4)
- #define RC ((shell_t) 5)
- #define AWK ((shell_t) 6)
- #define PERL ((shell_t) 7)
- X
- #define BOURNE_AGAIN_SHELL "bash"
- #define BOURNE_SHELL "sh"
- #define KORN_SHELL "ksh"
- #define C_SHELL "csh"
- #define RC_SHELL "rc"
- #define TC_SHELL "tcsh"
- #define AWK_LANG "awk"
- #define PERL_LANG "perl"
- X
- X /* structure for shell-specific info */
- typedef struct {
- X char *varname; /* name of variable containing the positional parameters */
- X char *setcmd; /* formatted string (%s is replaced with variable name) */
- X char *prefix; /* beginning for variable setting */
- X char *suffix; /* ending for variable setting */
- X char *escape; /* format to escape chars (%c is the char to escape) */
- X char *metachars; /* special characters that need to be escaped */
- } shell_info;
- X
- X /* array of shell info - indexed by the #define for the shell type */
- static CONST shell_info Shell[] = {
- X
- X /* BASH : Positional parms in -- ; Assignment Syntax: name="value"; */
- X { "--", "%s=", "'", "';\n", "'\\%c'", "'" },
- X
- X /* TCSH : Positional parms in argv ; Assignment Syntax: set name="value"; */
- X { "argv", "set %s=", "'", "';\n", "'\\%c'", "'" },
- X
- X /* CSH : Positional parms in argv ; Assignment Syntax: set name="value"; */
- X { "argv", "set %s=", "'", "';\n", "'\\%c'", "'" },
- X
- X /* KSH : Positional parms in -- ; Assignment Syntax: name="value"; */
- X { "--", "%s=", "'", "';\n", "'\\%c'", "'" },
- X
- X /* SH : Positional parms in -- ; Assignment Syntax: name="value"; */
- X { "--", "%s=", "'", "';\n", "'\\%c'", "'" },
- X
- X /* RC : Positional parms in -- ; Assignment Syntax: name="value"; */
- X { "*", "%s=", "'", "';\n", "''", "'" },
- X
- X /* AWK : Positional parms in ARGV; Assignment Syntax: name\nvalue\n\n; */
- X { "ARGV", "%s\n", "", "\n\n", "'\034'", "\n" },
- X
- X /* PERL : Positional parms in ARGV; Assignment Syntax: $name=value\n; */
- X { "ARGV", "$%s = ", "", ";\n", "'.\"%c\".'", "'" }
- };
- /*************************************************************************/
- X
- X /* define all current arg-vector types */
- typedef ARGVEC_T(char *) strvec_t;
- typedef ARGVEC_T(char) charvec_t;
- typedef ARGVEC_T(int) intvec_t;
- typedef ARGVEC_T(short) shortvec_t;
- typedef ARGVEC_T(long) longvec_t;
- typedef ARGVEC_T(float) floatvec_t;
- typedef ARGVEC_T(double) doublevec_t;
- typedef ARGVEC_T(VOID) genericvec_t; /* generic vector */
- X
- X /* union to hold all possibles values of an argument */
- typedef union {
- X BOOL Bool_val;
- X short Short_val;
- X int Int_val;
- X long Long_val;
- X float Float_val;
- X double Double_val;
- X char Char_val;
- X char *Str_val;
- X strvec_t Str_vec;
- X charvec_t Char_vec;
- X intvec_t Int_vec;
- X shortvec_t Short_vec;
- X longvec_t Long_vec;
- X floatvec_t Float_vec;
- X doublevec_t Double_vec;
- X genericvec_t Vector;
- } storage_t;
- X
- X /* structure to hold a command-line argument name, value, and fmt-string */
- typedef struct {
- X CONST char *name; /* name of shell variable to use */
- X storage_t value; /* storage for value of argument */
- } cmdarg_t;
- #define CMDARGNULL (cmdarg_t *)NULL
- X
- EXTERN int eprintf ARGS((const char *, ...));
- EXTERN VOID syserr ARGS((const char *, ...));
- EXTERN VOID usrerr ARGS((const char *, ...));
- EXTERN char *getenv ARGS((const char *));
- EXTERN VOID manpage ARGS((const ARGDESC *));
- EXTERN VOID perror ARGS((const char *));
- X
- extern int errno; /* system wide error level */
- X
- /*************************************************************************/
- X /*
- X ** variables that are set via command-line arguments
- X */
- static char *Cmd_Name; /* name of this program */
- X
- static ARGDESC *UsrArgd = ARGDESCNULL; /* users arg-table */
- static cmdarg_t *UsrVals = CMDARGNULL; /* variable names & values */
- static int UsrArgc = 0; /* # of arg-table entries */
- static shell_t UsrSh; /* shell indicator */
- static BOOL UseStdin = TRUE; /* read argd from stdin */
- X
- static char *ShellName = CHARNULL; /* name of user's shell */
- static char *UsrName = CHARNULL; /* name of users program */
- static char *FieldSep = " "; /* field-separators for arrays */
- static strvec_t UsrArgv = ARGVEC_EMPTY(char *); /* users args */
- static char *ArgdString = CHARNULL; /* argd string (with WhiteSpace) */
- static char *ArgdEnv = CHARNULL; /* environment variable for argd */
- static char *ArgdFname = CHARNULL; /* argd input file */
- static BOOL Unset = FALSE; /* ?unset positional parms? */
- static char *StrTrue = CHARNULL; /* string for TRUE values */
- static char *StrFalse = CHARNULL; /* string for FALSE values */
- static char OptsOnly = FALSE; /* parse options only? */
- static char KwdsOnly = FALSE; /* parse keywords only? */
- static BOOL ModArr = FALSE; /* modify array behavior */
- static BOOL PrUsage = FALSE; /* ?just print usage? */
- static BOOL PrManual = FALSE; /* ?just print manual page(s)? */
- static BOOL Prompt = FALSE; /* ?prompt for missing args? */
- static BOOL Ignore = FALSE; /* ?ignore bad syntax and continue? */
- X
- /*************************************************************************/
- X /* now we are ready to define the command-line */
- static
- CMD_OBJECT
- X Args
- X
- CMD_NAME
- X "parseargs -- parse command-line arguments in shell scripts"
- X
- CMD_DESCRIPTION
- X "Given a description of the command-line and the command-line arguments, \
- parseargs will parse all command-line arguments, convert them to their \
- desired type, and print on standard output, a script of all the resulting \
- shell assignment statements."
- X
- CMD_ARGUMENTS
- X 'U', ARGOPT, argBool, __ &PrUsage,
- X "usage : just print program usage, dont parse command-line",
- X
- X 'M', ARGOPT, argBool, __ &PrManual,
- X "man1 : just print man1 template, dont parse command-line",
- X
- X 'T', ARGOPT, argStr, __ &StrTrue,
- X "TRUEstr : string to use for TRUE Booleans (default=\"TRUE\")",
- X
- X 'F', ARGOPT, argStr, __ &StrFalse,
- X "FALSEstr : string to use for FALSE Booleans (default=\"\")",
- X
- X 'A', ARGOPT, argBool, __ &ModArr,
- X "array : modify the behavior of arrays",
- X
- X 'S', ARGOPT, argStr, __ &FieldSep,
- X "SEParator : field-separator-string used to delimit array elements \
- (default=\" \")",
- X
- X 'a', ARGOPT, argStr, __ &ArgdString,
- X "ARGSpec : argument specification string",
- X
- X 'e', ARGOPT, argStr, __ &ArgdEnv,
- X "ENVarname : environment variable containing arg-spec",
- X
- X 'f', ARGOPT, argStr, __ &ArgdFname,
- X "FILEname : read the arg-spec from <filename> (default=stdin)",
- X
- X 'l', ARGOPT, argBool, __ &KwdsOnly,
- X "Long-OPTionS : long-options only - do not parse options",
- X
- X 'o', ARGOPT, argBool, __ &OptsOnly,
- X "OPTionS : options only - do not parse long-options",
- X
- X 's', ARGOPT, argStr, __ &ShellName,
- X "SHell : use <shell> command syntax (default=\"sh\")",
- X
- X 'u', ARGOPT, argBool, __ &Unset,
- X "unset : unset positional parameters before parsing",
- X
- X 'p', ARGOPT, argBool, __ &Prompt,
- X "prompt : prompt the user for missing required arguments",
- X
- X 'i', ARGOPT, argBool, __ &Ignore,
- X "ignore : ignore bad command-line syntax and continue processing \
- (instead of aborting)",
- X
- X '-', ARGOPT, argDummy, __ NULL,
- X "+ : end of options - all remaining arguments are interpreted as \
- positional parameters (even if one begins with '-' or '+')",
- X
- X ' ', ARGREQ, argStr, __ &UsrName,
- X "name : name of calling program",
- X
- X ' ', ARGOPT|ARGVEC, argStr, __ &UsrArgv,
- X "arguments : arguments to calling program",
- X
- X END_ARGUMENTS
- X
- CMD_END
- X
- X
- /***************************************************************************
- ** ^FUNCTION: cleanup - deallocate all global storage
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static VOID cleanup()
- #endif /* !__ANSI_C__ */
- /*
- ** ^PARAMETERS:
- ** None.
- **
- ** ^DESCRIPTION:
- ** Cleanup is used to deallocate any global storage. It is called
- ** before exiting.
- **
- ** ^REQUIREMENTS:
- ** None.
- **
- ** ^SIDE-EFECTS:
- ** Storage associated with all dynamically allocated global-variables
- ** is released and set to NULL.
- **
- ** ^RETURN-VALUE:
- ** None.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static void cleanup( void )
- #endif
- {
- X register ARGDESC *ad;
- X register storage_t val;
- X
- X /* free up any vectors from the command-line */
- X for ( ad = ARG_FIRST(UsrArgd) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
- X if ( ! BTEST(arg_flags(ad), ARGVEC) ) continue;
- X
- X val = *((storage_t *) arg_valp(ad));
- X
- X if ( arg_type(ad) == argStr ) vecFree( val.Str_vec, char * );
- X else if ( arg_type(ad) == argChar ) vecFree( val.Char_vec, char );
- X else if ( arg_type(ad) == argInt ) vecFree( val.Int_vec, int );
- X else if ( arg_type(ad) == argShort ) vecFree( val.Short_vec, short );
- X else if ( arg_type(ad) == argLong ) vecFree( val.Long_vec, long );
- X else if ( arg_type(ad) == argFloat ) vecFree( val.Float_vec, float );
- X else if ( arg_type(ad) == argDouble ) vecFree( val.Double_vec, double );
- X }
- X
- X /* free up tables */
- X vecFree( UsrArgv, char * );
- X if ( UsrArgd ) {
- X free( UsrArgd );
- X UsrArgd = ARGDESCNULL;
- X }
- X if ( UsrVals ) {
- X free( UsrVals );
- X UsrVals = CMDARGNULL;
- X }
- X if ( ArgdFname && !ArgdEnv ) {
- X free( ArgdString );
- X ArgdString = CHARNULL;
- X }
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: ckalloc - allocate space, check for success
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static ARBPTR ckalloc( size )
- /*
- ** ^PARAMETERS:
- */
- X size_t size;
- /* -- the number of bytes to allocate
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Ckalloc will use malloc to attempt to fill the given request
- ** for memory. If The request cannot be met than a message is
- ** printed and execution is terminated.
- **
- ** ^REQUIREMENTS:
- ** size should be > 0
- **
- ** ^SIDE-EFECTS:
- ** Memory is allocated that should later be deallocated using free().
- **
- ** ^RETURN-VALUE:
- ** The address of the allocated region.
- **
- ** ^ALGORITHM:
- ** - Allocate space, check for success
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static ARBPTR ckalloc( size_t size )
- #endif
- {
- X ARBPTR ptr;
- X
- X ptr = malloc( size );
- X if ( !ptr ) {
- X eprintf( "%s: Fatal Error: out of memory!!", Cmd_Name );
- X cleanup();
- X if ( errno ) perror( Cmd_Name );
- X exit( e_SYSTEM );
- X }
- X
- X return ptr;
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: ckrealloc - reallocate space, check for success
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static ARBPTR ckrealloc( ptr, size )
- /*
- ** ^PARAMETERS:
- */
- X ARBPTR ptr;
- /* -- address of the region to be expanded/shrunk
- */
- X size_t size;
- /* -- the number of bytes to allocate
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Ckrealloc will use realloc to attempt to fill the given request
- ** for memory. If The request cannot be met than a message is
- ** printed and execution is terminated.
- **
- ** ^REQUIREMENTS:
- ** size should be > 0
- **
- ** ^SIDE-EFECTS:
- ** Memory is allocated that should later be deallocated using free().
- **
- ** ^RETURN-VALUE:
- ** The address of the (re)allocated region (which may have been moved).
- **
- ** ^ALGORITHM:
- ** - Reallocate space, check for success
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static ARBPTR ckrealloc( ARBPTR ptr, size_t size )
- #endif
- {
- X ptr = realloc( ptr, (unsigned int)size );
- X if ( !ptr ) {
- X eprintf( "%s: Fatal Error: out of memory!!", Cmd_Name );
- X cleanup();
- X if ( errno ) perror( Cmd_Name );
- X exit( e_SYSTEM );
- X }
- X
- X return ptr;
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: escape_char - (re)map a character
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static VOID escape_char( str, ch, esc )
- /*
- ** ^PARAMETERS:
- */
- X char *str;
- /* -- the string to be translated
- */
- X int ch;
- /* -- the character to be replaced/translated
- */
- X int esc;
- /* -- the replacement character to use
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Escape_char will escape all occurences of a character by replacing
- ** it with <esc> if the character appears in double or single quotes.
- **
- ** ^REQUIREMENTS:
- ** Both <ch> and <esc> should be non-zero.
- ** <str> should be non-null and non-empty.
- **
- ** ^SIDE-EFECTS:
- ** Each occurrence in <str> of <ch> within single or double quotes is
- ** replaced with <esc>.
- **
- ** ^RETURN-VALUE:
- ** None.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static void escape_char( char *str, int ch, int esc )
- #endif
- {
- X int squoted = 0, dquoted = 0;
- X
- X for ( ; *str ; str++ ) {
- X if ( *str == '\'' && !dquoted )
- X squoted = ~squoted;
- X else if ( *str == '"' && !squoted )
- X dquoted = ~dquoted;
- X else if ( (squoted || dquoted) && *str == ch )
- X *str = esc;
- X }
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: restore_char - restore any chars escaped by escape_char()
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static VOID restore_char( str, ch, esc )
- /*
- ** ^PARAMETERS:
- */
- X char *str;
- /* -- the string to be translated
- */
- X int ch;
- /* -- the character to be restored
- */
- X int esc;
- /* -- the replacement character to use to escape the above character.
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Restore_char will attempt to undo the results of a previous call
- ** to escape_char by replacing each occurence of <esc> in <str> with <ch>.
- **
- ** ^REQUIREMENTS:
- ** <str> should be the victim of a previous escape_char(str, ch, esc) call.
- ** Furthermore, <esc> should be a character that occurs only as a result
- ** of this call (it should be VERY uncommon).
- **
- ** It should be noted that escape_char() only replaces characters in quotes
- ** whereas this routine replaces all occurrences.
- **
- ** ^SIDE-EFECTS:
- ** Each occurrence of <esc> in <str> is replaced with <ch>.
- **
- ** ^RETURN-VALUE:
- ** None.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X void restore_char( char *str, int ch, int esc )
- #endif
- {
- X for ( ; *str ; str++ )
- X if ( *str == esc ) *str = ch;
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: get_arg_type - return function corresponding to given string
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static argTypePtr_t get_arg_type( type_str )
- /*
- ** ^PARAMETERS:
- */
- X char *type_str;
- /* -- string corresponding to the name of an existing argXxxx type function.
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Get_arg_type will attempt to match <type_name> against the name of all
- ** known argXxxx argumnent translation routines and routine the address of
- ** the corresponding function. If no match is found, then an error message
- ** is printed and execution is terminated.
- **
- ** ^REQUIREMENTS:
- ** type_str should be non-NULL and non-empty
- **
- ** ^SIDE-EFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** Address of the corresponding function
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static argTypePtr_t get_arg_type( const char *type_str )
- #endif
- {
- X register CONST char *str = type_str;
- X
- X /* translate all listXxx into argXxx */
- X if ( strnEQ( str, "list", 4 ) )
- X str += 4;
- X
- X if ( strnEQ( str, "arg", 3 ) )
- X str += 3;
- X
- X if ( strEQ( str, "Usage" ) )
- X return argUsage;
- X else if ( strEQ( str, "Dummy" ) )
- X return argDummy;
- X else if ( strEQ( str, "Bool" ) )
- X return argBool;
- X else if ( strEQ( str, "SBool" ) )
- X return argSBool;
- X else if ( strEQ( str, "UBool" ) )
- X return argUBool;
- X else if ( strEQ( str, "Int" ) )
- X return argInt;
- X else if ( strEQ( str, "Short" ) )
- X return argShort;
- X else if ( strEQ( str, "Long" ) )
- X return argLong;
- X else if ( strEQ( str, "Float" ) )
- X return argFloat;
- X else if ( strEQ( str, "Double" ) )
- X return argDouble;
- X else if ( strEQ( str, "Char" ) )
- X return argChar;
- X else if ( strEQ( str, "Str" ) )
- X return argStr;
- X else {
- X eprintf( "%s: Fatal Error: invalid argument type '%s'\n",
- X Cmd_Name, type_str );
- X cleanup();
- X exit( e_ARGD );
- X }
- }
- X
- X
- /***************************************************************************
- ** ^FUNCTION: get_arg_flag - return BITMASK corresponding to string
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static argMask_t get_arg_flag( flag_str )
- /*
- ** ^PARAMETERS:
- */
- X char flag_str[];
- /* -- name of an ARGXXXXX argument-flag
- */
- #endif /* !__ANSI_C__ */
- X
- /* ^DESCRIPTION:
- ** Get_arg_flag will attempt to match the given string against the name of
- ** all valid argument-flags and return its associated bitmask. If no match
- ** is found, then an error message is printed and execution is terminated.
- **
- ** ^REQUIREMENTS:
- ** flag_str should be non-NULL and non-empty
- **
- ** ^SIDE-EFECTS:
- ** None.
- **
- ** ^RETURN-VALUE:
- ** The bitmask corresponding to named ARGXXXX flag.
- **
- ** ^ALGORITHM:
- ** Trivial.
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static argMask_t get_arg_flag( const char flag_str[] )
- #endif
- {
- X if ( strnEQ( flag_str, "ARG", 3 ) ) {
- X if ( strEQ( flag_str+3, "OPT" ) ) return ARGOPT;
- X else if ( strEQ( flag_str+3, "REQ" ) ) return ARGREQ;
- X else if ( strEQ( flag_str+3, "POS" ) ) return ARGPOS;
- X else if ( strEQ( flag_str+3, "VALREQ" ) ) return ARGVALREQ;
- X else if ( strEQ( flag_str+3, "VALOPT" ) ) return ARGVALOPT;
- X else if ( strEQ( flag_str+3, "HIDDEN" ) ) return ARGHIDDEN;
- X else if ( strEQ( flag_str+3, "LIST" ) ) return ARGVEC;
- X else if ( strEQ( flag_str+3, "VEC" ) ) return ARGVEC;
- X else {
- X eprintf( "%s: Fatal Error: invalid argument flag '%s'\n",
- X Cmd_Name, flag_str );
- X cleanup();
- X exit( e_ARGD );
- X }
- X }
- X else {
- X eprintf( "%s: Fatal Error: invalid argument flag '%s'\n",
- X Cmd_Name, flag_str );
- X cleanup();
- X exit( e_ARGD );
- X }
- }
- X
- /***************************************************************************
- ** ^FUNCTION: get_argtable_string - read in the argument-table
- **
- ** ^SYNOPSIS:
- */
- #ifndef __ANSI_C__
- X static char *get_argtable_string()
- #endif
- /*
- ** ^PARAMETERS:
- ** None.
- **
- ** ^DESCRIPTION:
- ** Get_argtable_string will read (from standard input if UseStdin is set)
- ** the entire argument descriptor table into a string and return its address.
- **
- ** Execution is terminated if there is an error reading STDIN or if the
- ** string is too big to fit into memory.
- **
- ** ^REQUIREMENTS:
- ** Standard input should be open for reading and be non-interactive.
- **
- ** ^SIDE-EFECTS:
- ** Memory is allocated that should later be deallocated using free.
- **
- ** ^RETURN-VALUE:
- ** NULL if STDIN is connected to a terminal (after all,
- ** this program is for Non-interactive input)
- **
- ** ^ALGORITHM:
- ** - start off with a 1k buffer
- ** - open the file (if necessary)
- ** - while (not eof)
- ** - read 1k bytes (or whatever is left).
- ** - increase the buffer size by 1k bytes.
- ** end-while
- ** - shrink the buffer down to the number of bytes used.
- ** - close the file (if we had to open it).
- ** - return the buffer address
- ***^^**********************************************************************/
- #ifdef __ANSI_C__
- X static char *get_argtable_string( void )
- #endif
- {
- X int isatty ARGS((int));
- X int fread ARGS((char *, int, int, FILE *));
- X FILE *fp;
- X char *buf;
- X register int nchars = 0; /* # bytes read */
- X register int bufsiz = 0; /* actual buffer-size needed */
- X
- X /* open file if necessary */
- X if ( UseStdin ) {
- X if ( isatty(STDIN) ) {
- X /* we wont read the arg-table from a terminal */
- X eprintf( "\
- %s: Fatal Error:\n\
- \tcannot read arg-descriptor table from stdin\n\
- \tif stdin is connected to a terminal\n!",
- X Cmd_Name );
- X cleanup();
- X exit( e_ARGD );
- X }
- X errno = 0; /* reset errno if isatty() was not a terminal */
- X fp = stdin;
- X }
- X else {
- X if ( (fp = fopen( ArgdFname, "r")) == FILENULL ) {
- X eprintf( "%s: Fatal error: Unable to open %s for reading\n",
- SHAR_EOF
- true || echo 'restore of parseargs/parseargs.c failed'
- fi
- echo 'End of part 5'
- echo 'File parseargs/parseargs.c is continued in part 6'
- echo 6 > _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.
-