v17i047: parseargs - functions to parse command line arguments, Part02/12

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


Submitted-by: Brad Appleton <brad at hcx1.ssd.csd.harris.com>
Posting-number: Volume 17, Issue 47
Archive-name: parseargs/part02

This is part 2 of parseargs

#!/bin/sh
# this is Part.02 (part 2 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file parseargs/README continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 2; 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/README'
else
echo 'x - continuing file parseargs/README'
sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/README' &&
X
X The cmd_xxx macros are included only if PARSEARGS_PRIVATE is #defined.
X
X Similarly, there are also some macros (some public, some private) to
X query certain attributes of an argument descriptor (or assist in its
X manipulation). The public macros are documented in the manual pages,
X private ones are listed here:
X
X     ARG_isBOOLEAN(ad) -- is this arg an argBool, or an arg[STU]Bool type?
X     ARG_isPSEUDOARG(ad) -- is this arg an argDummy or an argUsage type?
X     ARG_FIRST(argd) -- return the first argument-entry
X     ARG_LAST(argd) -- return the first last-entry
X     ARG_isEND(ad) -- are we at the end of the argument list?
X     ARG_ADVANCE(ad) -- return the next argument entry.
X     ARG_RETREAT(ad) -- return the previous argument entry.
X
X
X These last five macros are for traversing all the entries in the
X argument descriptor array that correspond to actual command-line
X arguments (i.e. the 2nd thru 2nd-to-last entries in the array):
X
X     for ( ad = ARG_FIRST(argd) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) )  ...
X or
X     for ( ad = ARG_LAST(argd) ; !ARG_isEND(ad) ; ARG_RETREAT(ad) )  ...
X
X
X OPERATING SYSTEM DEPENDENCIES
X =============================
X I also added "-D${os}_style" to the CFLAGS macro used in the Makefile.
X It is used to conditionally include OS dependent code in the parseargs
X files. I tried to keep "#ifdef <os>_style" sections of code to a
X minimum.
X
X I tried to make a distinction between portions of the code that depend
X upon the underlying OS and portions of the code that depend on the
X desired argument parsing style so that - in theory - one could compile
X for any of the existing styles on any of the supported systems. Thus,
X just because "unix_style" is #defined does not necessarily imply that
X the underlying OS is unix. This would only be implied if "unix" was
X #defined.
X
X It is assumed that the following constants are #defined for the
X following operating systems:
X
X        NAME                        OS
X    ------------------   ------------------------
X     unix                Unix (BSD or AT&T)
X     BSD, ucb_universe   BSD Unix (only one need be present)
X     MANX, AZTEC         AmigaDOS
X     MSDOS               MS-DOS for IBM PCs
X     OS2                 OS/2 for IBM PCs
X     vms                 VAX/VMS
X
X As of this writing, as long as the above constants are defined for the
X corresponding OS, parseargs compiles without errors on both BSD and
X AT&T Unix Systems using both ANSI and non-ANSI C Compilers.
X
X
X IBM-PC VERSION OF parseargs(3)
X ==============================
X I also added ibm_args.c for MS-DOS and OS/2.
X
X IBM_ARGS.C HAS NOT BEEN TESTED ON AN IBM-PC! I did not have one to
X test it on.
X
X The ibm-pc version is VERY similar to the unix version. The difference
X is that ibm_args.c will look in $SWITCHAR for the option character(s)
X to use. If the option character is '-', it behaves just like
X unix_args.c, if the option character is something else or $SWITCHAR is
X undefined then it behaves more like normal MS-DOS stuff. The main
X difference is that if the ibm-pc version is NOT emulating unix, than
X all option arguments MUST be in the same argument as the option itself
X and they must be separated by an '=' character (so "/S=str" is fine
X but "/Sstr" and "/S str" are not).
X
X By default, if SWITCHAR is undefined then both the long and short
X option prefix character are '/'. One is able to distinguish an option
X from a long-option in this case because the third character of an
X option-arg will always be '=' or ' '. Hence, using the test program
X with the defaults, both "ibm_test foo /D=directory" and "ibm_test
X /DIR=directory" are equivalent.
X
X
X VAX/VMS VERSION OF parseargs(3)
X ===============================
X I also added vms_args.c for VAX/VMS.
X
X VMS_ARGS.C HAS NOT BEEN TESTED ON A VMS SYSTEM!!! I did not have one
X to test it on. It should accept command-line arguments as described in
X the "Grammar Rules" section of the VAX manual but I  cant guarantee
X anything so you'll have to test it out for yourself.
X
X ARGLIST and ARGVEC are comma-separated lists in the VMS version of
X parseargs (not whitespace separated lists). In order to preserve a
X one-to-one mapping between UNIX & AmigaDOS whitespace separated lists
X with VMS comma-separated lists, a  VMS ARGLIST or ARGVEC that
X corresponds to a positional parameter may use both commas and white-
X space to separate its arguments. This avoids having VMS command lines
X like the following:
X
X     cmdname file1,file2,file3 directory1,directory2
X
X for which there exists no corresponding command-line for UNIX or or
X AmigaDOS programs without changing the standard command-line syntax
X for these systems.
X
X In addition to a help option in the default argument descriptor, The
X VMS version of parseargs(3) also has /OUTPUT, /INPUT, and /ERROR
X qualifiers in the standard default argument-descriptor array. These
X all serve to redirect stdin, stdout, or stderr to or from a file (many
X thanks to posters from comp.os.vms for giving me a clue on how to do
X this). As a result of this, under VAX/VMS, there are two new argtype
X functions "argInput" and "argOutput": each requires that ad->ad_valp
X be a  file pointer (not a pointer to a file pointer as in "__ &stdin"
X but an actual file pointer as in "__ stdin"). ArgInput and argOutput
X close the stream associated with the given file-pointer and reconnect
X the stream to the named file for input or output (so the effect is to
X redirect input (output) from (to) the stream to the named file. If
X redirection fails, the original stream remains closed (sorry -- its a
X side-effect of freopen()).
X
X One can implement a "negatable" vms qualifier by using two entries in
X the argument descriptor table as follows:
X
X     'F', ARGOPT, argSBool, __ &myflag, "FLAG {set flag}",
X     'f', ARGOPT, argUBool, __ &myflag, "NOFLAG {unset flag}",
X
X so that /FLAG will turn the flag on (via argBool or argSBool) and
X /NOFLAG will turn it off (via argUBool).
X
X I did not know what to do (if anything) to add the VAX/VMS shell (DCL)
X into the parseargs command-line interface (parseargs(1)) so it is not
X currently implemented. I  will leave the task of configuring
X parseargs(1) for DCL programmers to some other brave soul who knows
X more than I about DCL! I was thinking that for DCL, the parseargs
X command could directly set the value of a symbol (with the proper
X scope of course) at execution time instead of printing something on
X stdout that would be evaluated later (as the UNIX version does).
X
X Anyone who uses VAX/VMS is strongly encouraged to test vms_args.c on
X their system (and make changes if need be) and to modify the usage and
X parsing functions accordingly!!! It would probably be a good idea to
X use some builtin VMS system call to replace the method used for
X finding the basename of a file (basename() in strfuncs.c) when "#ifdef
X vms" is true. There are also some command-line parsing routines
X available through DCL that could replace a  lot of the guts of
X vms_args.c as well.
X
X
X LITERATE PROGRAMMING
X ====================
X If you look at the source code you will notice that it contains lots
X of funny looking comments with sections that have titles enclosed
X between '^' and ':' characters. This is my own feeble attempt at
X literate programming. I  have a Unix-shell script which will extract
X certain portions of these "structured" comments so that I  may dump
X them directly into the documentation (and thus attempt to keep the
X documentation up-to-date at the same rate as the source). If anyone
X is interested in my script(s) please let me know and I will gladly e-
X mail them to the interested parties.
X
X
X ACKNOWLEDGEMENTS
X ================
X I was in constant contact with Peter Da Silva during the entire period
X that I  implemented all of the above modifications and would like to
X thank him for his time and his sage advice.
X
X Thanx also to Jim Barbour for helping me with some VMS specific things
X (like getting the original, unparsed command-line from DCL and
X retreiving the value of a symbol), and to Tom Christiansen and Raymond
X Chen for their help in getting parseargs(1) to work for perl scripts.
X
X Lastly, thanks to all those who use and will continue to improve
X parseargs, all I ask is that you keep me updated of your efforts (so I
X can keep my own version of parseargs up-to-date). I am always eager
X to discuss possible changes or enhancements with any interested
X parties.
X
SHAR_EOF
echo 'File parseargs/README is complete' &&
chmod 0664 parseargs/README ||
echo 'restore of parseargs/README failed'
Wc_c="`wc -c < 'parseargs/README'`"
test 41278 -eq "$Wc_c" ||
	echo 'parseargs/README: original size 41278, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/amiga_args.c ==============
if test -f 'parseargs/amiga_args.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/amiga_args.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/amiga_args.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/amiga_args.c' &&
/*************************************************************************
** ^FILE: amiga_args.c - parse AmigaDOS argument vectors
**
** ^DESCRIPTION:
**    This file contains the routines used to parse AmigaDOS argument
**    vectors and to print AmigaDOS usage messages.
**
** ^HISTORY:
**    01/02/91 	Brad Appleton 	<brad at ssd.csd.harris.com>
**    - Added structured block comments
**    - Added optional arguments to keywords
**
**    --/--/--  Peter da Silva  <peter at ferranti.com>    Created
***^^**********************************************************************/
X
#include <ctype.h>
#include <useful.h>
#include "strfuncs.h"
#include "pgopen.h"
X
#define PARSEARGS_PRIVATE   /* include private definitions */
#include "parseargs.h"
X
EXTERN  VOID  syserr       ARGS((const char *, ...));
EXTERN  VOID  usrerr       ARGS((const char *, ...));
EXTERN  char *getenv       ARGS((const char *));
EXTERN  VOID  get_winsize  ARGS((int, int *, int *));
X
VERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
X
/***************************************************************************
** ^GLOBAL-VARIABLE: Usage_Requested
**
** ^VISIBILITY:
**    static-global (visible to all functions in this file).
**
** ^DESCRIPTION:
**    Indicates whether a usage message was requested by the user
**    (as opposed to triggerred by a syntax error).  If the message
**    is requested by the user then it is always printed in verbose
**    mode and does not return an error-status-code.
***^^**********************************************************************/
static  BOOL  Usage_Requested = FALSE;
X
X
/***************************************************************************
** ^FUNCTION: amiga_parse - parse Amiga_DOS arg-vectors
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   int amiga_parse( argv, argd )
/*
** ^PARAMETERS:
*/
X   char *argv[];
/*    -- the vector of string arguments from the command-line
*/
X   ARGDESC argd[];
/*    -- the programmer description of the command and its args
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Amiga_parse will parse the arguments in the given vector of strings,
**    assign the corresponding values to the command-line arguments specified
**    in argd, and check the syntax of the command-line.
**
** ^REQUIREMENTS:
**    The final element in argv must be a NULL pointer.
**
** ^SIDE-EFECTS:
**    argd is modified according to the command-line description and parameters
**
** ^RETURN-VALUE:
**    pe_SUCCESS (0) if no errors are encountered
**    pe_SYSTEM (-1) if a system error is encountered
**    pe_SYNTAX if a syntax error is encountered
**
** ^ALGORITHM:
**    - for each command-line argument
**       - attempt to match the argument as a keyword
**       - if it is a keyword argument
**          - record and convert its value (if any)
**         else it is a positional parameter
**          - record and convert its value (if any)
**         else there are too many arguments
**          - return pe_SYNTAX
**         end-if
**       end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int amiga_parse( char **argv, ARGDESC argd[] )
#endif
{
X   register ARGDESC *cmd, *args, *ad = ARGDESCNULL;
X   register char **av;
X   register char *p = CHARNULL;
X   argName_t   keyword;
X   argMask_t   flags;
X   int  parse_error = pe_SUCCESS;
X   BOOL is_match = FALSE;
X
X   if ( !argd )  return  parse_error;
X
X      /* initialize command-structure */
X   if ( !CMD_isINIT(argd) )  init_args( argd );
X   cmd = argd;
X   cmd_prev(cmd) = ARGDESCNULL;
X
X      /* run through the argument vector */
X   for ( av = argv ; *av ; av++ ) {
X      char c = '\0';
X
X         /* If looking for keywords, see if this is one */
X      if( !BTEST(cmd_state(cmd), ps_NOFLAGS) ) {
X         p = strpbrk(*av, s_ARG_SEP);
X         if ( p ) {
X            c = *p;
X            *p++ = '\0';  /* skip past arg-separator character */
X         }
X
X         is_match = FALSE;
X         for ( args = argd ; args  &&  !is_match ; args = cmd_defargs(args) ) {
X            for (ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
X               if (arg_type(ad) == argDummy)  continue;
X
X               if (!ARG_isPOSONLY(ad)  &&  match(*av, arg_sname(ad)) == 0) {
X                  is_match = TRUE;
X                  break;
X               }/*if*/
X            }
X         }
X
X         if ( !is_match )  ad = ARGDESCNULL;
X      }/*if !NOFLAGS*/
X
X      if (c)  *(p-1) = c;  /* restore the equal sign */
X
X         /* If we have a keyword here */
X      if( !BTEST(cmd_state(cmd), ps_NOFLAGS)  &&  ad) {
X         if ( cmd_prev(cmd) ) { /* a value may have been given but wasnt */
X            if ( ARG_isVALOPTIONAL(cmd_prev(cmd)) ) {
X               BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN );
X            }
X            else {  /* value was required */
X               (VOID)get_keyword( arg_sname(cmd_prev(cmd)), keyword );
X               usrerr( "value required for %s keyword", keyword );
X               parse_error = pe_SYNTAX;
X            }
X            cmd_prev(cmd) = ARGDESCNULL;
X         }
X
X         if ( cmd_list(cmd) ) { /* end of list */
X            cmd_list(cmd) = ARGDESCNULL;
X         }
X
X         flags = arg_flags(ad);    /* save flags */
X         if ( ARG_isGIVEN(ad) )    /* reset flags for this appearance */
X            BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP );
X
X         if ( p ) { /* matched NAME=VALUE */
X            if ( ARG_isMULTIVAL(ad) )
X               cmd_list(cmd) = ad;
X            else
X               cmd_list(cmd) = ARGDESCNULL;
X
X               /* try to convert the type */
X            if ( !HANDLE(ad, p, cmd_flags(cmd)) ) {
X               arg_flags(ad) = flags;  /* restore flags */
X               parse_error = pe_SYNTAX;
X            }
X            else
X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
X            ad = ARGDESCNULL;
X         }
X         else {
X            if (arg_type(ad) == argUsage) {
X               Usage_Requested = TRUE;
X               usage(argd);
X               exit(1);
X            }
X            else if (arg_type(ad) == argEnd) {
X               BSET( cmd_state(cmd), ps_NOFLAGS );
X               BSET( arg_flags(ad), ARGGIVEN );
X            }
X            else if ( ARG_isVALTAKEN(ad) ) {
X               cmd_prev(cmd) = ad;
X            }
X            else if ( !HANDLE(ad, CHARNULL, cmd_flags(cmd)) ) {
X               arg_flags(ad) = flags;  /* restore flags */
X               parse_error = pe_SYNTAX;
X            }
X            else {
X               BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
X            }
X            ad = ARGDESCNULL;
X         }/*else*/
X      }
X      else if (cmd_prev(cmd)) {
X         flags = arg_flags(cmd_prev(cmd));    /* save flags */
X         if ( ARG_isGIVEN(cmd_prev(cmd)) )    /* reset flags */
X            BCLEAR( arg_flags(cmd_prev(cmd)), ARGVALGIVEN | ARGVALSEP );
X
X            /* previous value may have required a keyword */
X         BSET( arg_flags(cmd_prev(cmd)), ARGVALSEP );
X
X         if ( ARG_isMULTIVAL(cmd_prev(cmd)) )
X            cmd_list(cmd) = cmd_prev(cmd);
X         else
X            cmd_list(cmd) = ARGDESCNULL;
X
X            /* try to convert the type */
X         if ( !HANDLE(cmd_prev(cmd), *av, cmd_flags(cmd)) ) {
X            arg_flags(cmd_prev(cmd)) = flags;  /* restore flags */
X            parse_error = pe_SYNTAX;
X         }
X         else
X            BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN | ARGVALGIVEN );
X
X         ad = ARGDESCNULL;
X         cmd_prev(cmd) = ARGDESCNULL;
X         continue;
X      }
X      else {  /* it's a positional argument or a list item */
X         if (cmd_list(cmd)) { /* its a list item */
X            flags = arg_flags(cmd_list(cmd));    /* save flags */
X            if ( ARG_isGIVEN(cmd_list(cmd)) )    /* reset flags */
X               BCLEAR( arg_flags(cmd_list(cmd)), ARGVALGIVEN | ARGVALSEP );
X
X            BSET( arg_flags(cmd_list(cmd)), ARGVALSEP );
X
X            if ( !HANDLE(cmd_list(cmd), *av, cmd_flags(cmd)) ) {
X               arg_flags(cmd_list(cmd)) = flags;  /* restore flags */
X               parse_error = pe_SYNTAX;
X            }
X
X            BSET( arg_flags(cmd_list(cmd)), ARGGIVEN | ARGVALGIVEN );
X            continue;
X         }
X         else {  /* its a positional argument */
X            if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) )
X               BSET( cmd_state(cmd), ps_NOFLAGS );
X
X            is_match = FALSE;
X            for ( args = argd; args && !is_match; args = cmd_defargs(args) ) {
X               for (ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad)) {
X                  if (arg_type(ad) == argDummy)  continue;
X
X                  if ( ARG_isPOSITIONAL(ad)  &&
X                       (!ARG_isGIVEN(ad) || ARG_isMULTIVAL(ad)) ) {
X                     is_match = TRUE;
X                     break;
X                  }/*if*/
X               }
X            }
X
X            if ( !is_match ) {
X               usrerr("too any arguments");
X               parse_error = pe_SYNTAX;
X               ad = ARGDESCNULL;
X            }
X            else {
X               flags = arg_flags(ad);    /* save flags */
X               if ( ARG_isGIVEN(ad) )    /* reset flags for this appearance */
X                  BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP );
X
X               BSET( arg_flags(ad), ARGVALSEP );
X
X                  /* try to convert */
X               if ( !HANDLE(ad, *av, cmd_flags(cmd)) ) {
X                  arg_flags(ad) = flags;  /* restore flags */
X                  parse_error = pe_SYNTAX;
X               }
X               else
X                  BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
X               ad = ARGDESCNULL;
X            }
X         }/*else positional*/
X      }/*else not keyword*/
X   }/*while*/
X
X   /* If last argument was a keyword and required an option
X   ** then complain about it
X   */
X   if ( cmd_prev(cmd) ) { /* a value may have been given but wasnt */
X      if ( ARG_isVALOPTIONAL(cmd_prev(cmd)) ) {
X         BSET( arg_flags(cmd_prev(cmd)), ARGGIVEN );
X      }
X      else {  /* value was required */
X         (VOID)get_keyword( arg_sname(cmd_prev(cmd)), keyword );
X         usrerr( "value required for %s keyword", keyword );
X         parse_error = pe_SYNTAX;
X      }
X      cmd_prev(cmd) = ARGDESCNULL;
X   }
X
X   return  parse_error;
}
X
X
/***************************************************************************
** ^FUNCTION: fmtarg - format command-argument syntax
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static int fmtarg(ad, buf)
/*  
** ^PARAMETERS:
*/
X   ARGDESC *ad;
/*    -- pointer to the argument to format
*/
X   char *buf;
/*    -- character buffer to hold the formatted result
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Fmtarg will determine the proper command-line syntax for the
**    given argument and write the result to the given buffer.
**
** ^REQUIREMENTS:
**    buf must be large enough to hold the formatted result (100 characters
**    should do the trick).
**
** ^SIDE-EFECTS:
**    buf is overwritten.
**
** ^RETURN-VALUE:
**    The number of printable characters in the argument-syntax-string
**
** ^ALGORITHM:
**    Print argument usage based on whether or not the argument is
**    positional, hidden, multi-valued (list or vector), etc ....
**    Optional arguments and values are enclosed in square braces.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   static int fmtarg( const ARGDESC *ad, char *buf )
#endif
{
X      /* buf must already be large enough */
X   char * pos;
X   argName_t  keyword, name;
X
X   (VOID) get_name(arg_sname(ad), name);
X
X   if ( ARG_isPOSITIONAL(ad) ) {
X      sprintf( buf, "<%s>", name );
X   }
X   else {
X      (VOID) get_keyword(arg_sname(ad), keyword);
X      (VOID) strcpy( buf, keyword );
X      pos = buf + strlen(buf);
X
X      if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
X         if ( ARG_isVALOPTIONAL(ad) )
X            sprintf( pos, " [<%s>]", name );
X         else
X            sprintf( pos, " <%s>", name );
X      }
X   }/*else*/
X
X   return  strlen(buf);
}
X
X
/***************************************************************************
** ^FUNCTION: amiga_usage - print a usage message
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   VOID amiga_usage( argd, usage_flags )
/*  
** ^PARAMETERS:
*/
X   ARGDESC *argd;
/*    -- the command-descriptor array
*/
X   argMask_t usage_flags;
/*    -- flags set by $USAGECNTL
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Amiga_usage will print the AmigaDOS command-line usage of the given
**    command on standard diagnostic output (stderr). The content of the
**    usage message is controlled by the bitmasks in usage_flags which
**    correspond to the settings in the user's USAGECNTL variable.
**
** ^REQUIREMENTS:
**    argd should be a non-null command-line argument-descriptor array
**
** ^SIDE-EFECTS:
**    Prints on stderr.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    - if no usage is desired then exit
**    - if paging is requested print to the pager instead of stderr
**    - print the command-line syntax
**    - if the description is requested print it
**    - if verbose mode is requested, print the description of each argument
***^^**********************************************************************/
#ifdef __ANSI_C__
X   void amiga_usage( const ARGDESC *argd, argMask_t usage_flags )
#endif
{
X   register CONST ARGDESC  *ad, *args, *cmd;
X   int  max_cols = 80, max_lines  = 24;
X   int  margin, ll, pl, keywords, longest, positionals;
X   BOOL first = TRUE;
X   FILE *fp;
X
X   if ( !argd )  return;
X
X      /* initialize command-structure */
X   if ( !CMD_isINIT(argd) )  init_args( (ARGDESC *)argd );
X   cmd = argd;
X
X      /* force verbose-mode if requested */
X   if ( Usage_Requested )   BSET( usage_flags, usg_VERBOSE );
X
X   if ( BTEST(usage_flags, usg_NONE) )  return;
X
X   fp = ( BTEST(usage_flags, usg_PAGED) )
X      ? pgopen( stderr, getenv("USAGE_PAGER") )
X      : stderr;
X
X      /* get screen size */
X   get_winsize( fileno(stderr), &max_lines, &max_cols );
X
X   fprintf(fp, "Format: %s", ProgName);
X   ll = strlen( ProgName ) + 8;
X   margin = ll + 1;
X   longest = 0;
X
X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
X            argName_t  buf;
X
X               /* don't display hidden arguments */
X            if ( ARG_isHIDDEN(ad) )  continue;
X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
X
X               /* figure out how wide this parameter is (for printing) */
X            pl = fmtarg(ad, buf);
X
X            if ( pl > longest)  longest = pl;
X
X            if ( !ARG_isREQUIRED(ad) ) {
X               pl += 2;  /* [] */
X            }
X            if ( ARG_isMULTIVAL(ad) ) {
X               strcat( buf, "..." );
X               pl += 3;
X            }
X
X               /* see if this will fit */
X            if ( (ll + pl + 1) > (max_cols - first) ) {
X                  /* no... start a new line */
X               fprintf(fp, "\n%*s", margin, "");
X               ll = margin;
X            }
X            else {
X                  /* yes... just throw in a space */
X               fputc(' ', fp);
X               ++ll;
X            }
X            ll += pl;
X
X               /* show the argument */
X            if ( !ARG_isREQUIRED(ad) )  fputc('[', fp);
X            fprintf(fp, buf);
X            if ( !ARG_isREQUIRED(ad) )  fputc(']', fp);
X
X            first = FALSE;  /* not first line anymore */
X         }/*for each ad */
X      }/* for each argd */
X   }/* for each parm-type */
X
X   fputc('\n', fp);
X
X   if ( BTEST(usage_flags, usg_DESCRIPTION) ) {
X      CONST char *description = cmd_description(cmd);
X
X      if ( description  &&  *description ) {
X         fprintf( fp, "Description:\n" );
X         indent_para(fp, max_cols, 8, "", 0, description);
X         fputc( '\n', fp );
X      }
X   }/*if*/
X
X   if ( !BTEST(usage_flags, usg_VERBOSE) )  {
X      if ( pgactive(fp) )  (VOID) pgclose( fp );
X      return;
X   }
X
X   keywords = 0;
X   for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
X      for ( args = argd ; args ; args = cmd_defargs(args) ) {
X         for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
X            argName_t  buf;
X
X               /* don't display hidden arguments */
X            if ( ARG_isHIDDEN(ad) )  continue;
X            if ( !positionals  &&  ARG_isPOSITIONAL(ad) )  continue;
X            if ( positionals  &&  !ARG_isPOSITIONAL(ad) )  continue;
X
X            if( !(keywords++) )  fprintf(fp, "Keywords/Arguments:\n");
X            (VOID) fmtarg(ad, buf);
X            indent_para(fp, max_cols, 8, buf, longest+2, arg_description(ad));
X         }/*for each ad */
X      }/* for each argd */
X   }/* for each parm-type */
X
X   if ( pgactive(fp) )  (VOID) pgclose( fp );
}
SHAR_EOF
chmod 0664 parseargs/amiga_args.c ||
echo 'restore of parseargs/amiga_args.c failed'
Wc_c="`wc -c < 'parseargs/amiga_args.c'`"
test 16890 -eq "$Wc_c" ||
	echo 'parseargs/amiga_args.c: original size 16890, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/arglist.c ==============
