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