home *** CD-ROM | disk | FTP | other *** search
- /*************************************************************************
- ** ^FILE: parseargs.h -- definitions for argument parsing library
- **
- ** ^DESCRIPTION:
- ** This file contains all the necessary macros, type, and function
- ** declarations necessary to use the parseargs library. For most purposes,
- ** no special symbols need be #defined before including this file; however,
- ** for implementors (and more sophisticated uses), the following symbols
- ** may be #defined before including this file in order to include/exclude
- ** various portions of the file:
- **
- ** PARSEARGS_PRIVATE
- ** Include private definitions that are needed to implement/enhance
- ** various functions in the parseargs library.
- **
- ** PARSEARGS_NEXTERNS
- ** Do NOT include the external function declarations for the members
- ** of the parseargs library.
- **
- ** PARSEARGS_NARGTYPES
- ** Do NOT include the external function declarations any of the
- ** pre-defined argument-type (argXxxx) functions.
- **
- ** ^HISTORY:
- ** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com>
- ** - added ps_NOTCMDLINE state-flag for vms_style
- **
- ** 08/27/91 Earl Chew <cechew@bruce.cs.monash.edu.au>
- ** - Add ProgNameLen
- ** - Promote ps_flags_t to unsigned short
- ** - Add new states ps_USERNAME, ps_USERPURPOSE, ps_FREENAME,
- ** ps_FREEPURPOSE
- ** - arg_sdesc() now only returns a raw string --- use get_argdesc()
- ** to extract the description from it
- **
- ** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com>
- ** - Added all the #ifdef stuff
- ** - Added public and private macros for getting and setting
- ** the attributes of an argdesc-array and an argdesc
- **
- ** --/--/-- Peter da Silva <peter@ferranti.com>
- **
- ** --/--/-- Eric P. Allman <eric@Berkeley.EDU> Created
- ***^^**********************************************************************/
-
- /* $Header: parseargs.h,v 2.0 89/12/24 00:56:29 eric Exp $ */
-
- #ifndef PARSEARGS_H
- #define PARSEARGS_H
-
- #include <useful.h>
-
- /* type definition for argument prompt strings */
- #define MAX_ARGNAME 80
- typedef char argName_t[ MAX_ARGNAME ];
-
- /* type definition for bitmasks */
- typedef unsigned short argMask_t;
-
- /**********************************************************************
- ** ^STRUCT: ARGDESC - argument-descriptor
- **
- ** ^DESCRIPTION:
- ** The basic type used by the parseargs library is the argument descriptor
- ** (or "argdesc" for short). An ARGDESC structure is used to describe a
- ** command-line argument. Each command line argument contains various
- ** fields which need to be set and/or queried by the programmer. Each
- ** field is described in further detail below:
- */
- typedef struct _argdesc {
- char ad_name;
- /* -- This is a single character which corresponds to the option-letter
- ** (case-sensitive) from the command-line that matches the argument
- ** described by this structure. Positional-arguments are denoted by
- ** putting a a space character in this field.
- */
- argMask_t ad_flags;
- /* -- This field contains the various bitflags that describe the semantics
- ** of this argument. See the ARGFLAGS section for more information on
- ** the possible combinations of bitmasks for this field.
- */
- BOOL (*ad_type) ARGS((struct _argdesc *, char *, BOOL));
- /* -- This field is a pointer to a type conversion function (such as the
- ** ones provided in argtype(3)). The type conversion function is respon-
- ** sible for verifying the validity of the argument, allocating any
- ** necessary storage for its internal representation, and converting
- ** the command-line argument into its required internal form. The type
- ** conversion function used may be one of the pre-defined argtype(3)
- ** functions. The function is given three parameters: The first is
- ** a pointer to the ARGDESC struct in question, the second is the
- ** string-value (if any) supplied on the command-line, and the third
- ** is a boolean value that is TRUE only if the second parameter points
- ** to temporary storage (and hence may need to be copied).
- ** In the case of parseargs(1) this field must correspond to the name
- ** of one of the argument type functions described in argtype(3).
- */
- ARBPTR ad_valp;
- /* -- This field is a generic pointer to the storage used to represent
- ** the internal value of the command-line argument. It may be a
- ** pointer to a number, a boolean value, a string, a list, or anything
- ** else for which there exists a corresponding arg-type function to
- ** use in the ad_type field. In the case of of parseargs(1) this field
- ** must be the name of the corresponding shell variable which will
- ** eventually hold the value of the argument given on the command-line.
- */
- CONST char *ad_prompt;
- /* -- This field contains the long-name of the argument and an optional
- ** description (the description must be separated from the long-name by
- ** at least one whitespace character and may optionally be enclosed in
- ** a set of balanced delimiters (such as parentheses, curly-braces,
- ** square-brackets, or angle-brackets). The longname may be specifed
- ** in two parts: a keyword name and an argument name. The argument
- ** name may be separated from the keyword name by a single equal sign
- ** ('='). No whitespace is allowed before or after the equal sign.
- ** Alternatatively, the keyword name may be distinguished from the
- ** argument name by character case: if the long-name contains any
- ** uppercase characters, then the substring of long-name consisting of
- ** all uppercase characters is used as the argument keyword and the
- ** entire long-name is used as the name of the argument (if a value may
- ** be supplied). The long-name may be matched by supplying a unique
- ** prefix of either the argument keyword or the argument name.
- */
- } ARGDESC;
- /**^^**********************************************************************/
-
-
- /* define a NULL pointer to an arg-descriptor */
- #define ARGDESCNULL (ARGDESC *)NULL
-
- /* define a pointer to an argtype function */
- typedef BOOL (*argTypePtr_t) ARGS((ARGDESC *, char *, BOOL));
-
-
- /**********************************************************************
- ** ^SECTION: RETURN-CODES
- ** The XparseXXXX functions in the parseargs library may return any of
- ** the following return codes (which are #define'd below):
- */
- #define pe_SYSTEM -1
- /* -- a system error occurred. The global variable errno may indicate
- ** the problem (then again, it may not).
- */
- #define pe_SUCCESS 0
- /* -- success, no errors encountered.
- */
- #define pe_SYNTAX 1
- /* -- a command-line syntax error was encountered
- */
- #define pe_DEFARGS 2
- /* -- an attempt (using parsecntl()) was made to change the
- ** default arg-search list of a command to point to an argdesc-array
- ** which already has the given command on its default arg-search list
- ** (which would cause an infinite loop when attempting to match an
- ** unknown command-line argument).
- */
- #define pe_NOMATCH 3
- /* -- unable to match the named argument. This occurs
- ** when the argument keyword name passed to parsecntl() (using the
- ** pc_ARGFLAGS function code) was NOT found in the given argdesc-array
- ** or in its default-list.
- */
- #define pe_BADMODE 4
- /* -- bad mode for given command in parsecntl(). This occurs when
- ** pc_WRITE or pc_RDWR mode is passed to parsecntl() in conjunction
- ** with the pc_ARGFLAGS functions code. Parsecntl will not modify
- ** existing arguments.
- */
- #define pe_BADCNTL 5
- /* -- bad command for parsecntl. This occurs if an unknown function-code
- ** was passed to parsecntl().
- */
- #define pe_BADOPEN 6
- /* -- error opening file
- */
- #define pe_BADREAD 7
- /* -- error reading file
- */
- /**^^**********************************************************************/
-
-
- /**********************************************************************
- ** ^SECTION: ARGUMENT-FLAGS
- ** These are the possible bitmasks that may be turned ON or OFF in
- ** the ad_flags field of an ARGDESC structure.
- */
- #define ARGOPT 0x0000
- /* -- This flag is actually a dummy flag (i.e. it is the default). This flag
- ** specifies that the command-line argument is optional (need not appear
- ** on the command-line). It is only needed if no other flags are used to
- ** define the given argument. If other flags are given and ARGREQ is NOT
- ** one of them, then ARGOPT is always assumed.
- */
- #define ARGREQ 0x0001
- /* -- The associated command argument is required on the command-line.
- */
- #define ARGPOS 0x0002
- /* -- The associated command argument is positonal. The difference between
- ** using this flag to indicate a positional argument and between using
- ** a blank in the ad_name field to indicate a positional arguments is
- ** the following: If this flag is set but the ad_name of the argument
- ** is non-blank, then this argument may be matched either positionally
- ** or by keyword. If the ad_name field is blank, then this argument may
- ** only be matched positionally.
- */
- #define ARGNOVAL 0x0004
- /* -- The associated command argument takes no value (as in "-x value");
- ** Its mere presence (or lack thereof) on the command-line is sufficient
- ** to determine the necessary action(s) to take (as in "-x").
- **
- ** NOTE: all argBool, and arg[STU]Bool arguments are always forced to be
- ** ARGNOVAL (as are argUsage arguments).
- */
- #define ARGVALOPT 0x0008
- /* -- This flag is used to indicate that the command-line argument takes a
- ** value (as in "-s string" or "/str=string") but that the value to this
- ** command-line argument is NOT required (hence simply "-s" or "/str" is
- ** also permissable).
- */
- #define ARGVALREQ 0x0000
- /* -- Another "dummy" flag. Unless ARGNOVAL or ARGVALOPT is specified,
- ** ARGVALREQ is always assumed. This flag indicates that the value to a
- ** command-line argument is required (hence "-s string" is okay but just
- ** "-s" is not).
- */
- #define ARGHIDDEN 0x0010
- /* -- Don't display this argument in usage messages but still attempt to
- ** match it against strings given on the command-line.
- */
- #define ARGLIST 0x0020
- /* -- A variable number of values are used for this argument (and hence may
- ** use more than one or two argv elements from the command-line as in
- ** "-l val1 val2 ..."). The list of values must be stored in an arglist
- ** structure (NOT a vector structure), an the corresponding argument-type
- ** function should be one of the listXxxx functions.
- */
- #define ARGVEC 0x0040
- /* -- A variable number of values are used for this argument (and hence may
- ** use more than one or two argv elements from the command-line as in
- ** in "-v val1 val2 ..."). The list of values must be stored in a vector
- ** structure (NOT an arglist structure).
- */
-
- /* The following bitmasks may also be present, but, unlike the above masks
- ** which must be specified by the programmer at initialization time, the
- ** following masks must only be read (never set) by the programmer:
- */
- #define ARGGIVEN 0x0080
- /* -- The argument WAS given on the command-line.
- */
- #define ARGVALGIVEN 0x0100
- /* -- The value for this argument was given on the command-line.
- */
- #define ARGVALSEP 0x0200
- /* -- The value to this argument was supplied in a separate argv element
- ** from the argument itself (as in "-x value" as opposed to "-xvalue").
- */
- #define ARGKEYWORD 0x0400
- /* -- This argument was matched as a keyword (long-form) on the command-line
- ** and not as a single character.
- */
- #define ARGDESCRIBED 0x0800
- /* -- This argument was given a description by the programmer at
- ** initialization.
- */
- #define ARGCOPYF 0x1000
- /* -- This flag is only used for lists and vectors (multivalued arguments)
- ** and is used on a per-item basis. If it is set, it means that the
- ** corresponding value in the vector/list required space to be allocated
- ** (such as the duplication of a temporary string).
- */
- /**^^**********************************************************************/
-
-
- /**********************************************************************
- ** ^SECTION: ARGDESC-MACROS
- ** The following macros are used to extract and query the attributes
- ** of a pointer to a preprocessed arg-descriptor:
- */
- #define arg_cname(ad) ((ad) -> ad_name)
- /* -- return the single-character name of an argument.
- */
- #define arg_flags(ad) ((ad) -> ad_flags)
- /* -- return the argument flags of an argument. The flags themselves
- ** may be manipulated using the BTEST, BSET, and BCLEAR macros
- ** #defined in <useful.h>.
- */
- #define arg_type(ad) ((ad) -> ad_type)
- /* -- return the pointer to the value-translation-routine of an argument.
- */
- #define arg_valp(ad) ((ad) -> ad_valp)
- /* -- return the pointer to the value of this argument.
- */
- #define arg_sname(ad) ((ad) -> ad_prompt)
- /* -- return the string name of an argument.
- */
- #define arg_sdesc(ad) ( arg_sname(ad) )
- /* -- return the description of an argument. If a description was supplied,
- ** the ARGDESCRIBED flag will be set and the description is available
- ** by calling get_argdesc().
- */
- #define ARG_isDESCRIBED(ad) BTEST( arg_flags(ad), ARGDESCRIBED )
- /* -- Evaluates to TRUE only if an argument description was provided.
- */
- #define arg_description(ad) ( ARG_isDESCRIBED(ad) ? arg_sdesc(ad) : "" )
- /* -- Return the description string (or an empty string if no description
- ** was given) for this argument.
- */
- #define ARG_isPOSITIONAL(ad) BTEST( arg_flags(ad), ARGPOS )
- /* -- Evaluates to TRUE if this argument may be positionally matched.
- */
- #define ARG_isPOSONLY(ad) ( arg_cname(ad) == ' ' )
- /* -- Evaluates to TRUE if this argument may only be positionally matched.
- */
- #define ARG_isLIST(ad) ( BTEST(arg_flags(ad), ARGLIST) )
- /* -- Evaluates to TRUE if this argument is an arglist.
- */
- #define ARG_isVEC(ad) ( BTEST(arg_flags(ad), ARGVEC) )
- /* -- Evaluates to TRUE if this argument is a vector.
- */
- #define ARG_isMULTIVAL(ad) ( BTEST(arg_flags(ad), ARGVEC | ARGLIST) )
- /* -- Evaluates to TRUE if this argument is an arglist or a vector.
- */
- #define ARG_isVALTAKEN(ad) ( ! BTEST(arg_flags(ad), ARGNOVAL) )
- /* -- Evaluates to TRUE if this argument does NOT take a value.
- */
- #define ARG_isGIVEN(ad) ( BTEST(arg_flags(ad), ARGGIVEN) )
- /* -- Evaluates to TRUE if this argument was given on the command-line.
- */
- #define ARG_isVALGIVEN(ad) ( BTEST(arg_flags(ad), ARGVALGIVEN) )
- /* -- Evaluates to TRUE if the argument value was given on the command-line.
- */
- #define ARG_isREQUIRED(ad) ( BTEST(arg_flags(ad), ARGREQ) )
- /* -- Evaluates to TRUE if this argument is required.
- */
- #define ARG_isVALOPTIONAL(ad) ( BTEST(arg_flags(ad), ARGVALOPT) )
- /* -- Evaluates to TRUE if the argument value is optional.
- */
- #define ARG_isVALSEPARATE(ad) ( BTEST(arg_flags(ad), ARGVALSEP) )
- /* -- Evaluates to TRUE if the argument value is optional.
- */
- #define ARG_isHIDDEN(ad) ( BTEST(arg_flags(ad), ARGHIDDEN) )
- /* -- Evaluates to TRUE if this argument is omitted from usage messages.
- */
- /**^^**********************************************************************/
-
-
- /* macro to define a NULL argument-type function */
- #define argNULL (argTypePtr_t)NULL
-
- /* macro for an empty argument descriptor */
- #define ARG_EMPTY { '\0', 0x0000, argNULL, ARBNULL, CHARNULL }
-
- /*
- ** macro to denote start & end of an ARGDESC array declared without
- ** the CMD_XXXXXXX macros which follow.
- */
- #define STARTOFARGS ARG_EMPTY
- #define ENDOFARGS ARG_EMPTY, ARG_EMPTY
-
- /***************************************************************************
- ** ^SECTION: CMD-MACROS
- ** Parseargs.h defines a set of macros to allow a more "self documenting"
- ** approach to declaring argument-descriptor arrays. The "old-style" is
- ** still accepted (but if used it is recommended that the STARTOFARGS
- ** macro is used in conjunction with ENDOFARGS). An example use of these
- ** macros (which, with one exception, all begin with "CMD") follows:
- **
- ** #include <parseargs.h>
- **
- ** static BOOL bflag = FALSE;
- ** static char *arg1 = CHARNULL;
- ** static char *arg2 = CHARNULL;
- **
- ** static
- ** CMD_OBJECT
- ** MyCmd
- **
- ** CMD_NAME
- ** "mycmd -- one line statement of purpose"
- **
- ** CMD_DESCRIPTION
- ** "Mycmd will try really really hard to run without errors \
- ** and do whatever the heck it is supposed to do. If (God forbid) \
- ** something should actually go wrong it will say so."
- **
- ** CMD_ARGUMENTS
- ** 'b', ARGOPT, argSBool, __ &bflag,
- ** "bflag -- turn on `b'-mode (whatever that is)",
- **
- ** ' ', ARGREQ, argStr, __ &arg1,
- ** "arg1 -- first argument to this spiffy program",
- **
- ** ' ', ARGOPT, argStr, __ &arg2,
- ** "arg2 -- optional second argument to this spiffy program",
- **
- ** END_ARGUMENTS
- ** CMD_END
- **
- ** main( argc, argv )
- ** int argc;
- ** char *argv[];
- ** {
- ** (void) parseargs( argv, MyCmd );
- ** (void) dostuff();
- ** exit( 0 );
- ** }
- ***^^**********************************************************************/
- #define CMD_OBJECT ARGDESC
- #define CMD_NAME [] = { { '\0', (argMask_t)0x0000, (argTypePtr_t)
- #define CMD_DESCRIPTION , ARBNULL,
- #define CMD_ARGUMENTS },
- #define START_ARGUMENTS ARG_EMPTY
- #define END_ARGUMENTS ARG_EMPTY
- #define CMD_END };
-
- /*
- ** shorthand for declaring main program
- */
- #ifdef __ANSI_C__
- # define MAIN(argc,argv) int main( int argc, char *argv[] )
- #else
- # define MAIN(argc,argv) int main( argc, argv ) int argc; char *argv[];
- #endif
-
- /***************************************************************************
- ** ^SECTION: MULTI-VALUED_ARGUMENTS
- ** Parseargs supports two different types of multi-valued arguments:
- ** linked-lists and vectors. The linked-lists are called argument lists
- ** (or arg-lists) and are specified by supplying the ARGLIST flag along
- ** with an associated listXxxx argument-translation routine. The value
- ** associated with an arg-list should be a list structure of type ArgList.
- ** The include file <parseargs.h> defines four macros for manipulating
- ** ArgList structures: ARGLISTNULL, L_NEXT, L_STRING, and L_FLAGS.
- **
- ** ARGLISTNULL is simply the NULL argument-list pointer. L_NEXT and
- ** L_STRING each take a pointer to a non-NULL ArgList structure. L_NEXT
- ** returns the address of the next item in the list and L_STRING returns
- ** the string-value of the current list-item. L_FLAGS return the argflags
- ** for a given item in the list. With non-multivalued arguments, only the
- ** flags in the argument descriptor are needed; lists and vectors however
- ** need a set of flags for each item they contain. Once an arg-list has
- ** been created, it may be deallocated using the function listFree. List-
- ** Free takes one parameter: the address of the first item in the arg-list.
- **
- ** An alternative to argument-lists is argument vectors (or arg-vectors).
- ** Arg-vectors use the ARGVEC flag instead of the ARGLIST flag and do not
- ** require a special listXxxx function for each vector-type. Each of the
- ** argXxxx functions is responsible for handling vectors of its type
- ** (although some argXxx functions such as the boolean types do not sup-
- ** port vectors). An arg-vector is a structure which contains a count, an
- ** array of elements (i.e. an argc/argv pair), and an array of flags, one
- ** for each element of argv. There are two macros in defined in
- ** <parseargs.h> which are used for arg-vectors. ARGVEC_T may be used to
- ** declare a vector structure or a vector type; ARGVEC_EMPTY may be used
- ** to initialize the structure. It is strongly recommended that ARGVEC_T
- ** be used to declare vector types in a typedef statement (particularly
- ** if one is using function prototypes) but for those who insist, it may
- ** be used to directly declare a structure. String-vectors will always
- ** have an extra NULL-pointer at the end such that:
- **
- ** ( StrVec.array[ StrVec.count ] == (char *)NULL )
- **
- ** is always true, and character-vectors will always have an extra NUL-
- ** character at the end such that:
- **
- ** ( CharVec.array[ CharVec.count ] == '\0' )
- **
- ** is always true. Integer and floating point vectors contain no extra
- ** "null" elements.
- **
- ** Once created, arg-vectors may be deallocated by calling the macro vec-
- ** Free or the macro vecDeepFree and passing it the arg-vector structure.
- ** The differemce between these two macros is that the latter will also
- ** free each item in the vector that required space to be allocated (at
- ** the expense of traversing the vector). At this writing, the only
- ** predefined argument-type(s) that would benefit from vecDeepFree is
- ** argStr vectors.
- **
- ** An example use of arg-lists, and of arg-vectors follows:
- **
- ** #include <parseargs.h>
- **
- ** typedef ARGVEC_T(char *) strvec_t;
- **
- ** static ArgList *StringList = ARGLISTNULL;
- ** static strvec_t StringVec = ARGVEC_EMPTY(char *);
- ** static ARGVEC_T(int) NumberVec = ARGVEC_EMPTY(int);
- **
- ** static
- ** CMD_OBJECT Args
- ** CMD_NAME "foo -- do whatever foo does"
- ** CMD_DESCRIPTION "put a brief paragraph here"
- ** CMD_ARGUMENTS
- ** 'l', ARGLIST, listStr, __ &StrList, "LiSt {list of strings}",
- ** 's', ARGVEC, argStr, __ &StrVec, "STRing {vector of strings}",
- ** 'i', ARGVEC, argInt, __ &NumVec, "NUMber {vector of numbers}",
- ** END_ARGUMENTS
- ** CMD_END
- **
- ** main( int argc, char *argv[] )
- ** {
- ** int i, *ls;
- **
- ** if ( parseargs(argv, Args) ) syserr( "parseargs failed" );
- **
- ** for ( ls = StrList, i=1 ; ls ; ls = L_NEXT(ls), i++ )
- ** printf( "List item %d=%s, flags=%x0\n",
- ** i, L_STRING(ls), L_FLAGS(ls) );
- **
- ** for ( i = 0 ; i < StrVec.count ; i++ )
- ** printf( "String[%d]=%s, flags=%x0\n",
- ** i, StrVec.array[i], StrVec.flags[i] );
- **
- ** for ( i = 0 ; i < NumVec.count ; i++ )
- ** printf( "Number[%d]=%s, flags=%x0\n",
- ** i, NumVec.array[i], NumVec.flags[i] );
- **
- ** listFree( StrList );
- ** StrList = ARGLISTNULL;
- **
- ** vecDeepFree( StrVec, char * );
- ** vecFree( NumVec, int );
- **
- ** exit( 0 );
- ** }
- **
- **^^***********************************************************************/
-
- /* definition of an arg-list */
- typedef struct arglist {
- struct arglist *nl_next; /* pointer to next item */
- ARBPTR nl_val; /* value of current item */
- argMask_t nl_flags; /* flags for current item */
- } ArgList;
- #define ARGLISTNULL (ArgList *)NULL
-
- /* definition of an arg-list-head (the first two fields MUST exactly
- ** overlay with their corresponding elements in an ArgList struct)
- */
- typedef struct arglisthead {
- ArgList *nl_next; /* pointer to next item */
- ARBPTR nl_val; /* value of current item */
- argMask_t nl_flags; /* flags for current item */
- ArgList *nl_tail; /* pointer to last item */
- } ArgListHead;
- #define ARGLISTHEADNULL (ArgListHead *)NULL
-
- /*
- ** macros to manipulate arg-lists
- */
- #define L_STRING(ls) ((char *)((ls)->nl_val)) /* Item as a string */
- #define L_NEXT(ls) ((ls)->nl_next) /* Next item of list */
- #define L_ADVANCE(ls) (ls) = (ArgList *)L_NEXT(ls) /* Advance list ptr */
- #define L_FLAGS(ls) ((ls)->nl_flags) /* flags of current item */
-
- /*
- ** macros to declare and initialize arg-vectors
- ** (NOTE: this wont work for vectors of function pointers)
- */
- #define ARGVEC_T(type) \
- struct { type *array; unsigned short count; argMask_t *flags; }
- #define ARGVEC_EMPTY(type) \
- { (type *) NULL, (unsigned short) 0, (argMask_t *) NULL }
-
-
- /**********************************************************************
- ** ^SECTION: PARSE-FLAGS
- ** The following bitmasks may be combined in order to modify the
- ** behavior of the parseargs library. The parse flags for a given
- ** may be set through the use of the parsecntl() function.
- */
- #define pa_PROMPT 0x0001
- /* -- Prompt the user for any missing arguments that are required on the
- ** command-line. No special escaping or quoting is performed on the
- ** user input. Required arguments that expect a list of values will
- ** be repeatedly prompted for (one item per line) until a blank line
- ** (followed by a carriage return) is entered.
- */
- #define pa_IGNORE 0x0002
- /* -- Ignore any unrecognized or improperly specified command-line arguments
- ** and continue execution of the program. Normally, if a required
- ** argument is unmatched (or an argument is improperly specified),
- ** a usage message is printed program execution is terminated.
- */
- #define pa_OPTSONLY 0x0004
- /* -- Under UNIX, setting this flag will disable the parsing of long-option
- ** syntax. This will cause all arguments starting with '+' to always be
- ** treated as a positional parameter (instead of a long-option).
- */
- #define pa_KWDSONLY 0x0008
- /* -- Under UNIX, setting this flag disables the parsing of single-character
- ** options. This will cause all arguments starting with '-' to always
- ** be treated as a positional parameter (instead of an option).
- */
- #define pa_FLAGS1ST 0x0010
- /* -- Setting this flag causes the parseargs library to force any and all
- ** non-positional arguments to be specified before any positional ones.
- ** As an example, under UNIX, if this flag is SET then parseargs will
- ** consider the command line "cmd -x arg" to consist of one option and
- ** one positional argument; however the command line "cmd arg -x" would
- ** be considered to consist of two positional arguments (the -x option
- ** will be unmatched).
- **
- ** If this flag is UNSET, then both of the previous examples are
- ** considered to consist of one option and one positional argument.
- */
- #define pa_ANYCASE 0x0020
- /* -- Setting this flag cause character-case to be ignored when attempting
- ** to match single-character argument names (i.e. causes "-i" and "-I"
- ** to be considered equivalent).
- */
- #define pa_ARGV0 0x0040
- /* -- Normally, the parseargs library will assume that the first argument
- ** on the command-line is the name of the command. Setting this flag
- ** tells parseargs that this is NOT the case and that the very first
- ** argument on the command-line is a bona-fide argument to the command.
- */
- #define pa_NOCHECK 0x0080
- /* -- Setting this flag will prevent parseargs from checking for any
- ** required arguments that were not given on the command-line. This
- ** is useful when more than one call to the parseargs library is needed
- ** to parse all the command-line arguments (which could occur if the
- ** command-line argument came from a file or from two argv-vectors).
- ** When this flag is set, then each call to parseargs will check for
- ** missing required arguments (and will prompt the user for them if
- ** desired).
- **
- ** Keeping this flag on until the final set of arguments is parsed will
- ** cause parseargs to not check for missing arguments until the last set
- ** of arguments has been parsed (by the final call to one of the
- ** functions in the parseargs library).
- */
- #define pa_CONTINUE 0x0100
- /* -- Setting this flag will cause subsequent calls to the parseargs library
- ** to NOT reset the current command-state. Hence, all arguments will not
- ** be initially set to "NOT GIVEN" and other (normal) initializations are
- ** not be performed. This is useful in conjunction with the pa_NOCHECK
- ** when more than one call to parseargs is required to parse all the
- ** command arguments. In this scenario, pa_CONTINUE should be unset (the
- ** default setting) for the very first call to parseargs, but should then
- ** be set before any subsequent calls to parseargs are made.
- */
- #define pa_NOCMDENV 0x0200
- /* -- Setting this flag prevents parseargs from checking the <CMD-NAME>_ARGS
- ** environment variable for any user-defined default command arguments.
- */
- #define pa_COPYF 0x0400
- /* -- When this flag is OFF (the default), a value of FALSE is provided as
- ** the <copyf> argument to all the arg-type (argXxxxx) functions when an
- ** argument is matched. Setting this flag will cause a value of TRUE to
- ** be provided as the <copyf> argument to all the arg-type (argXxxxx)
- ** functions when an argument is matched.
- */
- /**^^**********************************************************************/
-
-
- /**********************************************************************
- ** ^SECTION: PARSE-CNTLS - specify which attributes to get/set
- ** Each of the following function codes specifies an attribute that
- ** is to be manipulated by parsecntl(3). The function code is the
- ** second parameter to parsecntl(3). With the exception of pc_ARGFLAGS,
- ** each of the function codes corresponds to a call to parsecntl(3)
- ** using four parameters (pc_ARGFLAGS uses 5 parameters). In each case,
- ** the last parameter is either the address of a buffer to write the
- ** attribute to, or the actual buffer to read the attribute from
- ** (depending upon the mode -- the third parameter to parsecntl).
- */
- typedef enum {
- pc_PARSEFLAGS,
- /* -- get/set parse flags
- **
- ** This function code is used to read and/or modify the existing parsing
- ** parsing behavior. The fourth parameter to parsecntl should be a
- ** combination of pc_XXXX bitmasks if the parse-flags are only being
- ** written, otherwise it should be a pointer to an argMask_t variable.
- */
- pc_ARGFLAGS,
- /* -- get/set argument flags
- **
- ** This function code may only be used to read the argument-flags of
- ** a named argument. It is an error to specify a mode that attempts
- ** to write the argument-flags with this function code. The fourth
- ** parameter to parsecntl should be the keyword name of the argument
- ** whose flags are to be read. The fifth (and final) argument should
- ** be a pointer to the argMask_t variable which will receive the resulting
- ** argument-flags.
- */
- pc_DEFARGS,
- /* -- get/set the default arguments
- **
- ** This function code is used to query or modify the current default
- ** argument-descriptor list for the given command. The fourth parameter
- ** to parsecntl should be the argument-descriptor array to assign as the
- ** new default-list (or the address of an argdesc-array if the default
- ** list is being retrieved).
- **
- ** If a given option/qualifier does not appear to match any items in the
- ** argdesc-array, a default argdesc-array is then searched to match the
- ** option. If it is STILL unmatched then it is flagged as such. The
- ** default-argdesc array is automatically used by all programmer-defined
- ** argdesc-array but may be unset or reset using the pc_DEFARGS function
- ** of parsecntl(3). In such a manner, a programmer could specify a dif-
- ** ferent set of default-arguments to search for. Furthermore, default
- ** argdesc-arrays may also be assigned default argdesc-arrays, thus
- ** allowing the programmer to define a whole search-list of default
- ** argdesc-arrays for a given command.
- **
- ** This could prove useful in a situation where a set of commands have a
- ** few common-options and differ in their remaining ones. If the same
- ** main() were used for each command, then main could define one common
- ** argdesc-array and then a set of argdesc-arrays for each command. Main
- ** could then figure out which argdesc-array to used based on the name in
- ** argv[0], and set its default argdesc-array to be the common argdesc-
- ** array, as in the following:
- **
- ** #include <parseargs.h>
- ** .
- ** . variable declarations
- ** .
- **
- ** static ARGDESC common_args[] = {
- ** STARTOFARGS,
- ** 'L', ARGOPT, argBool, __ &lflag, "list (list available items)"
- ** 'I', ARGOPT, argStr, __ &item, "item (specify item to use)",
- ** ENDOFARGS
- ** };
- **
- ** static ARGDESC cmd1_args[] = {
- ** STARTOFARGS,
- ** 's', ARGOPT, argBool, __ &sflag, "S (set S)",
- ** 't', ARGOPT, argBool, __ &tflag, "T (set T)",
- ** ENDOFARGS
- ** };
- **
- ** static ARGDESC cmd2_args[] = {
- ** STARTOFARGS,
- ** 'x', ARGOPT, argBool, __ &xflag, "X (set X)",
- ** 'y', ARGOPT, argBool, __ &yflag, "Y (set Y)",
- ** ENDOFARGS
- ** };
- **
- ** main( argc, argv ) int argc; char *argv[];
- ** {
- ** ARGDESC *cmd = cmd1_args;
- ** int status;
- **
- ** if ( strcmp(*argv, "cmd2") == 0 ) cmd = cmd2_args;
- **
- ** if ( parsecntl( cmd, pc_DEFARGS, pc_WRITE, common_args ) != 0 )
- ** syserr( "unable to set default args" );
- **
- ** status = parseargs( argv, cmd );
- ** .
- ** .
- ** .
- ** }
- **
- ** Note that in the above call to parsecntl(3), that zero will be
- ** returned upon success and non-zero upon failure. If pe_DEFARGS is
- ** returned, then cmd is already on common_args's list of defaults (and
- ** would result in an infinite loop while parsing).
- */
- pc_NAME,
- /* -- get/set the command-name
- */
- pc_PURPOSE,
- /* -- get/set the command-purpose
- */
- pc_DESCRIPTION
- /* -- get/set the command-description
- */
- /* Each of these last three function codes are used to modify or query the
- ** name, purpose, or description associated with a command. The fourth
- ** parameter to parsecntl should be the new string to use (or the address
- ** of the string, a char** variable, to recieve the current value).
- */
- } parsecntl_t;
-
- /**^^**********************************************************************/
-
-
- /**********************************************************************
- ** ^SECTION: PARSE-MODES - modes to get/set command attributes.
- ** Parsecntl may be used to read current command attributes, write/assign
- ** new command attributes, or both. The mode argument to parsecntl
- ** determines which of these three alternatives are desired. If the
- ** programmer merely wishes to assign new attributes, then invoking
- ** parsecntl in pc_WRITE mode and passing the new attributes will do the
- ** job. If the programmer wishes simply to query attributes, then
- ** invoking parsecntl in pc_READ mode and passing a pointer to the
- ** desired object in which to write the attribute settings will suffice.
- **
- ** If the programmer wishes to assign new attributes and at the same time
- ** find out what the attributes were before making the assignment, then
- ** programmer must invoke parsecntl for pc_RDWR mode and pass a pointer
- ** to the object containing the new attribute settings; When parsecntl
- ** returns, then (assuming it returns 0) the desired attributes will have
- ** been assigned and the object that contained the new attribute settings
- ** will now contain the attribute settings that were in effect immediately
- ** before parsecntl was invoked.
- */
- typedef enum {
- pc_READ,
- /* -- read-mode: attributes are retrieved
- */
- pc_WRITE,
- /* -- write-mode: attributes are assigned new values
- */
- pc_RDWR
- /* -- read/write-mode: attributes are retrieved and then assigned
- */
-
- } parsemode_t;
- /**^^**********************************************************************/
-
-
- /*
- ** private (implementation specific) definitions
- */
- #ifdef PARSEARGS_PRIVATE
-
- /* macros to define command-line style specific character sequences */
- # ifdef amiga_style
- # define s_ARG_SEP "=:" /* AmigaDOS argument separator characters */
- # endif
- # ifdef ibm_style
- # define s_ARG_SEP "=" /* MS-DOS and OS/2 argument separator characters */
- # endif
- # ifdef unix_style
- # define c_OPT_PFX '-' /* Unix option prefix character */
- # define c_KWD_PFX '+' /* Unix keyword prefix character */
- # define s_ARG_SEP "=:" /* Unix keyword-value separator characters */
- # endif
- # ifdef vms_style
- # define s_KWD_PFX "/" /* VMS qualifier prefix character */
- # define s_LSI_SEP ",+" /* VMS LiSt Item separator characters */
- # define s_ARG_SEP "=:" /* VMS qualifier-value separator characters */
- # endif
-
-
- /* call the function to parse the given argument-value string */
- # define HANDLE(ad,vp,pflags) ((*arg_type(ad))(ad, vp, BTEST(pflags, pa_COPYF)))
-
-
- /* parse-state flags */
- # define ps_OLDSTYLE 0x01 /* force backward compatibility? */
- # define ps_NOFLAGS 0x02 /* opt/kwd parsing in effect? */
- # define ps_NOCMDENV 0x04 /* <CMD>_ARGS environment-variable parsed? */
- # define ps_NOPARSECNTL 0x08 /* PARSECNTL environment-variable parsed? */
- # define ps_USERNAME 0x10 /* user supplied name string */
- # define ps_FREENAME 0x10 /* free name string space */
- # define ps_USERPURPOSE 0x20 /* user supplied purpose string */
- # define ps_FREEPURPOSE 0x20 /* free purpose string space */
- # ifdef vms_style
- # define ps_NOTCMDLINE 0x40 /* argv-array is NOT from the command-line */
- # endif
-
- typedef unsigned short ps_flags_t;
-
-
- /*
- ** structure to hold arg-desc pointers maintained in the command-context
- */
- typedef struct {
- ARGDESC *default_argd; /* pointer to default args */
- ARGDESC *current_list; /* pointer to ad with arglist (or argvector)
- ** that is currently being appended.
- */
- # ifdef amiga_style
- ARGDESC *previous_ad; /* pointer to previously matched ad */
- # endif
- } ARGDPTRS;
-
- /*
- ** structures to replace the first and last argument descriptor
- ** in a command (each field must exactly overlay its counterpart
- ** in an ARGDESC struct).
- */
- typedef struct {
- char id; /* id is ALWAYS '\0' for first and last ad */
- ps_flags_t state_flags; /* current parse-state */
- CONST char *argv0; /* argv[0] from the command-line */
- ARGDPTRS *argdp; /* structure with ARGDESC pointers */
- CONST char *purpose; /* one-line purpose provided with CMD_NAME */
- } CTXDESC; /* the command-context */
-
- typedef struct {
- char id; /* id is ALWAYS '\0' for first and last ad */
- argMask_t parse_flags; /* current parse-flag bitmasks */
- CONST char *name; /* command-name provided with CMD_NAME */
- CTXDESC *context; /* pointer to command-context */
- CONST char *description; /* description provided with CMD_DESCRIPTION */
- } CMDDESC; /* the command-descriptor */
-
- /*
- ** macros to extract command-line attributes in the command-object
- */
- # define cmd_desc(cmd) (CMDDESC *)cmd
- # define cmd_id(cmd) (cmd_desc(cmd)) -> id
- # define cmd_flags(cmd) (cmd_desc(cmd)) -> parse_flags
- # define cmd_name(cmd) (cmd_desc(cmd)) -> name
- # define cmd_description(cmd) (cmd_desc(cmd)) -> description
- # define cmd_context(cmd) (cmd_desc(cmd)) -> context
- # define cmd_ctxid(cmd) (cmd_context(cmd)) -> id
- # define cmd_state(cmd) (cmd_context(cmd)) -> state_flags
- # define cmd_argv0(cmd) (cmd_context(cmd)) -> argv0
- # define cmd_purpose(cmd) (cmd_context(cmd)) -> purpose
- # define cmd_ptrs(cmd) (cmd_context(cmd)) -> argdp
- # define cmd_defargs(cmd) (cmd_ptrs(cmd)) -> default_argd
- # define cmd_list(cmd) (cmd_ptrs(cmd)) -> current_list
- # ifdef amiga_style
- # define cmd_prev(cmd) (cmd_ptrs(cmd)) -> previous_ad
- # endif
-
- /* macro to determine if a command-object has been initialized */
- # define CMD_isINIT(cmd) \
- ( !cmd_id(cmd) && cmd_context(cmd) )
-
- /*
- ** macros to help ascertain argument type
- */
- # define ARG_isBOOLEAN(ad) \
- ( arg_type(ad) == argBool || arg_type(ad) == argSBool || \
- arg_type(ad) == argUBool || arg_type(ad) == argTBool \
- )
- # define ARG_isPSEUDOARG(ad) \
- ( arg_type(ad) == argEnd || \
- arg_type(ad) == argUsage || \
- arg_type(ad) == argDummy \
- )
-
- /*
- ** macros to assist in traversing a command-object
- */
- # define ARG_FIRST(cmd) ((cmd) + 1)
- # define ARG_LAST(cmd) ( ((ARGDESC *)cmd_context(cmd)) - 1 )
- # define ARG_isEND(ad) ( arg_cname(ad) == '\0' )
- # define ARG_ADVANCE(ad) (ad)++
- # define ARG_RETREAT(ad) (ad)--
-
-
- /**********************************************************************
- ** ^SECTION: USAGECNTL
- ** Each of the different values in $USAGECNTL corresponds to a
- ** bitmask as follows:
- */
- # define usg_NONE 0x0001
- /* -- "Quiet", "Silent", and "None" : dont print usage
- */
- # define usg_VERBOSE 0x0002
- /* -- "Verbose", "!Terse" : print argument descriptions
- */
- # define usg_OPTS 0x0004
- /* -- "Options" -- print option syntax
- */
- # define usg_LONGOPTS 0x0008
- /* -- "LongOpts", "KeyWords" : print long-option/keyword syntax
- */
- # define usg_DESCRIPTION 0x0010
- /* -- "Description" : print the command description
- */
- # define usg_PAGED 0x0020
- /* -- "Paged" : pipe the usage message through a paging program
- */
- /**^^**********************************************************************/
-
- #endif /* PARSEARGS_PRIVATE */
-
- /*
- ** pre-defined types available for ad_type
- */
- #ifndef PARSEARGS_NARGTYPES
- # define ARGTYPE(name) EXTERN BOOL name ARGS(( ARGDESC *, char *, BOOL ))
- ARGTYPE( argUsage );
- ARGTYPE( argEnd );
- ARGTYPE( argDummy );
- ARGTYPE( argBool );
- ARGTYPE( argSBool );
- ARGTYPE( argUBool );
- ARGTYPE( argTBool );
- ARGTYPE( argChar );
- ARGTYPE( argStr );
- ARGTYPE( argInt );
- ARGTYPE( argShort );
- ARGTYPE( argLong );
- ARGTYPE( argFloat );
- ARGTYPE( argDouble );
- ARGTYPE( listStr );
- EXTERN VOID listFree ARGS((ArgList *argls));
- # define vecFree(vec,type) \
- do { \
- if ( vec.count > 0 ) { \
- if ( vec.array ) free( vec.array ); \
- if ( vec.flags ) free( vec.flags ); \
- } \
- vec.array = (type *)NULL; \
- vec.flags = (argMask_t *)NULL; \
- vec.count = 0; \
- } while ( 0 )
- # define vecDeepFree(vec,type) \
- do { \
- register int i; \
- \
- for ( i = 0 ; i < vec.count ; i++ ) \
- if ( BTEST(vec.flags[i], ARGCOPYF) ) \
- free( (ARBPTR) vec.array[i] ); \
- \
- if ( vec.count > 0 ) { \
- if ( vec.array ) free( vec.array ); \
- if ( vec.flags ) free( vec.flags ); \
- } \
- vec.array = (type *)NULL; \
- vec.flags = (argMask_t *)NULL; \
- vec.count = 0; \
- } while ( 0 )
-
- # undef ARGTYPE
- #endif /* PARSEARGS_NARGTYPES */
-
- /*
- ** parseargs library function-prototypes
- */
- #ifndef PARSEARGS_NEXTERNS
- EXTERN int fparseargs ARGS(( FILE *, ARGDESC * ));
- EXTERN int lparseargs ARGS(( ArgList *, ARGDESC * ));
- EXTERN int sparseargs ARGS(( char *, ARGDESC * ));
- EXTERN int vparseargs ARGS(( ARGDESC *, int, ...));
- EXTERN int parseargs ARGS(( char **, ARGDESC * ));
- EXTERN int parsecntl ARGS(( ARGDESC *, parsecntl_t, parsemode_t, ...));
- EXTERN VOID usage ARGS(( const ARGDESC * ));
- EXTERN VOID init_args ARGS(( ARGDESC * ));
- EXTERN CONST char *ProgName;
- EXTERN int ProgNameLen;
- #endif /* PARSEARGS_NEXTERNS */
-
- #endif /* PARSEARGS_H */
-