home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume17
/
parseargs
/
part06
< prev
next >
Wrap
Internet Message Format
|
1991-03-17
|
63KB
From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
Newsgroups: comp.sources.misc
Subject: v17i051: parseargs - functions to parse command line arguments, Part06/12
Message-ID: <1991Mar17.200733.17985@sparky.IMD.Sterling.COM>
Date: 17 Mar 91 20:07:33 GMT
Approved: kent@sparky.imd.sterling.com
X-Checksum-Snefru: 6591537f 439c2bbf 7a5900e7 66cacf7c
Submitted-by: Brad Appleton <brad@hcx1.ssd.csd.harris.com>
Posting-number: Volume 17, Issue 51
Archive-name: parseargs/part06
This is part 6 of parseargs
#!/bin/sh
# this is Part.06 (part 6 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file parseargs/parseargs.c continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 6; 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/parseargs.c'
else
echo 'x - continuing file parseargs/parseargs.c'
sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/parseargs.c' &&
X Cmd_Name, ArgdFname );
X cleanup();
X if ( errno ) perror( Cmd_Name );
X exit( e_SYSTEM );
X }
X }
X
X /* get initial block for buffer */
X buf = (char *)ckalloc( BUFFER_SIZE * sizeof(char) );
X
X /*
X ** Loop reading characters into buffer and resizing as needed
X */
X do {
X /* read fildes into the buffer */
X nchars = fread( &(buf[bufsiz]), sizeof(char), BUFFER_SIZE, fp );
X if ( nchars < 0 ) {
X eprintf( "\
%s: Fatal Error:\n\
\tBad status from read() while reading argument descriptor table\n",
X Cmd_Name );
X free(buf);
X cleanup();
X if ( errno ) perror( "" );
X exit( e_SYSTEM );
X }
X errno = 0; /* errno is undefined after a succesful fread() */
X bufsiz += nchars;
X
X /* see if we need to grow the buffer */
X if ( nchars == BUFFER_SIZE )
X buf = (char *)ckrealloc( buf, (bufsiz + BUFFER_SIZE) * sizeof(char) );
X } while ( nchars == BUFFER_SIZE );
X
X /* shrink the buffer down to the exact size used */
X buf = (char *)ckrealloc( buf, (bufsiz + 1) * sizeof(char) );
X
X /* close file if necessary */
X if ( !UseStdin ) (VOID) fclose( fp );
X
X return buf;
}
X
X
/***************************************************************************
** ^FUNCTION: get_shell_type - return shell corresponding to given string
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static shell_t get_shell_type( sh_str )
/*
** ^PARAMETERS:
*/
X char *sh_str;
/* -- string corresponding tp the basename of a shell/command-interpreter
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Get_shell_type will retrun the shell-type for the named shell. If
** No corresponding shell is known, then an error message is printed
** and execution is terminated.
**
** ^REQUIREMENTS:
** sh_str should be non-NULL and non-empty.
**
** ^SIDE-EFECTS:
** None.
**
** ^RETURN-VALUE:
** The corresponding shell-type.
**
** ^ALGORITHM:
** Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X static shell_t get_shell_type ( const char *sh_str )
#endif
{
X if ( strEQ( sh_str, BOURNE_SHELL ) )
X return SH;
X else if ( strEQ( sh_str, TC_SHELL ) )
X return TCSH;
X else if ( strEQ( sh_str, C_SHELL ) )
X return CSH;
X else if ( strEQ( sh_str, KORN_SHELL ) )
X return KSH;
X else if ( strEQ( sh_str, BOURNE_AGAIN_SHELL ) )
X return BASH;
X else if ( strEQ( sh_str, RC_SHELL ) )
X return RC;
X else if ( strEQ( sh_str, AWK_LANG ) )
X return AWK;
X else if ( strEQ( sh_str, PERL_LANG ) )
X return PERL;
X
X else {
X eprintf( "%s: Fatal Error: unknown shell '%s'\n",
X Cmd_Name, sh_str );
X eprintf( "\tKnown shells are: %s, %s, %s, %s, %s, %s, %s, and %s\n",
X AWK_LANG, BOURNE_AGAIN_SHELL, C_SHELL, KORN_SHELL, RC_SHELL,
X PERL_LANG, BOURNE_SHELL, TC_SHELL );
X cleanup();
X exit( e_SYNTAX );
X }
}
X
X
/***************************************************************************
** ^FUNCTION: build_tables - build the Argument and Value tables
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static int build_tables( argd_str )
/*
** ^PARAMETERS:
*/
X char argd_str[];
/* -- the comma-separated table of argument descriptions
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Build_tables will read the contents of the argument-descriptor-table
** string and build the corresponding Argument and Value tables to be
** used by parseargs(3).
**
** ^REQUIREMENTS:
** argd_str should be non-NULL and non-empty
**
** ^SIDE-EFECTS:
** The global variables UsrVals and UsrArgd are allocated and initialized
**
** ^RETURN-VALUE:
** The number of argument entries interpreted from the given string.
**
** ^ALGORITHM:
** - split argd_str into a vector of tokens
** - make sure the first and last tokens are syntactically correct
** - make sure that the number of tokens is a multiple of 5 (the number
** of fields in an argument descriptor)
** - num-args = num-tokens / 5
** - allocate space for UsrVals and UsrArgd
** - i = 0
** - for every 5 tokens
** - UsrArgd[i].ad_name = token#1
** - UsrArgd[i].ad_flags = 0
** - split token#2 into a subvector of '|' separated fields
** - for each '|' separated token
** - UsrArgd[i].ad_flags |= bitmask( subfield )
** end-for
** - UsrArgd[i].ad_type = argtype( token#3 )
** - UsrVals[i].name = token#4
** - UsrArgd[i].ad_valp = &(UsrVals[i].value)
** - UsrArgd[i].ad_prompt = token#5
** - increment i by one
** end-for
** - Initialize first and last entries in UsrArgd
** - return num-args
***^^**********************************************************************/
#ifdef __ANSI_C__
X static int build_tables( char argd_str[] )
#endif
{
X char **token_vec, **flags_vec, *type_name;
X int i = 0, j = 0, idx, token_num = 0, flags_num = 0;
X int argc = 0, ad_idx;
X BOOL start_string_used = FALSE, is_braces = FALSE;
X
X /* what about NULL or empty-string */
X if ( !argd_str || !*argd_str ) return 0;
X
X /* escape all commas inside of single or double quotes */
X escape_char( argd_str, ',', ESCAPED_COMMA );
X
X /* parse Argument Table String */
X token_num = strsplit( &token_vec, argd_str, ArgTableDelims );
X if ( token_num ) (VOID) strtrim( token_vec[ token_num - 1 ], WhiteSpace );
X
X /* see if we need to build the tables at all */
X if ( token_num == 0 || isEND_ARGS(*token_vec) ) {
X free( token_vec );
X return 0; /* nothing to parse */
X }
X
X /* make sure table is properly terminated */
X if ( !isEND_ARGS( token_vec[ --token_num ] ) ) {
X restore_char( token_vec[ token_num ], ',', ESCAPED_COMMA );
X eprintf( "\
%s: Fatal Error:\n\
\tArgument descriptor table is not terminated with the string:\n\
\t\t\"%s\"\n\
\tLast entry in table is: \"%s\"\n",
X Cmd_Name, s_END_ARGS, token_vec[ token_num ] );
X free( token_vec );
X cleanup();
X exit( e_ARGD );
X }
X
X /* check for optional start-string */
X (VOID) strtrim( *token_vec, WhiteSpace );
X if ( isSTART_ARGS(*token_vec) ) {
X start_string_used = TRUE;
X --token_num;
X ++token_vec;
X }
X
X /* make sure table has proper number of arguments */
X if ( (token_num % NFIELDS) != 0 ) {
X eprintf( "\
%s: Fatal Error:\n\
\tArgument descriptor table has an invalid number of arguments\n\
\tThe number of comma-separated arguments MUST be a multiple of %d\n\
\t(not including terminating \"%s\")\n",
X Cmd_Name, NFIELDS, s_END_ARGS );
X free( (start_string_used) ? (token_vec - 1) : token_vec );
X cleanup();
X exit( e_ARGD );
X }
X
X /* determine number of arg-descriptors and allocate arg-tables */
X argc = token_num / NFIELDS;
X UsrArgd = (ARGDESC *) ckalloc( (argc + 2) * sizeof(ARGDESC) );
X UsrVals = (cmdarg_t *) ckalloc( argc * sizeof(cmdarg_t) );
X
X /* start filling in the tables */
X i = 0;
X while ( i < token_num ) {
X restore_char( token_vec[i], ',', ESCAPED_COMMA );
X (VOID) strtrim( token_vec[i], WhiteSpace );
X idx = (i / NFIELDS); /* save index into UsrVals table */
X ad_idx = (idx + 1); /* save index into UsrArgd table */
X is_braces = FALSE;
X
X /* remove first curly-brace if its present (this has the drawback
X ** of disallowing a left curly-brace from being an option character).
X */
X if ( token_vec[i][0] == c_BEGIN_STRUCT ) {
X token_vec[i][0] = ' ';
X (VOID) strltrim( token_vec[i], WhiteSpace );
X is_braces = TRUE;
X }
X
X /* get argument name */
X UsrArgd[ ad_idx ].ad_name = *(token_vec[i++]);
X if ( !UsrArgd[ ad_idx ].ad_name ) UsrArgd[ ad_idx ].ad_name = ' ';
X
X /*
X ** get argument flags, flags may be ORed together so I
X ** need to parse the flags for each individual flag used
X */
X UsrArgd[ ad_idx ].ad_flags = (argMask_t) 0; /* initialize */
X flags_num = strsplit( &flags_vec, token_vec[i++] , ArgFlagsDelims );
X for ( j = 0 ; j < flags_num ; j++ ) {
X (VOID) strtrim( flags_vec[j], WhiteSpace );
X UsrArgd[ ad_idx ].ad_flags |= get_arg_flag( flags_vec[j] );
X }
X free( flags_vec );
X
X /* get argument type and name for Value table */
X type_name = strtrim( token_vec[i++], WhiteSpace );
X restore_char( token_vec[i], ',', ESCAPED_COMMA );
X UsrVals[ idx ].name = strtrim( token_vec[i++], WhiteSpace );
X
X /* remove any leading "__" from the name */
X if ( strnEQ("__", UsrVals[ idx ].name, 2) ) {
X (VOID) strltrim( (char *)UsrVals[idx].name, "_ \t\n\r\v\f" );
X }
X
X /* remove any leading '&', '$', and '@' from the name */
X if ( strchr("&$@", UsrVals[ idx ].name[0]) ) {
X (VOID) strltrim( (char *)UsrVals[idx].name, "&$@ \t\n\r\v\f" );
X }
X
X /* get type and value pointer for Arg table */
X UsrArgd[ ad_idx ].ad_type = get_arg_type( type_name );
X UsrArgd[ ad_idx ].ad_valp = __ &(UsrVals[ idx ].value);
X
X /* if we have a vector we need to initialize it */
X if ( ARG_isVEC((UsrArgd + ad_idx)) ) {
X UsrVals[ idx ].value.Vector.count = 0;
X UsrVals[ idx ].value.Vector.array = (VOID *)NULL;
X }
X
X /* get argument prompt/description */
X restore_char( token_vec[i], ',', ESCAPED_COMMA );
X UsrArgd[ ad_idx ].ad_prompt = strtrim( token_vec[i++], WhiteSpace );
X
X /* if in curly-braces, remove the trailing brace */
X if ( is_braces ) {
X int last = strlen( UsrArgd[ad_idx].ad_prompt ) - 1;
X if ( UsrArgd[ ad_idx ].ad_prompt[ last ] == c_END_STRUCT ) {
X *((char *)(UsrArgd[ ad_idx ].ad_prompt) + last) = '\0';
X (VOID) strrtrim( (char *)UsrArgd[ad_idx].ad_prompt, WhiteSpace );
X }
X }/*end-if*/
X }/*while*/
X
X /* free up token tables (just the arrays, not the actual elements) */
X free( flags_vec );
X free( (start_string_used) ? (token_vec - 1) : token_vec );
X
X /* set up first & last argument entries */
X (UsrArgd -> ad_name) = UsrArgd[ argc+1 ].ad_name = '\0';
X (UsrArgd -> ad_flags) = UsrArgd[ argc+1 ].ad_flags = (argMask_t) 0;
X (UsrArgd -> ad_type) = UsrArgd[ argc+1 ].ad_type = argNULL;
X (UsrArgd -> ad_valp) = UsrArgd[ argc+1 ].ad_valp = ARBNULL;
X UsrArgd[ argc+1 ].ad_prompt = CHARNULL;
X
X /* try to get a command-description */
X cmd_description(UsrArgd) = getenv( "DESCRIPTION" );
X if ( !cmd_description(UsrArgd) ) {
X cmd_description(UsrArgd) = getenv( "CMD_DESCRIPTION" );
X }
X
X return argc;
}
X
X
/***************************************************************************
** ^FUNCTION: put_char_arg - print a character
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static put_char_arg( fp, ch )
/*
** ^PARAMETERS:
*/
X FILE *fp;
/* -- the output stream to write to.
*/
X int ch;
/* -- the character to print
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Put_char_arg will write the given character on the specified output
** stream. If the character is metacharacter for the current shell, then
** it is "escaped" according to the given shell syntax.
**
** ^REQUIREMENTS:
** <fp> should be non-NULL and open for writing.
** <ch> should be a printable character.
**
** ^SIDE-EFECTS:
** output is written to <fp>.
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** print a character argument on standard output
** and make sure we preserve the evaluation of
** any special characters such as: double-quotes,
** back-quotes, back-slash, dollar-signs, etc ....
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void put_char_arg( FILE *fp, int ch )
#endif
{
X /* newline needs to be escaped specially for CSH, TCSH, and PERL */
X if ( ch == '\n' ) {
X if ( UsrSh == CSH || UsrSh == TCSH ) {
X fprintf( fp, "\\\n" );
X return;
X }
X else if ( UsrSh == PERL ) {
X fprintf( fp, "\\n" );
X return;
X }
X }/*if newline*/
X
X if ( strchr( Shell[ UsrSh ].metachars, ch ) ) {
X fprintf( fp, Shell[ UsrSh ].escape, ch );
X }
X else {
X fputc( ch, fp );
X }
}
X
X
/***************************************************************************
** ^FUNCTION: put_str_arg - same as put_char_arg but for a string!
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static VOID put_str_arg( fp, str )
/*
** ^PARAMETERS:
*/
X FILE *fp;
/* -- the output stream to write to
*/
X char str[];
/* -- the string to print
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Put_str_arg will print the given string to the given output stream
** and will escape any shell meta-characters for the current shell.
**
** ^REQUIREMENTS:
** <fp> should be non-NULL and open for writing.
** <str> should be non-NULL and non-empty.
**
** ^SIDE-EFECTS:
** Output is written to <fp>
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - foreach character in str
** - put_char_arg(fp, character)
** end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void put_str_arg( FILE *fp, const char str[] )
#endif
{
X if ( !str ) return;
X
X for ( ; *str ; str++ )
X put_char_arg( fp, *str );
}
X
X
/***************************************************************************
** ^FUNCTION: put_arg - convert & print the given value into the given buffer
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static VOID put_arg( fp, ad, val, idx )
/*
** ^PARAMETERS:
*/
X FILE *fp;
/* -- the output stream to write to
*/
X ARGDESC *ad;
/* -- the argument-descriptor of the argument to print.
*/
X cmdarg_t *val;
/* -- the value of the argument to print
*/
X short idx;
/* -- the index in the argument-vector of the item to be printed
** (only used when ad corresponds to an ARGVEC argument).
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Put_arg will print the given variable/array setting on the given
** output stream using the syntax of the user-sepcified shell.
**
** ^REQUIREMENTS:
** <val> should be the value corresponing to the argument-descriptor <ad>
**
** ^SIDE-EFECTS:
** Output is written to <fp>.
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - if we have a vector, make sure we were given a valid index.
** - if we have a vector, then value=val.vec[idx],
** else value = val.value
** - print the beginning of the variable setting
** - case (argument-type) of
** INTEGRAL-TYPE: print the integer value
** DECIMAL-TYPE: print the floating point value
** CHARACTER: print the character value and escape it if necessary
** STRING: print the string value and escape it if necessary
** BOOLEAN: print the string StrTrue if value is TRUE
** print the string StrFalse if value is FALSE
** - print the end of the variable setting
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void put_arg(
X FILE *fp, const ARGDESC *ad, const cmdarg_t *val, short idx
X )
#endif
{
X if ( ARG_isVEC(ad) ) {
X if ( idx < 0 || idx >= val->value.Vector.count ) {
X return; /* bad index given */
X }
X
X if ( arg_type(ad) == argStr ) {
X if ( UsrSh == PERL ) fputc( '\'', fp );
X put_str_arg( fp, val->value.Str_vec.array[idx] );
X if ( UsrSh == PERL ) fputc( '\'', fp );
X }
X else if ( arg_type(ad) == argChar ) {
X if ( UsrSh == PERL ) fputc( '\'', fp );
X put_char_arg( fp, val->value.Char_vec.array[idx] );
X if ( UsrSh == PERL ) fputc( '\'', fp );
X }
X else if ( arg_type(ad) == argDouble ) {
X fprintf( fp, "%lf", val->value.Double_vec.array[idx] );
X }
X else if ( arg_type(ad) == argFloat ) {
X fprintf( fp, "%f", val->value.Float_vec.array[idx] );
X }
X else if ( arg_type(ad) == argLong ) {
X fprintf( fp, "%ld", val->value.Long_vec.array[idx] );
X }
X else if ( arg_type(ad) == argInt ) {
X fprintf( fp, "%d", val->value.Int_vec.array[idx] );
X }
X else if ( arg_type(ad) == argShort ) {
X fprintf( fp, "%ld", val->value.Short_vec.array[idx] );
X }
X
X /* Boolean vectors are not supported */
X }/*if vector*/
X else {
X if ( arg_type(ad) == argStr ) {
X put_str_arg( fp, val->value.Str_val );
X }
X else if ( arg_type(ad) == argChar ) {
X put_char_arg( fp, val->value.Char_val );
X }
X else if ( arg_type(ad) == argDouble ) {
X fprintf( fp, "%lf", val->value.Double_val );
X }
X else if ( arg_type(ad) == argFloat ) {
X fprintf( fp, "%f", val->value.Float_val );
X }
X else if ( arg_type(ad) == argLong ) {
X fprintf( fp, "%ld", val->value.Long_val );
X }
X else if ( arg_type(ad) == argInt ) {
X fprintf( fp, "%d", val->value.Int_val );
X }
X else if ( arg_type(ad) == argShort ) {
X fprintf( fp, "%ld", val->value.Short_val );
X }
X else if ( ARG_isBOOLEAN(ad) ) {
X fprintf( fp, "%s", (val->value.Bool_val) ? StrTrue : StrFalse );
X }
X }/*else !vector*/
}
X
X
/***************************************************************************
** ^FUNCTION: print_argvector - print shell variable settings for an ARGVEC
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static VOID print_argvector( ad, val )
/*
** ^PARAMETERS:
*/
X ARGDESC *ad;
/* -- the argument-descriptor of the vector to print
*/
X cmdarg_t *val;
/* -- the value of the vector to print
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Parseargs treats ARGLIST and ARGVEC arguments in a special way. The
** method used for setting up an argument list depends largely upon the
** syntax of shell that was specified on the command line via the -s option
** (although an ARGLIST argument is treated the same as an ARGVEC argument).
**
** ^Resetting_the_Positional_Parameters_to_an_Argument_List:
** For the Bourne, Bourne-Again, and Korn shells, if the variable name
** corresponding to the ARGLIST argument is "--", then the positional
** parameters of the calling program will be re-assigned to the contents
** of the argument list ($1 will be the first item, $2 the second item,
** and so on). In this particular case, the calling program may wish to
** use the -u option to reset the positional parameters to NULL before
** making any shell-variable assignments (this way, the positional
** parameters will be unset if the associated list of command line
** arguments is not encountered).
**
** Similarly for the C and TC shells, if the variable name corresponding
** to the ARGLIST argument is "argv", then the positional parameters
** of the calling program will be re-assigned to the contents of the
** argument list.
**
** For the Plan 9 shell (rc), if the variable name corresponding to the
** ARGLIST argument is "*", then the positional parameters of the calling
** program will be re-assigned to the contents of the argument list.
**
** For awk and perl, if the variable name corresponding to the ARGLIST
** argument is "ARGV", then the positional parameters of the calling
** program will be re-assigned to the contents of the argument list.
**
** ^Bourne_Shell_Argument_Lists:
** For the Bourne shell, if the associated variable name is NOT "--"
** and the -A option was NOT specified, then that variable is treated as
** a regular shell variable and is assigned using the following syntax:
**
** name='arg1 arg2 ...'
**
** After invoking parseargs, if you wish to go through all the words in
** the variable name and one of the words in name contains an IFS charac-
** ter (such as a space or a tab), then that particular word will be
** treated by the Bourne shell as two distinct words.
**
** Also for the Bourne shell, If the associated variable name is NOT
** "--" and the -A option WAS specified, then that variable is treated
** as the root name of an array that is set using the following syntax:
**
** name1='arg1'
** name2='arg2'
** ...
**
** and the variable "name_count" will be set to contain the number of
** items in the array. The user may then step through all the items in
** the array using the following syntax:
**
** i=1
** while [ $i -le $name_count ] ; do
** eval echo "item #$i is: " \$name$i
** i=`expr $i + 1`
** done
**
** ^Korn_Shell_Argument_Lists:
** For the Korn shell, if the associated variable name is NOT "--",
** then that variable is treated as an array and is assigned using the -A
** option of the set command. The first item will be in ${name[0]}, the
** second item will be in ${name[1]}, etc ..., and all items may be given
** by ${name[*]} or ${name[@]}. If the associated variable name is NOT
** "--" and the -A option WAS specified, then that variable is assigned
** using the +A option of the set command (which preserves any array
** elements that were not overwritten by the set command).
**
** It should be noted that there is a bug in versions of the Korn shell
** earlier than 11/16/88a, in which the following:
**
** set -A name 'arg1' 'arg2' ...
**
** causes the positional parameters to be overwritten as an unintentional
** side-effect. If your version of the Korn shell is earlier than this
** and you wish to keep the contents of your positional parameters after
** invoking parseargs than you must save them yourself before you call
** parseargs. This may be accomplished by the following:
**
** set -A save_parms "$@"
**
** ^C_and_TC_Shell_Argument_Lists:
** For the C and TC shells, ARGLIST variables are treated as word-lists
** and are assigned using the following syntax:
**
** set name = ( 'arg1' 'arg2' ... )
**
** The first item will be in $name[1], the second item will be in
** $name[2], etc ..., and all items may be given by $name. Notice that
** Korn shell arrays start at index zero whereas C and TC shell word-
** lists start at index one.
**
** ^Bourne-Again_Shell_Argument_Lists:
** At present, the Free Software Foundation's Bourne-Again shell is
** treated exactly the same as the Bourne Shell. This will change when
** bash supports arrays.
**
** ^Plan_9_Shell_Argument_Lists:
** For the Plan 9 shell, if the associated variable name is not "*" then
** it is considered to be word-list and set using the following syntax:
**
** name=( 'arg1' 'arg2' ... )
**
** ^Awk_Argument_Lists:
** For awk, if the -A option is not given, then the output for thes
** variable-list will be a line with the variable name, followed by a
** line with each of the values (each value will be separated with the
** field separator specified using the -S option - which defaults to a
** space character):
**
** name
** arg1 arg2 ...
**
** If the -A option is given, then the associated variable is considered
** the root name of an array. The ouput for the array will consist of two
** lines for each item in the list (as in the following expample):
**
** name1
** arg1
**
** name2
** arg2
**
** and the variable "name_count" will have an output line showing the
** number of items in the array.
**
** ^Perl_Argument_Lists:
** For perl, each argument list is considered an array and is set using
** the following syntax:
**
** @name=( arg1 , arg2 , ... )
**
** ^A_Final_Note_on_Argument_Lists:
** The word-lists used by the C shell, the arrays used by the Korn shell,
** The Plan 9 shell, awk, & perl, and the positional parameters used by
** all shells (if overwritten by parseargs) will preserve any IFS
** characters in their contents. That us to say that if an item in one
** of the aforementioned multi-word lists contains any IFS characters,
** it will not be split up into multiple items but will remain a single
** item which contains IFS characters.
**
** ^REQUIREMENTS:
** <val> should correspond to the vlue of the argument indicated by <ad>
**
** ^SIDE-EFECTS:
** prints the array assignment statement on standard output
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - print the beginning of the array assigment statement
** - print each item in the array (escaping characters where needed)
** - print the end of the array assignment statement
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void print_argvector( const ARGDESC *ad, const cmdarg_t *val )
#endif
{
X BOOL is_array = TRUE;
X int i;
X char *varname;
X
X switch( UsrSh ) {
X case KSH :
X if ( strEQ( val->name, Shell[ UsrSh ].varname ) ) {
X fputs( "set -- ", stdout );
X }
X else {
X printf( "set %cA %s ", ((ModArr) ? '+' : '-'), val->name );
X }
X break;
X
X case TCSH : case CSH : case RC: case PERL :
X if ( UsrSh == PERL )
X printf( "@%s = ", val->name );
X else if ( UsrSh == RC )
X printf( "%s=", val->name );
X else /* UsrSh == CSH/TCSH */
X printf( "set %s=", val->name );
X fputc( '(', stdout );
X break;
X
X case BASH: case SH : case AWK:
X if ( UsrSh == AWK ) is_array = FALSE;
X if ( strEQ( val->name, Shell[ UsrSh ].varname ) ) {
X fputs( ((UsrSh == AWK) ? "ARGV\n" : "set -- "), stdout );
X }
X else {
X if ( ModArr ) { /* use fake array syntax */
X i = strlen( val->name );
X varname = (char *)ckalloc( (i + 4) * sizeof(char) );
X for ( i = 0 ; i < val->value.Vector.count ; i++ ) {
X sprintf( varname, "%s%d", val->name, i+1 );
X printf( Shell[ UsrSh ].setcmd, varname );
X printf( Shell[ UsrSh ].prefix );
X put_arg( stdout, ad, val, i );
X printf( "%s", Shell[ UsrSh ].suffix );
X }
X sprintf( varname, "%s_count", val->name );
X printf( Shell[ UsrSh ].setcmd, varname );
X printf( Shell[ UsrSh ].prefix );
X printf( "%d", val->value.Vector.count );
X printf( "%s", Shell[ UsrSh ].suffix );
X free( varname );
X if ( val->value.Vector.array ) {
X free( val->value.Vector.array );
X val->value.Vector.array = NULL;
X }
X return;
X }/*if ModArr*/
X else {
X is_array = FALSE;
X printf( Shell[ UsrSh ].setcmd, val->name );
X printf( Shell[ UsrSh ].prefix );
X }
X }/*else !positional-parms*/
X break;
X
X }/*switch*/
X
X for ( i = 0 ; i < val->value.Vector.count ; i++ ) {
X if ( is_array ) printf( Shell[ UsrSh ].prefix );
X put_arg( stdout, ad, val, i );
X if ( is_array ) printf( Shell[ UsrSh ].prefix );
X if ( i != (val->value.Vector.count - 1) ) {
X fputs( ((UsrSh == PERL) ? ", " : FieldSep), stdout );
X }
X }/* end-for */
X
X if ( val->value.Vector.array ) {
X free( val->value.Vector.array );
X val->value.Vector.array = NULL;
X }
X
X if ( UsrSh == CSH || UsrSh == TCSH || UsrSh == RC || UsrSh == PERL ) {
X fputc( ')', stdout );
X }
X
X fputs( ((! is_array) ? Shell[ UsrSh ].suffix : ";\n"), stdout );
}
X
X
/***************************************************************************
** ^FUNCTION: print_args - print the shell variable settings for the usr args
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static VOID print_args( vals, argd )
/*
** ^PARAMETERS:
*/
X cmdarg_t *vals;
/* -- the table of argument values.
*/
X ARGDESC *argd;
/* -- the table of argument-descriptors.
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Print_args prints the actual shell variable assignment statement(s) for
** each argument found on the command line. If a command-line argument was
** specified withch may take an optional value, then regargdless of whether
** or not the optional value was supplied, the variable <name>_flag is set
** to the value indicated by StrTrue.
**
** ^REQUIREMENTS:
** The argument values have already been set due to the fact that parseargs
** should already have been invoked to parse the command-line
**
** ^SIDE-EFECTS:
** Variable assignment statements are printed on standard output.
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - for each argument in the argument table
** - if this argument was supplied on the command-line
** - if the argument takes an optional value
** then set argname_flag = TRUE
** - if the argument is a vector
** - call print_argvector to print the vector elements
** - else
** - print the beginning of the variable assignment statement for
** the shell indicated by UsrSh
** - print the argument value using put_arg
** - print the end of the variable assignment statement for the shell
** indicated by UsrSh
** end-if vector
** end-if supplied
** end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void print_args( const cmdarg_t *vals, const ARGDESC *argd )
#endif
{
X register CONST ARGDESC *ad;
X register int i;
X argName_t buf;
X
X /* print values for all options given */
X for ( ad = ARG_FIRST(argd), i = 0 ; !ARG_isEND(ad) ; ARG_ADVANCE(ad), i++ ) {
X if ( ARG_isGIVEN(ad) ) {
X /******************************************************************
X ** ^SECTION: ARGVALOPT
X ** Options that may take an optional argument need special
X ** consideration. The shell programmer needs to know whether
X ** or not the option was given, and (if given) if it was
X ** accompanied by an argument. In order to accommodate this
X ** need, parseargs will set an additional shell variable for
X ** each argument that is given the ARGVALOPT flag if it is
X ** supplied on the command line regardless of whether or not
X ** it was accompanied by its optional argument. If the user
X ** has defined an option which may optionally take an argument
X ** and the option appears on the command line with or without
X ** its associated argument, then the shell variable <name>_flag
X ** will be assigned the value "TRUE" (or the value supplied with
X ** the -T option to parseargs) where <name> is the name of the
X ** shell variable associated with the option in the argument
X ** description string.
X ***^^*************************************************************/
X if ( ARG_isVALOPTIONAL(ad) ) {
X sprintf(buf, "%s_flag", vals[i].name);
X printf( Shell[ UsrSh ].setcmd, buf);
X printf( Shell[ UsrSh ].prefix );
X printf( "%s%s", StrTrue, Shell[ UsrSh ].suffix );
X
X if ( !ARG_isVALGIVEN(ad) ) continue;
X }/*if OPTARG*/
X
X /* vectors are special */
X if ( ARG_isVEC(ad) ) {
X print_argvector( ad, (vals + i) );
X continue;
X }
X
X /* print shell-specific variable prefix and name */
X printf( Shell[ UsrSh ].setcmd, vals[i].name );
X printf( Shell[ UsrSh ].prefix );
X
X /* print shell-variable value */
X put_arg( stdout, ad, (vals + i), 0 );
X
X /* print the shell-specific suffix */
X printf( "%s", Shell[ UsrSh ].suffix );
X }/*if ARGGIVEN*/
X }/* end-for */
}
X
X
/***************************************************************************
** ^FUNCTION: unset_positional_parameters - unset shell parameters
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static void unset_positional_parameters()
#endif
/*
** ^PARAMETERS:
** None.
**
** ^DESCRIPTION:
** Unset_positional_parameters will print (on standard output) the
** shell commands to unset the positional parameters of the invoking
** shell_script.
**
** ^REQUIREMENTS:
** The currenty shell-type has already been determined.
**
** ^SIDE-EFECTS:
** Prints on stdout.
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - Use the syntax of the current shell to unset the positional parameters
***^^**********************************************************************/
#ifdef __ANSI_C__
X static void unset_positional_parameters( void )
#endif
{
X switch( UsrSh ) {
X case TCSH: case CSH:
X printf( "set argv=();\n" );
X break;
X
X case PERL:
X printf( "@ARGV = ();\n" );
X break;
X
X case KSH:
X printf( "set --;\n" );
X break;
X
X case BASH: case SH:
X printf( "shift $#;\n" );
X break;
X
X case RC:
X printf( "*=();\n" );
X break;
X
X case AWK:
X printf( "%s%s", Shell[ UsrSh ].varname, Shell[ UsrSh ].suffix );
X break;
X
X default:
X break;
X }/*switch*/
}
X
X
/***************************************************************************
** ^FUNCTION: ck_cmd_errs - check for command syntax errors
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static int ck_cmd_errs()
#endif
/*
** ^PARAMETERS:
** None.
**
** ^DESCRIPTION:
** Ck_cmd_errs will check for the improper specification of arguments
** from the command-line.
**
** ^REQUIREMENTS:
** The command-line should already have been parsed by parseargs(3)
**
** ^SIDE-EFECTS:
** - Exits the program if an error is encountered.
** - Assigns any needed defaults for StrTrue and StrFalse.
** - Gets the argd-string from an environment variable if needed
** (or sets UseStdin if it is to be read from standard input)
** - Determines the shell specified by the user (default=Bourne)
**
** ^RETURN-VALUE:
** e_SUCCESS if everything checks out all right
** Exits with one of the following exit-codes upon failure:
**
** e_SYNTAX : command-line sytntax error
**
** e_NOENV : AN environment variable was "purported" to contain the
** description string that describes all the arguments but
** upon examination, the variable was unset or empty.
**
** ^ALGORITHM:
** - make sure only one of '-a', '-e', and '-f' was given
** - turn OFF UseStdin if any of the above were given
** - make sure only one of '-l' and '-o' was given
** - if '-e' was specified, read the environment-variable and
** make sure it is non-NULL and non-empty
** - assign default values for StrTrue and StrFalse if they were not
** supplied on the command-line
** - determine the type of the user's shell
** - return
***^^**********************************************************************/
#ifdef __ANSI_C__
X static int ck_cmd_errs( void )
#endif
{
X /* make sure certain arg-combos were NOT used */
X if ( (ArgdString && (ArgdFname || ArgdEnv)) || (ArgdFname && ArgdEnv) ) {
X eprintf( "%s: only one of `-a', `-e', or `-f' may be given.\n\n",
X Cmd_Name );
X usage( Args );
X exit( e_SYNTAX );
X }
X
X /* make sure at least ONE of KeyWords and Options are enabled */
X if ( OptsOnly && KwdsOnly ) {
X eprintf( "%s: only one of `-o' or `l' may be given.\n\n",
X Cmd_Name );
X exit( e_SYNTAX );
X }
X
X /* turn OFF UseStdin if `-a', `-e', or `-f' was given */
X if (ArgdString || ArgdEnv || ArgdFname)
X UseStdin = FALSE;
X
X /* get the argd-string from an environment variable if so specified */
X if ( ArgdEnv ) {
X ArgdString = getenv( ArgdEnv );
X if ( !ArgdString || !*ArgdString ) {
X eprintf( "%s: variable \"%s\" is NULL or does not exist\n",
X Cmd_Name, ArgdEnv);
X exit( e_NOENV );
X }
X }
X
X /* set up default boolean value strings if needed */
X if ( !StrTrue ) {
X StrTrue = (char *)Default_StrTrue;
X }
X if ( !StrFalse ) {
X StrFalse = (char *)Default_StrFalse;
X }
X
X /* see if we need to "default" the shell name */
X if ( !PrUsage && !PrManual ) {
X if ( !ShellName ) {
X UsrSh = SH; /* default to Bourne Shell */
X }
X else {
X UsrSh = get_shell_type( basename( ShellName ) );
X }
X }
X
X /* everything is a-ok */
X return e_SUCCESS;
} /* ck_cmd_errs */
X
X
/***************************************************************************
** ^FUNCTION: main
**
** ^SYNOPSIS:
** main( argc, argv )
**
** ^PARAMETERS:
** int argc;
** -- the number of argumenst on the command-line
**
** char *argv[];
** -- the NULL terminated vector of arguments from the command-line
** (the first of which is the name of the paraseargs(1) command).
**
** ^DESCRIPTION:
** This is the main program for parseargs(1). It parses the user's command-
** line and outputs the approriate variable assignment statements (or prints
** a usage message or manual template).
**
** ^REQUIREMENTS:
** All the static local variables that are used to define the argument
** table and the values it points to (for parseargs(1) not for the user's
** command) should be properly initialized).
**
** ^SIDE-EFFECTS:
** Shell variable assignment statements, A usage message, or a manual
** page template is printed on standard output. Any diagnostic messages
** are printed on standard error.
**
** ^RETURN-VALUE:
** Execution is terminated and the corresponding exit-code is returned
** to the calling progarm (see the RETURN-CODES section).
**
** ^ALGORITHM:
** - save the name of this program
** - parse the command-line
** - read the argument descriptor string into memory (if needed)
** - build the argument and value tables
** - set ProgName to the name of the user's program
** - if need to print usage, then do so and exit with status e_USAGE
** - if need to print manual template, then do so, exit-status=e_USAGE
** - modify parsing-behavior as specified on the command-line
** - parse the user's command-line arguments
** - unset the positional parameters if required
** - print thye resulting shell variable assignments
** - deallocate any remaining storage
** - exit, status=e_SUCCESS
***^^**********************************************************************/
MAIN( argc, argv )
{
X int rc;
X argMask_t flags = pa_ARGV0;
X
X Cmd_Name = *argv = basename( *argv );
X
X /* parse command-line */
X parseargs( argv, Args );
X
X /* see if there is any reason to exit now */
X (VOID) ck_cmd_errs();
X
X /* set desired option-syntax */
X if ( KwdsOnly ) BSET(flags, pa_KWDSONLY);
X if ( OptsOnly ) BSET(flags, pa_OPTSONLY);
X
X /* if needed - allocate and read in the argument descriptor string */
X if ( !ArgdString ) {
X ArgdString = get_argtable_string();
X if ( ArgdString ) {
X strrtrim( ArgdString, WhiteSpace );
X if ( !*ArgdString ) ArgdString = CHARNULL;
X }
X }
X
X /* fill in the argument tables from the environment variable */
X if ( ArgdString ) UsrArgc = build_tables( ArgdString );
X
X /* if no arguments or options taken, use NULL */
X if ( !UsrArgc ) UsrArgd = ARGDESCNULL;
X
X ProgName = UsrName; /* set up program name */
X
X if ( PrUsage ) { /* just print usage and exit */
X usage( UsrArgd );
X }
X else if ( PrManual ) { /* print man pages and exit */
X manpage( UsrArgd );
X }
X else { /* parse callers command-line & print variable settings */
X if ( Prompt ) BSET(flags, pa_PROMPT);
X if ( Ignore ) BSET(flags, pa_IGNORE);
X if ( flags ) (VOID) parsecntl( UsrArgd, pc_PARSEFLAGS, pc_WRITE, flags );
X
X if ( (rc = parseargs( UsrArgv.array, UsrArgd )) != 0 ) {
X if ( rc > 0 ) {
X rc = e_SYNTAX;
X }
X else { /* (rc < 0) means a system error */
X cleanup();
X if ( errno ) perror( UsrName );
X exit( e_SYSTEM );
X }
X }/*if*/
X
X if ( Unset ) unset_positional_parameters();
X
X print_args( UsrVals, UsrArgd );
X }
X
X cleanup();
X exit( rc );
} /* main */
SHAR_EOF
echo 'File parseargs/parseargs.c is complete' &&
chmod 0664 parseargs/parseargs.c ||
echo 'restore of parseargs/parseargs.c failed'
Wc_c="`wc -c < 'parseargs/parseargs.c'`"
test 70264 -eq "$Wc_c" ||
echo 'parseargs/parseargs.c: original size 70264, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/parseargs.h ==============
if test -f 'parseargs/parseargs.h' -a X"$1" != X"-c"; then
echo 'x - skipping parseargs/parseargs.h (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/parseargs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/parseargs.h' &&
/*************************************************************************
** ^FILE: parseargs.h -- definitions for argument parsing library
**
** ^DESCRIPTION:
** This file contains all the necessary macros, type, and function
** declarations necessary to use the parseargs library. For most purposes,
** no special symbols need be #defined before including this file; however,
** for implementors (and more sophisticated uses), the following symbols
** may be #defined before including this file in order to include/exclude
** various portions of the file:
**
** PARSEARGS_PRIVATE
** Include private definitions that are needed to implement/enhance
** various functions in the parseargs library.
**
** PARSEARGS_NEXTERNS
** Do NOT include the external function declarations for the members
** of the parseargs library.
**
** PARSEARGS_NARGTYPES
** Do NOT include the external function declarations any of the
** pre-defined argument-type (argXxxx) functions.
**
** ^HISTORY:
** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com>
** - Added all the #ifdef stuff
** - Added public and private macros for getting and setting
** the attributes of an argdesc-array and an argdesc
**
** --/--/-- Peter da Silva <peter@ferranti.com>
**
** --/--/-- Eric P. Allman <eric@Berkeley.EDU> Created
***^^**********************************************************************/
X
/* $Header: parseargs.h,v 2.0 89/12/24 00:56:29 eric Exp $ */
X
#ifndef PARSEARGS_H
#define PARSEARGS_H
X
#include <useful.h>
X
X /* type definition for argument prompt strings */
#define MAX_ARGNAME 80
typedef char argName_t[ MAX_ARGNAME ];
X
X /* type definition for bitmasks */
typedef unsigned short argMask_t;
X
/**********************************************************************
** ^STRUCT: ARGDESC - argument-descriptor
**
** ^DESCRIPTION:
** The basic type used by the parseargs library is the argument descriptor
** (or "argdesc" for short). An ARGDESC structure is used to describe a
** command-line argument. Each command line argument contains various
** fields which need to be set and/or queried by the programmer. Each
** field is described in further detail below:
*/
typedef struct _argdesc {
X char ad_name;
/* -- This is a single character which corresponds to the option-letter
** (case-sensitive) from the command-line that matches the argument
** described by this structure. Positional-arguments are denoted by
** putting a a space character in this field.
*/
X argMask_t ad_flags;
/* -- This field contains the various bitflags that describe the semantics
** of this argument. See the ARGFLAGS section for more information on
** the possible combinations of bitmasks for this field.
*/
X BOOL (*ad_type) ARGS((struct _argdesc *, char *, BOOL));
/* -- This field is a pointer to a type conversion function (such as the
** ones provided in argtype(3). The type conversion function is respon-
** sible for verifying the validity of the argument, allocating any
** necessary storage for its internal representation, and converting
** the command-line argument into its required internal form. The type
** conversion function used may be one of the pre-defined argtype(3)
** functions. The function is given three parameters: The first is
** a pointer to the ARGDESC struct in question, the second is the
** string-value (if any) supplied on the command-line, and the third
** is a boolean value that is TRUE only if the second parameter points
** to temporary storage (and hence may need to be copied).
** In the case of parseargs(1) this field must correspond to the name
** of one of the argument type functions described in argtype(3).
*/
X ARBPTR ad_valp;
/* -- This field is a generic pointer to the storage used to represent
** the internal value of the command-line argument. It may be a
** pointer to a number, a boolean value, a string, a list, or anything
** else for which there exists a corresponding arg-type function to
** use in the ad_type field. In the case of of parseargs(1) this field
** must be the name of the corresponding shell variable which eventually
** hold the value of the argument given on the command-line.
*/
X CONST char *ad_prompt;
/* -- This field contains the long-name of the argument and an optional
** description (the description must be separated from the long-name by
** at least one whitespace characters and may optionally be enclosed in
** a set of balanced delimiters (such as parentheses, curly-braces,
** square-brackets, or angle-brackets. If the long-name contains any
** uppercase characters, then the substring of long-name consisting of
** all uppercase characters is used as the argument name and the entire
** long-name is used as the name of the argument-value (if a value my be
** supplied). The long-name may be matched by supplying a unique prefix
** of either the argument name or the argument-value name.
*/
} ARGDESC;
/**^^**********************************************************************/
X
X
X /* define a NULL pointer to an arg-descriptor */
#define ARGDESCNULL (ARGDESC *)NULL
X
X /* define a pointer to an argtype function */
typedef BOOL (*argTypePtr_t) ARGS((ARGDESC *, char *, BOOL));
X
X
/**********************************************************************
** ^SECTION: RETURN-CODES
** The XparseXXXX functions in the parseargs library may return any of
** the following return codes (which are #define'd below):
*/
#define pe_SYSTEM -1
/* -- a system error occurred. The global variable errno may indicate
** the problem (then again, it may not).
*/
#define pe_SUCCESS 0
/* -- success, no errors encountered.
*/
#define pe_SYNTAX 1
/* -- a command-line syntax error was encountered
*/
#define pe_DEFARGS 2
/* -- an attempt (using parsecntl()) was made to change the
** default arg-search list of a command to point to an argdesc-array
** which already has the given command on its default arg-search list
** (which would cause an infinite loop when attempting to match an
** unknown command-line argument).
*/
#define pe_NOMATCH 3
/* -- unable to match the named argument. This occurs
** when the argument keyword name passed to parsecntl() (using the
** pc_ARGFLAGS functions code) was found in the given argdesc-array
** or in its default-list.
*/
#define pe_BADMODE 4
/* -- bad mode for given command in parsecntl(). This occurs when
** pc_WRITE or pc_RDWR mode is passed to parsecntl() in conjunction
** with the pc_ARGFLAGS functions code. Parsecntl will not modify
** existing arguments.
*/
#define pe_BADCNTL 5
/* -- bad command for parsecntl. This occurs if an unknown function-code
** was passed to parsecntl().
*/
#define pe_BADOPEN 6
/* -- error opening file
*/
#define pe_BADREAD 7
/* -- error reading file
*/
/**^^**********************************************************************/
X
X
/**********************************************************************
** ^SECTION: ARGUMENT-FLAGS
** These are the possible bitmasks that may be turned ON or OFF in
** the ad_flags field of an ARGDESC structure.
*/
#define ARGOPT 0x0000
/* -- This flag is actually a dummy flag (i.e. it is the default). This flag
** specifies that the command-line argument is optional (need not appear
** on the command-line). It is only needed if no other flags are used to
** define the given argument. If other flags are given and ARGREQ is NOT
** one of them, then ARGOPT is always assumed.
*/
#define ARGREQ 0x0001
/* -- The associated command argument is required on the command-line.
*/
#define ARGPOS 0x0002
/* -- The associated command argument is positonal. The difference between
** using this flag to indicate a positional argument and between using
** a blank in the ad_name field to indicate a positional arguments is
** the following: If this flag is set but the ad_name of the argument
** is non-blank, then this argument may be matched either positionally
** or by keyword. If the ad_name field is blank, then this argument may
** only be matched positionally.
*/
#define ARGNOVAL 0x0004
/* -- The associated command argument takes no value (as in "-x value");
** Its mere presence (or lack thereof) on the command-line is sufficient
** to determine the necessary action(s) to take (as in "-x").
**
** NOTE: all argBool, and arg[STU]Bool arguments are always forced to be
** ARGNOVAL (as are argUsage arguments).
*/
#define ARGVALOPT 0x0008
/* -- This flag is used to indicate that the command-line argument takes a
** value (as in "-s string" or "/str=string") but that the value to this
** command-line argument is NOT required (hence simply "-s" or "/str" is
** also permissable).
*/
#define ARGVALREQ 0x0000
/* -- Another "dummy" flag. Unless ARGNOVAL or ARGVALOPT is specified,
** ARGVALREQ is always assumed. This flag indicates that the value to a
** command-line argument is required (hence "-s string" is okay but just
** "-s" is not).
*/
#define ARGHIDDEN 0x0010
/* -- Don't display this argument in usage messages but still attempt to
** match it against strings given on the command-line.
*/
#define ARGLIST 0x0020
/* -- A variable number of values are used for this argument (and hence may
** use more than one or two argv elements from the command-line as in
** "-l val1 val2 ..."). The list of values must be stored in an arglist
** structure (NOT a vector structure), an the corresponding argument-type
** function should be one of the listXxxx functions.
*/
#define ARGVEC 0x0040
/* -- A variable number of values are used for this argument (and hence may
** use more than one or two argv elements from the command-line as in
** in "-v val1 val2 ..."). The list of values must be stored in a vector
** structure (NOT an arglist structure).
*/
X
/* The following bitmasks may also be present, but, unlike the above masks
** which must be specified by the programmer at initialization time, the
** following masks must only be read (never set) by the programmer:
*/
#define ARGGIVEN 0x0080
/* -- The argument WAS given on the command-line.
*/
#define ARGVALGIVEN 0x0100
/* -- The value for this argument was given on the command-line.
*/
#define ARGVALSEP 0x0200
/* -- The value to this argument was supplied in a separate argv element
** from the argument itself (as in "-x value" as opposed to "-xvalue").
*/
#define ARGKEYWORD 0x0400
/* -- This argument was matched as a keyword (long-form) on the command-line
** and not as a single character.
*/
#define ARGDESCRIBED 0x0800
/* -- This argument was given a description by the programmer at
** initialization.
*/
#define ARGCOPYF 0x1000
/* -- This flag is only used for lists and vectors (multivalued arguments)
** and is used on a per-item basis. If it is set, it means that the
** corresponding value in the vector/list required space to be allocated
** (such as the duplication of a temporary string).
*/
/**^^**********************************************************************/
X
X
/**********************************************************************
** ^SECTION: ARGDESC-MACROS
** The following macros are used to extract and query the attributes
** of a pointer to a preprocessed arg-descriptor:
*/
#define arg_cname(ad) ((ad) -> ad_name)
/* -- return the single-character name of an argument.
*/
#define arg_flags(ad) ((ad) -> ad_flags)
/* -- return the argument flags of an argument. The flags themselves
** may be manipulated using the BTEST, BSET, and BCLEAR macros
** #defined in <useful.h>.
*/
#define arg_type(ad) ((ad) -> ad_type)
/* -- return the pointer to the value-translation-routine of an argument.
*/
#define arg_valp(ad) ((ad) -> ad_valp)
/* -- return the pointer to the value of this argument.
*/
#define arg_sname(ad) ((ad) -> ad_prompt)
/* -- return the string name of an argument.
*/
#define arg_sdesc(ad) ( arg_sname(ad) + strlen(arg_sname(ad)) + 1 )
/* -- return the description of an argument. If a description was supplied,
** the ARGDESCRIBED flag will be set and the description will immediately
** follow the NUL byte of the string name.
*/
#define ARG_isDESCRIBED(ad) BTEST( arg_flags(ad), ARGDESCRIBED )
/* -- Evaluates to TRUE only if an argument description was provided.
*/
#define arg_description(ad) ( ARG_isDESCRIBED(ad) ? arg_sdesc(ad) : "" )
/* -- Return the description string (or an empty string if no description
** was given) for this argument.
*/
#define ARG_isPOSITIONAL(ad) BTEST( arg_flags(ad), ARGPOS )
/* -- Evaluates to TRUE if this argument may be positionally matched.
*/
#define ARG_isPOSONLY(ad) ( arg_cname(ad) == ' ' )
/* -- Evaluates to TRUE if this argument may only be positionally matched.
*/
#define ARG_isLIST(ad) ( BTEST(arg_flags(ad), ARGLIST) )
/* -- Evaluates to TRUE if this argument is an arglist.
*/
#define ARG_isVEC(ad) ( BTEST(arg_flags(ad), ARGVEC) )
/* -- Evaluates to TRUE if this argument is a vector.
*/
#define ARG_isMULTIVAL(ad) ( BTEST(arg_flags(ad), ARGVEC | ARGLIST) )
/* -- Evaluates to TRUE if this argument is an arglist or a vector.
*/
#define ARG_isVALTAKEN(ad) ( ! BTEST(arg_flags(ad), ARGNOVAL) )
/* -- Evaluates to TRUE if this argument does NOT take a value.
*/
#define ARG_isGIVEN(ad) ( BTEST(arg_flags(ad), ARGGIVEN) )
/* -- Evaluates to TRUE if this argument was given on the command-line.
*/
#define ARG_isVALGIVEN(ad) ( BTEST(arg_flags(ad), ARGVALGIVEN) )
/* -- Evaluates to TRUE if the argument value was given on the command-line.
*/
#define ARG_isREQUIRED(ad) ( BTEST(arg_flags(ad), ARGREQ) )
/* -- Evaluates to TRUE if this argument is required.
*/
#define ARG_isVALOPTIONAL(ad) ( BTEST(arg_flags(ad), ARGVALOPT) )
/* -- Evaluates to TRUE if the argument value is optional.
*/
#define ARG_isVALSEPARATE(ad) ( BTEST(arg_flags(ad), ARGVALSEP) )
/* -- Evaluates to TRUE if the argument value is optional.
*/
#define ARG_isHIDDEN(ad) ( BTEST(arg_flags(ad), ARGHIDDEN) )
/* -- Evaluates to TRUE if this argument is omitted from usage messages.
*/
/**^^**********************************************************************/
X
X
X /* macro to define a NULL argument-type function */
#define argNULL (argTypePtr_t)NULL
X
X /* macro for an empty argument descriptor */
#define ARG_EMPTY { '\0', 0x0000, argNULL, ARBNULL, CHARNULL }
X
X /*
X ** macro to denote start & end of an ARGDESC array declared without
X ** the CMD_XXXXXXX macros which follow.
X */
#define STARTOFARGS ARG_EMPTY
#define ENDOFARGS ARG_EMPTY, ARG_EMPTY
X
/***************************************************************************
** ^SECTION: CMD-MACROS
** Parseargs.h defines a set of macros to allow a more "self documenting"
** approach to declaring argument-descriptor arrays. The "old-style" is
** still accepted (but if used it is recommended that the STARTOFARGS
** macro is used in conjunction with ENDOFARGS). An example use of these
** macros (which, with one exception, all begin with "CMD") follows:
**
** #include <parseargs.h>
**
** static BOOL bflag = FALSE;
** static char *arg1 = CHARNULL;
** static char *arg2 = CHARNULL;
**
** static
** CMD_OBJECT
** MyCmd
**
** CMD_NAME
** "mycmd -- one line statement of purpose"
**
** CMD_DESCRIPTION
** "Mycmd will try really really hard to run without errors \
** and do whatever the heck it is supposed to do. If (God forbid) \
** something should actually go wrong it will say so."
**
** CMD_ARGUMENTS
** 'b', ARGOPT, argSBool, __ &bflag,
** "bflag -- turn on `b'-mode (whatever that is)",
**
** ' ', ARGREQ, argStr, __ &arg1,
** "arg1 -- first argument to this spiffy program",
**
** ' ', ARGOPT, argStr, __ &arg2,
** "arg2 -- optional second argument to this spiffy program",
**
** END_ARGUMENTS
** CMD_END
**
** main( argc, argv )
** int argc;
** char *argv[];
** {
** (void) parseargs( argv, MyCmd );
** (void) dostuff();
** exit( 0 );
** }
***^^**********************************************************************/
#define CMD_OBJECT ARGDESC
#define CMD_NAME [] = { { '\0', (argMask_t)0x0000, (argTypePtr_t)
#define CMD_DESCRIPTION , ARBNULL,
#define CMD_ARGUMENTS },
#define START_ARGUMENTS ARG_EMPTY
#define END_ARGUMENTS ARG_EMPTY
#define CMD_END };
X
X /*
X ** shorthand for declaring main program
X */
#ifdef __ANSI_C__
# define MAIN(argc,argv) int main( int argc, char *argv[] )
#else
# define MAIN(argc,argv) int main( argc, argv ) int argc; char *argv[];
#endif
X
/***************************************************************************
** ^SECTION: MULTI-VALUED_ARGUMENTS
** Parseargs supports two different types of multi-valued arguments:
** linked-lists and vectors. The linked-lists are called argument lists
** (or arg-lists) and are specified by supplying the ARGLIST flag along
** with an associated listXxxx argument-translation routine. The value
** associated with an arg-list should be a list structure of type ArgList.
** The include file <parseargs.h> defines four macros for manipulating
** ArgList structures: ARGLISTNULL, L_NEXT, L_STRING, and L_FLAGS.
**
** ARGLISTNULL is simply the NULL argument-list pointer. L_NEXT and
** L_STRING each take a pointer to a non-NULL ArgList structure. L_NEXT
** returns the address of the next item in the list and L_STRING returns
** the string-value of the current list-item. L_FLAGS return the arg-
** flags for a given item in the list. With non-multivalued, only the
** flags in the argument descriptor are needed; lists and vectors however
** need a set of flags for each item they contain. Once an arg-list has
** been created, it may be deallocated using the function listFree. List-
** Free takes two parameters, the first of which is the address of the
** first item in the arg-list, and the second of which is a boolean value
** that is TRUE only if each value pointed to by each item should also be
** deallocated.
**
** An alternative to argument-lists is argument vectors (or arg-vectors).
** Arg-vectors use the ARGVEC flag instead of the ARGLIST flag and do not
** require a special listXxxx function for each vector-type. Each of the
** argXxxx functions is responsible for handling vectors of its type
** (although some argXxx functions such as the boolean types do not sup-
SHAR_EOF
true || echo 'restore of parseargs/parseargs.h failed'
fi
echo 'End of part 6'
echo 'File parseargs/parseargs.h is continued in part 7'
echo 7 > _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.