if test -f 'parseargs/arglist.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/arglist.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/arglist.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/arglist.c' &&
/*************************************************************************
** ^FILE: arglist.c - argList manipulation routines.
**
** ^DESCRIPTION:
**    This file contains routines to add an item to the end of an arglist,
**    and to delete all items in an arglist.
**
** ^HISTORY:
**    01/02/91	Brad Appleton	<brad at ssd.csd.harris.com>
**       - Added structured comments
**       - Changed arglists to always be kept in FIFO order (hence
**         reverse_list() and cleanup_list() were no longer needed).
**         The lists are maintained in FIFO order by forcing the very
**         first item of the list to maintain an additional link to the
**         last item of the list (to make it easy to append an item).
**       - Added listFree() function
**
**    --/--/--	Peter da Silva	<peter at ferranti.com>	Created
***^^**********************************************************************/
X
#include <stdio.h>
#include <ctype.h>
#include <useful.h>
#include "strfuncs.h"
X
#define  PARSEARGS_NARGTYPES  /* exclude arg-type externs */
#include "parseargs.h"
X
EXTERN  VOID    syserr  ARGS((const char *, ...));
EXTERN  VOID    usrerr  ARGS((const char *, ...));
X
/***************************************************************************
** ^FUNCTION: listStr - string-list argument translation routine
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   BOOL listStr( ad, vp, copyf )
/*  
** ^PARAMETERS:
*/
X   ARGDESC *ad;
/*    -- the argument descriptor for this parameter.
*/
X   char *vp;
/*    -- a pointer to the string input value.
*/
X   BOOL copyf;
/*    -- if TRUE, the value will be destroyed later, and so should
**       be copied if it will be retained (as for a string).
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    ListStr converts a string-parameter value into its internal form,
**    including validity checking. If <copyf> is TRUE then <vp> is copied
**    to the end of the list, otherwise <vp> itself is placed at the end.
**
** ^REQUIREMENTS:
**    <ad> must point to the argdesc element corresponding to the matched
**    string-list argument. The ad_valp field of ad MUST be either NULL or
**    point to a valid arglist-head structure.
**
** ^SIDE-EFECTS:
**    If successful, arglist pointed to by arg_valp(ad) is appended with
**    the given string, <vp> is unchanged.
**
** ^RETURN-VALUE:
**    TRUE -- if the conversion was successful.  The actual
**            value should be added appended to the list.
**    FALSE -- if the conversion failed.  The reason for failure
**             should be diagnosed using usrerr().
**
** ^ALGORITHM:
**    - verify the validity of <vp> as a string argument
**    - if ( isEmpty(arglist) )
**       - allocate a listhead structure
**       - assign the item pointer to <vp> (or a copy of <vp>)
**       - assign the NEXT and LAST elements to NULL
**    - else
**       - allocate a new arglist structure and append it after
**         listhead.LAST
**       - assign listhead.LAST to the address of the new item
**       - assign the NEXT element of the new item to NULL
**      end-if
***^^**********************************************************************/
#ifdef __ANSI_C__
X   BOOL listStr( ARGDESC *ad, char *vp, BOOL copyf )
#endif
{
X   char *cp;
X   BOOL  badalloc = FALSE;
X   argName_t   argname;
X   ArgListHead *nl;
X   ArgList *nd;
X
X   (VOID) get_name( arg_sname(ad), argname );
X   if (copyf) {
X      register int i;
X
X      i = strlen(vp) + 1;
X      cp = (char *) malloc(i * sizeof(char));
X      if(!cp) {
X         usrerr("out of memory saving string %s", argname );
X         return FALSE;
X      }
X      memcpy(cp, vp, i);
X   }
X   else {
X      cp = vp;
X   }
X
X      /* if list is empty - need to new up a listhead,
X      ** otherwise just use a normal link.
X      */
X   nl = *((ArgListHead **) arg_valp(ad));
X   if ( nl ) {
X      nd = (ArgList *) malloc( sizeof(ArgList) );
X      if ( !nd )  badalloc = TRUE;
X   }
X   else {
X      nl = (ArgListHead *) malloc( sizeof(ArgListHead) );
X      nd = (ArgList *)NULL;
X      if ( !nl )  badalloc = TRUE;
X   }
X
X   if ( badalloc ) {
X      usrerr("out of memory saving arg %s", arg_sname(ad));
X      if(copyf) free(cp);
X      return FALSE;
X   }
X
X   if ( nd ) {
X      nl -> nl_tail -> nl_next = (ArgList *)nd;
X      nl -> nl_tail  = (ArgList *)nd;
X      nd -> nl_next  = (ArgList *)NULL;
X      nd -> nl_val   = (ARBPTR)cp;
X      nd -> nl_flags = arg_flags(ad);
X      if ( copyf )  BSET( nd->nl_flags, ARGCOPYF );
X   }
X   else {
X      *((ArgListHead **) arg_valp(ad)) = nl;
X      nl -> nl_tail  = (ArgList *)nl;
X      nl -> nl_next  = (ArgList *)NULL;
X      nl -> nl_val   = (ARBPTR)cp;
X      nl -> nl_flags = arg_flags(ad);
X      if ( copyf )  BSET( nl->nl_flags, ARGCOPYF );
X   }
X
X   return (TRUE);
}
X
X
/***************************************************************************
** ^FUNCTION: listFree - free the items in an arglist
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   VOID listFree( argls )
/*  
** ^PARAMETERS:
*/
X   ArgList *argls;
/*    -- the list to be freed
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    ListFree will free storage for each node in <argls>. Furthermore,
**    if <copyf> is true then the actual storage for each item in the
**    list is also released.
**
** ^REQUIREMENTS:
**    argls must point to a valid arglist-head structure.
**
** ^SIDE-EFECTS:
**    each item in argls is removed, argls itself should be set to NULL
**    after this routine is invoked.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    - For each node in argls
**       - if ( copyf ) free the item storage
**       - free the node
**      end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
X   void listFree( ArgList *argls )
#endif
{
X   register  ArgList *ls = argls;
X   ArgList  *nd;
X
X   if ( !ls )  return;
X
X   while ( ls ) {
X      nd = L_NEXT(ls);
X      if ( BTEST(L_FLAGS(ls), ARGCOPYF) )  free( ls->nl_val );
X      free( ls );
X      ls = nd;
X   }/*while*/
}
X
SHAR_EOF
chmod 0664 parseargs/arglist.c ||
echo 'restore of parseargs/arglist.c failed'
Wc_c="`wc -c < 'parseargs/arglist.c'`"
test 5961 -eq "$Wc_c" ||
	echo 'parseargs/arglist.c: original size 5961, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/argtype.c ==============
