v17i050: parseargs - functions to parse command line arguments, Part05/12
Brad Appleton
brad at hcx1.ssd.csd.harris.com
Mon Mar 18 06:07:12 AEST 1991
Submitted-by: Brad Appleton <brad at 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 at 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 at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.misc
mailing list