home *** CD-ROM | disk | FTP | other *** search
- From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
- Newsgroups: comp.sources.misc
- Subject: v17i047: parseargs - functions to parse command line arguments, Part02/12
- Message-ID: <1991Mar17.200602.17757@sparky.IMD.Sterling.COM>
- Date: 17 Mar 91 20:06:02 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: 2bd96682 5a86dd46 98f7903c bf35aa67
-
- Submitted-by: Brad Appleton <brad@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@ssd.csd.harris.com>
- ** - Added structured block comments
- ** - Added optional arguments to keywords
- **
- ** --/--/-- Peter da Silva <peter@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@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@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@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@ferranti.com>
- **
- ** --/--/-- Eric P. Allman <eric@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@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-