if test -f 'parseargs/argtype.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/argtype.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/argtype.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/argtype.c' &&
/*************************************************************************
** ^FILE: argtype.c - argument type definitions for parseargs(3)
**
** ^DESCRIPTION:
**    This file implements the argument conversion functions for
**    converting string, character, integer, floating-point,
**    boolean, and pseudo-arguments, from command-line strings.
**
** ^HISTORY:
**    01/03/91	Brad Appleton	<brad at ssd.csd.harris.com>
**       - Added structured block comments
**       - Added argUsage & argDummy dummy-functions
**       - Added argSBool, argTBool, and argUBool
**       - Added ARGVEC handling to all necessary functions
**       - Added argInput & argOutput for VMS
**       - put floating-point routines (argFloat & argDouble) into
**         this file (they may be excluded by #defining NOFLOAT)
**       - changed routines to return negative values (where appropriate)
**
**    --/--/--	Peter da Silva	<peter at ferranti.com>
**
**    --/--/--	Eric P. Allman	<eric at Berkeley.EDU> 	Created
***^^**********************************************************************/
X
#include <ctype.h>
#include <useful.h>
#include "strfuncs.h"
X
#define PARSEARGS_NARGTYPES  /* exclude arg-type externs */
#include "parseargs.h"
X
#ifdef __ANSI_C__
# define  PARMS(ad,vp,copyf) \
X	( register ARGDESC *ad,  register char *vp,  BOOL copyf )
#else
# define  PARMS(ad,vp,copyf) \
X	( ad, vp, copyf )  register ARGDESC *ad;  register char *vp;  BOOL copyf;
#endif
X
#define REALLOC(ptr,size)  (( ! ptr ) ? malloc(size) : realloc(ptr, size) )
EXTERN  VOID    syserr  ARGS((const char *, ...));
EXTERN  VOID    usrerr  ARGS((const char *, ...));
EXTERN  long    strtol  ARGS((char *, char **, int));
EXTERN  double  strtod  ARGS((const char *, char **));
X
X
/***************************************************************************
** ^FUNCTION: argtype -- argument translation routines.
**
** ^SYNOPSIS:
**    BOOL  argUsage( ad, vp, copyf )
**    BOOL  argEnd( ad, vp, copyf );
**    BOOL  argDummy( ad, vp, copyf );
**    BOOL  argBool( ad, vp, copyf );
**    BOOL  argSBool( ad, vp, copyf );
**    BOOL  argUBool( ad, vp, copyf );
**    BOOL  argTBool( ad, vp, copyf );
**    BOOL  argChar( ad, vp, copyf );
**    BOOL  argStr( ad, vp, copyf );
**    BOOL  argInt( ad, vp, copyf );
**    BOOL  argShort( ad, vp, copyf );
**    BOOL  argLong( ad, vp, copyf );
**    BOOL  argFloat( ad, vp, copyf );
**    BOOL  argDouble( ad, vp, copyf );
**    BOOL  argInput( ad, vp, copyf );
**    BOOL  argOutput( ad, vp, copyf );
**
** ^PARAMETERS:
**    ARGDESC *ad;
**    -- the argument descriptor for this parameter.
**
**    char *vp;
**    -- a pointer to the string input value.
**
**    BOOL  copyf;
**    -- if TRUE, the value will be destroyed later, and so should be copied
**       if it will be retained (as for a string).
**
** ^DESCRIPTION:
**    Each of these converts a parameter value to the internal form, includ-
**    ing validity checking.  Their parameters and return values all behave
**    similarly. One of these routines are called when an argunent of that
**    particular type is matched by one of the argument parsing function in
**    parseargs(3). When such an argument is matched, its argument transla-
**    tion routines is invoked and is passed (1) the address of the argument
**    descriptor for the matched argument, (2) the possible argument string
**    for that matched argument, and (3) a boolean filed that is TRUE only
**    if the second parameter points to temporary storage (indicating that
**    some copying may need to be done instead of just pointing to the same
**    object).
**
**    Once the argument translation routine is invoked, it is responsible
**    for converting the argument string to the desired internal form
**    (perhaps a number), and assigning the resultant value to the
**    arg_valp(ad) field of the argument descriptor (this includes handling
**    any necessary (re)allocation if the matched argument has the ARGVEC
**    flag enabled). If the argument is an ARGVEC or ARGLIST then the rou-
**    tine is responsible for allocating any space, copying the arg-flags to
**    the value-specific flags, and setting the ARGCOPYF flag for the value
**    if it needs to be allocated as well.
**
** ^REQUIREMENTS:
**    ARGKEYWORD should be set if the argument was matched via its
**    string name (as opposed to by its character name).
**
**    ARGVALSEP should be set is the argument value was in a separate
**    argv element from the argument string-name (or character name).
**
** ^SIDE-EFFECTS:
**    The value used should be stored in the location indicated by arg_valp(ad).
**
** ^RETURN-VALUE:
**    TRUE : if the conversion was successful and the entire value was used.
**
**    FALSE : if the conversion failed.  The reason for failure should be
**            diagnosed using usrerr().
**
**    -N : if the conversion was successful but only N characters of the value
**         were used, the remaining characters may still match other arguments.
** 
** ^ALGORITHM:
**    Function-specific, but the basic idea is as follows:
**
**    - convert the value-string into the desired type
**    - if the value is invalid call usrerr and return FALSE
**      end-if
**    - if this ad is an ARGVEC
**        - expand the vector and insert the new item at the end
**        - update the item count
**    - else 
**        - set *ad_valp to the converted value
**      end-if
**    - return TRUE if we used the whole arg, -N if we only used N-characters
***^^**********************************************************************/
X
/* vector types and defines */
#define BLOCKSIZE  5    /* number of items to allocate at once */
#define VEC_SIZE(vec,el_typ)  ( sizeof(el_typ *) * (BLOCKSIZE + vec->count) )
typedef ARGVEC_T(char *)  strvec_t;
typedef ARGVEC_T(char)    charvec_t;
typedef ARGVEC_T(int)     intvec_t;
typedef ARGVEC_T(short)   shortvec_t;
typedef ARGVEC_T(long)    longvec_t;
typedef ARGVEC_T(float)   floatvec_t;
typedef ARGVEC_T(double)  doublevec_t;
X
X
/***************************************************************************
** ^SECTION: PSEUDO-TYPES -- argUsage, argEnd, argDummy
**    ArgUsage is used to specify an argument that causes the command
**    usage to be printed.
**
**    ArgDummy is used to force an item to show up in usage-messages but
**    the item itself is never matched against any argumenmts from the
**    command-line.
**
**    ArgEnd is used by amiga_args.c and vms_args.c to indicate an argument
**    that forces all remaining arguments to be considered positional args.
**
**    These three are dummy functions. The routines themselves do nothing
**    of importance, we just need to have their addresses available for
**    identification in the corresponding <os>_args.c file.
***^^**********************************************************************/
X
/*ARGSUSED*/
BOOL argDummy  PARMS(ad, vp, copyf)
{
X   return   FALSE;
}
X
X
/*ARGSUSED*/
BOOL argEnd  PARMS(ad, vp, copyf)
{
X   return (FALSE);
}
X
X
/*ARGSUSED*/
BOOL argUsage  PARMS(ad, vp, copyf)
{
X   return   FALSE;
}
X
X
/***************************************************************************
** ^SECTION: STRING-TYPES -- argStr
**    ArgStr is one of the few argument translation routines that actually
**    uses the <copyf> flag. If <copyf> is true then the string is duplicated.
**
**    ArgStr assigns the given string (or a copy of it) to the value referenced
**    by arg_valp(unless the argument is a vector in which case the given string
**    is appended to the end).
**
**    ArgStr ensures that the very last item in a vector of strings (the one
**    accessed as vec.array[ vec.count ]) will always be NULL.
***^^**********************************************************************/
X
/*ARGSUSED*/
BOOL argStr  PARMS(ad, vp, copyf)
{
X   char *cp;
X   argName_t  argname;
X
X   (VOID) get_name( arg_sname(ad), argname );
X   if (copyf) {
X      register int i;
X
X      i = strlen(vp) + 1;
X      cp = (char *) malloc(i * sizeof(char));
X      if (!cp) {
X         usrerr("out of memory parsing %s", argname);
X         return FALSE;
X      }
X      memcpy(cp, vp, i);
X   }
X   else
X      cp = vp;
X
X   if ( ARG_isVEC(ad) ) {
X      strvec_t  *vec = (strvec_t *)arg_valp(ad);
X
X      if ( (vec->count % BLOCKSIZE) == 0 ) {
X         vec->array = (char **) REALLOC(vec->array, 1+VEC_SIZE(vec, char *));
X         if ( !vec->array ) {
X            if ( copyf )  free(cp);
X            syserr("out of memory saving arg %s", argname);
X         }
X         vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
X         if ( !vec->flags ) {
X            syserr("out of memory saving arg %s", argname);
X         }
X      }
X
X      vec->flags[ vec->count ] = arg_flags(ad);
X      if ( copyf )  BSET( vec->flags[vec->count], ARGCOPYF );
X      vec->array[ (vec->count)++ ] = cp;
X      vec->array[ vec->count ] = (char *)NULL;
X   }
X   else
X      *(char **) arg_valp(ad) = cp;
X
X   return (TRUE);
}
X
X
/***************************************************************************
** ^SECTION: CHARACTER-TYPES -- argChar
**    ArgChar assigns the given character to the value referenced by ad_valp
**    (unless the argument is a vector in which case the given character
**    is appended to the end).
**
**    If an argChar argument is matched as a single character option, then
**    the immediately following character will be considered its argument
**    (but the characters after it may still be processed as option-letters).
**
**    ArgChar ensures that the very last item in a vector of character (the
**    one accessed as vec.array[ vec.count ]) will always be a NUL byte so
**    that the resulting vector may also be used as a NULL terminated string.
**
**    Unlike argStr, argChar will translate character escape sequences such
**    as '\n' and '\012'.
***^^**********************************************************************/
X
/*ARGSUSED*/
BOOL argChar  PARMS(ad, vp, copyf)
{
X   auto char *vpp;
X   argName_t  argname;
X   int status = FALSE;
X   char c;
X
X   (VOID) get_name( arg_sname(ad), argname );
X   if (!vp || !*vp) {
X      status = FALSE;
X   }
X   if (strlen(vp) == 2 && vp[0]=='^') {
X      c = vp[1] ^ '@';
X      status = TRUE;
X   }
X   else if (strlen(vp) > 1 && vp[0]=='\\') {
X      c = (int) strtol(&vp[1], &vpp, 8);
X      if (*vpp == '\0')
X         status = TRUE;
X   }
X   else if (strlen(vp) == 1) {
X      c = *vp;
X      status = TRUE;
X   }
X   else if ( !BTEST(arg_flags(ad), ARGVALSEP | ARGKEYWORD) ) {
X      c = *vp;
X      status = TRUE;
X   }
X
X   if ( status ) {
X      if ( ARG_isVEC(ad) ) {
X         charvec_t  *vec = (charvec_t *)arg_valp(ad);
X
X         if ( (vec->count % BLOCKSIZE) == 0 ) {
X            vec->array = (char *) REALLOC(vec->array, 1+VEC_SIZE(vec, char));
X            if (!vec->array)  syserr("out of memory saving arg %s", argname);
X         }
X         vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t));
X         if ( !vec->flags ) {
X            syserr("out of memory saving arg %s", argname);
X         }
X
X         vec->flags[ vec->count ] = arg_flags(ad);
X         vec->array[ (vec->count)++ ] = c;
X         vec->array[ vec->count ] = '\0';
X      }
X      else
X         *(char *) arg_valp(ad) = c;
X   }
X   else {
X      usrerr("invalid character argument '%s' for %s",
X         vp, argname);
X   }
X   return (status) ? (BOOL) -1 : FALSE;
}
X
X
/***************************************************************************
** ^SECTION: INTEGER-TYPES -- argInt, argShort, argLong
**    Each of these functions converts the given string to the desired
**    integral type. The value may be specified as an octal number by
**    specifying the first digit to be 0. Similarly, If the first two 
**    characters are '0x' then the number is treated as hexadecimal.
***^^**********************************************************************/
X
X   /*
X   ** macro to define an integral argtype function
X   **
X   ** NOTE : do NOT use a terminating semicolon when invoking this macro!
X   */
#define  INTEGRAL_ARGTYPE(name,num_t,ls_t) \
BOOL name  PARMS(ad, vp, copyf) \
{ \
X   auto char *vpp; \
X   argName_t  argname; \
X   num_t  value; \
X \
X   (VOID) get_name( arg_sname(ad), argname ); \
X   value = (num_t) strtol(vp, &vpp, 0); \
X   if (*vpp != '\0') { \
X      usrerr("invalid integer argument '%s' for %s", vp, argname); \
X      return (FALSE); \
X   } \
X   else { \
X      if ( ARG_isVEC(ad) ) { \
X         ls_t  *vec = (ls_t *)arg_valp(ad); \
X \
X         if ( (vec->count % BLOCKSIZE) == 0 ) { \
X            vec->array = (num_t *) REALLOC(vec->array, VEC_SIZE(vec, num_t)); \
X            if ( !vec->array ) \
X               syserr("out of memory saving arg %s", argname); \
X \
X            vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
X            if ( !vec->flags ) \
X               syserr("out of memory saving arg %s", argname); \
X         } \
X \
X         vec->flags[ vec->count ] = arg_flags(ad); \
X         vec->array[ (vec->count)++ ] = value; \
X      } \
X      else \
X         *(num_t *) arg_valp(ad) = value; \
X \
X      return (TRUE); \
X   } \
}
X
X
/* define argInt() */
INTEGRAL_ARGTYPE( argInt, int, intvec_t )
X
/* define argShort() */
INTEGRAL_ARGTYPE( argShort, short, shortvec_t )
X
/* define argLong() */
INTEGRAL_ARGTYPE( argLong, long, longvec_t )
X
X
#ifndef NOFLOAT
X
/***************************************************************************
** ^SECTION: FLOATING-POINT-TYPES -- argFloat, argDouble
**    Each of these functions converts the given string to the desired
**    floating-point type.
***^^**********************************************************************/
X
X   /*
X   ** macro to define a decimal argtype function
X   **
X   ** NOTE : do NOT use a terminating semicolon when invoking this macro!
X   */
#define  DECIMAL_ARGTYPE(name,dec_t,ls_t) \
BOOL name  PARMS(ad, vp, copyf) \
{ \
X   auto char *vpp; \
X   argName_t  argname; \
X   dec_t  value; \
X \
X   (VOID) get_name( arg_sname(ad), argname ); \
X   value = (dec_t) strtod(vp, &vpp); \
X   if (*vpp != '\0') { \
X      usrerr("invalid decimal argument '%s' for %s", vp, argname); \
X      return (FALSE); \
X   } \
X   else { \
X      if ( ARG_isVEC(ad) ) { \
X         ls_t  *vec = (ls_t *)arg_valp(ad); \
X \
X         if ( (vec->count % BLOCKSIZE) == 0 ) { \
X            vec->array = (dec_t *) REALLOC(vec->array, VEC_SIZE(vec, dec_t)); \
X            if (!vec->array) \
X               syserr("out of memory saving arg %s", argname); \
X \
X            vec->flags = (argMask_t *) REALLOC(vec->flags, VEC_SIZE(vec, argMask_t)); \
X            if (!vec->flags) \
X               syserr("out of memory saving arg %s", argname); \
X         } \
X \
X         vec->flags[ vec->count ] = arg_flags(ad); \
X         vec->array[ (vec->count)++ ] = value; \
X      } \
X      else \
X         *(dec_t *) arg_valp(ad) = value; \
X \
X      return (TRUE); \
X   } \
}
X
/* define argFloat */
DECIMAL_ARGTYPE( argFloat, float, floatvec_t )
X
/* define argLong */
DECIMAL_ARGTYPE( argDouble, double, doublevec_t )
X
#endif  /* NOFLOAT */
X
X
/*************************************************************************
** ^SECTION: BOOLEAN-TYPES -- argBool, argSBool, argUBool, argTBool
**    ArgBool and argSBool set a boolean value (if no value is given).
**    ArgUBool unsets a boolean value (if no value is given). ArgTBool
**    toggles a boolean value (if no value is given). If a value is
**    supplied to any of these routines, then the string is looked up
**    in a table and assigned the corresponding value.
**
**    If a value is supplied for an argument that was matched via its
**    single character name and is part of the same argv element as the
**    argument-name (so that both ARGKEYWORD and ARGVALSEP are not set),
**    then only the first character of the value is used (unless it is
**    not found in our table, in which case the value is ignored and the
**    default action is taken).
**
**    The only possible arguments for single-character options are the
**    following:
**
**       1, +         set the flag
**       0, -         unset the flag
**       ^, ~         toggle the flag
**
**    The possible argument strings for long-options (keywords) are as
**    follows (case-insensitive):
*/
X
X   /* define a structure for an item in our boolean-lookup table */
struct booltab {
X   char   *bname;      /* string to match against */
X   char   bneedmatch;  /* number of characters that must match */
X   BOOL   bval;        /* value to use */
};
X
X   /* define the boolean-lookup table */
STATIC struct booltab	_BoolTab[] = {
X   "1",      1,   TRUE,
X   "0",      1,   FALSE,
X   "+",      1,   TRUE,
X   "-",      1,   FALSE,
X   "yes",    1,   TRUE,
X   "no",     1,   FALSE,
X   "true",   1,   TRUE,
X   "false",  1,   FALSE,
X   "on",     2,   TRUE,
X   "off",    3,   FALSE,
X   CHARNULL
};
X
/**^^**********************************************************************/
X
X
X   /*
X   ** NOTE: Lists and vectors of Boolean types are not supported!!!
X   **       (same goes for argEnd, argInput, & argOutput)
X   */
X
/*ARGSUSED*/
BOOL argBool  PARMS(ad, vp, copyf)
{
X   register struct booltab *b;
X   register char *cp;
X   argName_t  argname;
X   int len;
X
X   (VOID) get_name( arg_sname(ad), argname );
X
X   /* ARGVECs are not supported for this Boolean arg-types */
X   if ( ARG_isVEC(ad) )
X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
X            argname );
X
X   /* if vp is NULL, just set to TRUE
X   **    (needed for backward compatibility)
X   */
X   if ( !vp || !*vp ) {
X      *(BOOL *) arg_valp(ad) = TRUE;
X      return (TRUE);
X   }
X
X      /* allow single character arguments for non-keywords */
X   if ( !BTEST(arg_flags(ad), ARGKEYWORD | ARGVALSEP) ) {
X      if ( *vp == '+' || *vp == '1' ) {
X         *(BOOL *) arg_valp(ad) = TRUE;
X         return (BOOL) -1;
X      }
X      if ( *vp == '-' || *vp == '0' ) {
X         *(BOOL *) arg_valp(ad) = FALSE;
X         return (BOOL) -1;
X      }
X      if ( *vp == '~' || *vp == '^' ) {
X         *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE;
X         return (BOOL) -1;
X      }
X
X         /* unmatched value, return FALSE for non-argBool (so the caller
X         ** can use whatever default) and return TRUE for argBool.
X         */
X      if ( arg_type(ad) == argBool ) {
X         *(BOOL *) arg_valp(ad) = TRUE;
X         return  TRUE;
X      }
X      return  FALSE;
X   }/* if single char option */
X
X   /* copy input & convert to lower case */
X   cp = strlwr( strdup(vp) );
X   len = strlen( cp );
X
X   /* search for a match in the table */
X   for (b = _BoolTab; b->bname ; b++) {
X      /* if too short, don't even bother trying */
X      if (len < b->bneedmatch)
X         continue;
X
X      if ( memcmp(cp, b->bname, len) == 0) {
X         /* got a match */
X         *(BOOL *) arg_valp(ad) = b->bval;
X         free( cp );
X         return (TRUE);
X      }
X   }/*if match*/
X
X   free( cp );
X   usrerr("invalid Boolean argument '%s' for %s", vp, argname);
X   return (FALSE);
}
X
X
/*ARGSUSED*/
BOOL argSBool  PARMS(ad, vp, copyf)
{
X   argName_t  argname;
X   BOOL  retval;
X
X   (VOID) get_name( arg_sname(ad), argname );
X
X   /* ARGVECs are not supported for this Boolean arg-types */
X   if ( ARG_isVEC(ad) )
X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
X            argname );
X
X   /* if vp is NULL, just set to TRUE */
X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
X      *(BOOL *) arg_valp(ad) = TRUE;
X      return (TRUE);
X   }
X   else
X      return  retval;
}
X
/*ARGSUSED*/
BOOL argUBool  PARMS(ad, vp, copyf)
{
X   argName_t  argname;
X   BOOL  retval;
X
X   (VOID) get_name( arg_sname(ad), argname );
X
X   /* ARGVECs are not supported for this Boolean arg-types */
X   if ( ARG_isVEC(ad) )
X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
X            argname );
X
X   /* if vp is NULL, just set to FALSE */
X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
X      *(BOOL *) arg_valp(ad) = FALSE;
X      return (TRUE);
X   }
X   else
X      return retval;
}
X
/*ARGSUSED*/
BOOL argTBool  PARMS(ad, vp, copyf)
{
X   argName_t  argname;
X   BOOL  retval;
X
X   (VOID) get_name( arg_sname(ad), argname );
X
X   /* ARGVECs are not supported for this Boolean arg-types */
X   if ( ARG_isVEC(ad) )
X      syserr( "Error in '%s' arg-entry! Boolean argvecs are not supported!",
X            argname );
X
X   /* if vp is NULL, just toggle value */
X   if ( !vp || !*vp || !(retval = argBool(ad, vp, copyf)) ) {
X      *(BOOL *) arg_valp(ad) = (*(BOOL *) arg_valp(ad)) ? FALSE : TRUE ;
X      return (TRUE);
X   }
X   else
X      return retval;
}
X
X
#ifdef vms_style
X
/***************************************************************************
** ^SECTION: I/O-REDIRECTION-TYPES -- argInput, argOutput
**    ArgInput attempts to redirect the file-pointer addressed by ad_valp
**    to the file named by the given value. The file is opened for reading.
**
**    ArgOutput attempts to redirect the file-pointer addressed by ad_valp
**    to the file named by the given value. The file is opened for writing.
**
**    In either case, ad_valp should be of type (FILE *) (and not a pointer
**    to a file pointer as in (FILE **)!!!
**
**    If the given files cannot be opened, then an error message is printed
**    and the associated input/output streams are closed.
***^^**********************************************************************/
X
/*ARGSUSED*/
BOOL argInput  PARMS(ad, vp, copyf)
{
X      /* note that ad_valp is a file pointer
X      ** (so dont use &fp in the arg-desc)
X      */
X   FILE *fp = (FILE *)arg_valp(ad);
X   BOOL error = FALSE;
X
X   /* redirect file pointer to read from file */
X   if ( !vp ) {
X      usrerr( "Error: no file name given" );
X      error = TRUE;
X   }
X
X   if ( !error  &&  !fp )
X      error = TRUE;
X   else if ( !error  &&  !freopen(vp, "r", fp) )
X      error = TRUE;
X
X   if ( error )  {
X      usrerr( "Error: unable to redirect input to file \"%s.\"", vp );
X      return  (FALSE);
X   }
X   return (TRUE);
}
X
X
/*ARGSUSED*/
BOOL argOutput  PARMS(ad, vp, copyf)
{
X      /* note that ad_valp is a file pointer
X      ** (so dont use &fp in the arg-desc)
X      */
X   FILE *fp = (FILE *)arg_valp(ad);
X   BOOL error = FALSE;
X
X   /* redirect file pointer to write to file */
X   if ( !vp ) {
X      usrerr( "Error: no file name given" );
X      error = TRUE;
X   }
X
X   if ( !error  &&  !fp )
X      error = TRUE;
X   else if ( !error  &&  !freopen(vp, "a", fp) )
X      error = TRUE;
X
X   if ( error )  {
X      usrerr( "Error: unable to redirect output to file \"%s.\"", vp );
X      return  (FALSE);
X   }
X   return (TRUE);
}
X
#endif  /* vms_style */
SHAR_EOF
chmod 0664 parseargs/argtype.c ||
echo 'restore of parseargs/argtype.c failed'
Wc_c="`wc -c < 'parseargs/argtype.c'`"
test 22590 -eq "$Wc_c" ||
	echo 'parseargs/argtype.c: original size 22590, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/argtype3.txt ==============
