v17i051: parseargs - functions to parse command line arguments, Part06/12

Brad Appleton brad at hcx1.ssd.csd.harris.com
Mon Mar 18 06:07:33 AEST 1991


Submitted-by: Brad Appleton <brad at 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 at 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 at ferranti.com>
**
**    --/--/--	Eric P. Allman	<eric at 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 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