if test -f 'parseargs/argtype3.txt' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/argtype3.txt (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/argtype3.txt (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/argtype3.txt' &&
X
X
X
ARGTYPE(3)					       ARGTYPE(3)
X
X
X
NAME
X     argtype - argument	type functions used by parseargs(3)
X
SYNOPSIS
X     #include <parseargs.h>
X
X     BOOL  argUsage(  argdesc,	argstr,	 copyf	);
X     BOOL  argEnd(  argdesc,  argstr,  copyf  );
X     BOOL  argDummy(  argdesc,	argstr,	 copyf	);
X     BOOL  argBool(  argdesc,  argstr,	copyf  );
X     BOOL  argSBool(  argdesc,	argstr,	 copyf	);
X     BOOL  argUBool(  argdesc,	argstr,	 copyf	);
X     BOOL  argTBool(  argdesc,	argstr,	 copyf	);
X     BOOL  argChar(  argdesc,  argstr,	copyf  );
X     BOOL  argStr(  argdesc,  argstr,  copyf  );
X     BOOL  argInt(  argdesc,  argstr,  copyf  );
X     BOOL  argShort(  argdesc,	argstr,	 copyf	);
X     BOOL  argLong(  argdesc,  argstr,	copyf  );
X     BOOL  argFloat(  argdesc,	argstr,	 copyf	);
X     BOOL  argDouble(  argdesc,	 argstr,  copyf	 );
X     BOOL  listStr(  argdesc,  argstr,	copyf  );
X     void  listFree(  arglist  );
X     void  vecFree(  argvec, type  );
X     void  vecDeepFree(	 argvec, type  );
X
X     ARGDESC  *argdesc;
X     char  *argstr;
X     BOOL  copyf;
X     ArgList  *arglist;
X
DESCRIPTION
X     Each of these converts a parameter	value to the internal
X     form, including validity checking.	 Their parameters and
X     return values all behave similarly. One of	these routines
X     are called	when an	argunent of that particular type is
X     matched by	one of the argument parsing function in	par-
X     seargs(3).	When such an argument is matched, its argument
X     translation routines is invoked and is passed (1) the
X     address of	the argument descriptor	for the	matched	argument,
X     (2) the possible argument string for that matched argument,
X     and (3) a boolean filed that is TRUE only if the second
X     parameter points to temporary storage (indicating that some
X     copying may need to be done instead of just pointing to the
X     same object).
X
X     Once the argument translation routine is invoked, it is
X     responsible for converting	the argument string to the
X     desired internal form (perhaps a number), and assigning the
X     resultant value to	the arg_valp(ad) field of the argument
X     descriptor	(this includes handling	any necessary
X     (re)allocation if the matched argument has	the ARGVEC flag
X     enabled). If the argument is an ARGVEC or ARGLIST then the
X
X
X
Page 1
X
X
X
X
X
X
ARGTYPE(3)					       ARGTYPE(3)
X
X
X
X     routine is	responsible for	allocating any space, copying the
X     arg-flags to the value-specific flags, and	setting	the
X     ARGCOPYF flag for the value if it needs to	be allocated as
X     well.
X
X
RETURN VALUE
X     TRUE    The conversion was	successful and the entire value
X	     was used.
X
X
X     FALSE   The conversion failed.  The reason	for failure
X	     should be diagnosed using usrerr(3).
X
X
X     -N	     The conversion was	successful but only N characters
X	     of	the value were used, the remaining characters may
X	     still match other arguments.
X
X
PSEUDO-TYPES
X     ArgUsage is used to specify an argument that causes the com-
X     mand usage	to be printed.
X
X     ArgDummy is used to force an item to show up in usage-
X     messages but the item itself is never matched against any
X     argumenmts	from the command-line.
X
X     ArgEnd is used by Amiga style command-lines to indicate an
X     argument that forces all remaining	arguments to be	con-
X     sidered positional	args.
X
X     These three are dummy functions. The routines themselves do
X     nothing of	importance, we just need to have their addresses
X     available for identification in the corresponding command-
X     line styles.
X
STRING-TYPES
X     ArgStr is one of the few argument translation routines that
X     actually uses the copyf flag. If copyf is true then the
X     string is duplicated.
X
X     ArgStr assigns the	given string (or a copy	of it) to the
X     value referenced by arg_valp(ad) (unless the argument is a
X     vector in which case the given string is appended to the
SHAR_EOF
true || echo 'restore of parseargs/argtype3.txt failed'
fi
echo 'End of  part 2'
echo 'File parseargs/argtype3.txt is continued in part 3'
echo 3 > _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