home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-05-18 | 60.7 KB | 1,946 lines |
- Newsgroups: comp.sources.misc
- From: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
- Subject: v29i121: parseargs - functions to parse command line arguments, Part06/10
- Message-ID: <1992May17.182429.28867@sparky.imd.sterling.com>
- X-Md4-Signature: 3d12912bfa1164d531d8ad836e6725ce
- Date: Sun, 17 May 1992 18:24:29 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: brad@hcx1.ssd.csd.harris.com (Brad Appleton)
- Posting-number: Volume 29, Issue 121
- Archive-name: parseargs/part06
- Environment: UNIX, VMS, MS-DOS, OS/2, Amiga
- Supersedes: parseargs: Volume 17, Issue 46-57
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 6 (of 10)."
- # Contents: ibm_args.c vms_args.c
- # Wrapped by brad@hcx1 on Thu May 7 12:12:25 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'ibm_args.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ibm_args.c'\"
- else
- echo shar: Extracting \"'ibm_args.c'\" \(25618 characters\)
- sed "s/^X//" >'ibm_args.c' <<'END_OF_FILE'
- X/*************************************************************************
- X** ^FILE: ibm_args.c - parse MS-DOS and OS/2 argument vectors
- X**
- X** ^DESCRIPTION:
- X** This file contains the routines used to parse MS-DOS and OS/2
- X** argument vectors and to print MS-DOS and OS/2 usage messages.
- X**
- X** ^HISTORY:
- X** 27/08/91 Earl Chew <cechew@bruce.cs.monash.edu.au>
- X** - Use ProgNameLen when accessing ProgName
- X** - Use get_argdesc() to access description
- X**
- X** 01/02/91 Brad Appleton <brad@ssd.csd.harris.com> Created
- X***^^**********************************************************************/
- X
- X#include <ctype.h>
- X#include <useful.h>
- X#include "strfuncs.h"
- X#include "pgopen.h"
- X#include "exit_codes.h"
- X
- X#define PARSEARGS_PRIVATE /* include private definitions */
- X#include "parseargs.h"
- X
- XEXTERN VOID syserr ARGS((const char *, ...));
- XEXTERN VOID usrerr ARGS((const char *, ...));
- XEXTERN char *getenv ARGS((const char *));
- XEXTERN VOID get_winsize ARGS((int, int *, int *));
- X
- XVERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
- X
- X/***************************************************************************
- X** ^GLOBAL-VARIABLE: OptPrefix, KwdPrefix
- X**
- X** ^VISIBILITY:
- X** static-global (visible to all functions in this file).
- X**
- X** ^DESCRIPTION:
- X** OptPrefix contains the single character prefix used to precede
- X** an option switch on the command-line.
- X**
- X** KwdPrefix contains the single character prefix used to precede
- X** a keyword switch on the command-line.
- X***^^**********************************************************************/
- Xstatic char OptPrefix='/';
- Xstatic char KwdPrefix='/';
- X
- X#define isUNIXISH ( OptPrefix == '-' )
- X
- X
- X/***************************************************************************
- X** ^GLOBAL-VARIABLE: Usage_Requested
- X**
- X** ^VISIBILITY:
- X** static-global (visible to all functions in this file).
- X**
- X** ^DESCRIPTION:
- X** Indicates whether a usage message was requested by the user
- X** (as opposed to triggerred by a syntax error). If the message
- X** is requested by the user then it is always printed in verbose
- X** mode and does not return an error-status-code.
- X***^^**********************************************************************/
- Xstatic BOOL Usage_Requested = FALSE;
- X
- X
- X /* macros to detect an option/keyword -- watch out for side effects!! */
- X#define isOPT(s) \
- X ( !BTEST(cmd_flags(cmd), pa_KWDSONLY) && \
- X !BTEST(cmd_state(cmd), ps_NOFLAGS) && \
- X *s == OptPrefix && *(s+1) \
- X )
- X
- X#define isKWD(s) \
- X ( !BTEST(cmd_flags(cmd), pa_OPTSONLY) && \
- X !BTEST(cmd_state(cmd), ps_NOFLAGS) && \
- X *s == KwdPrefix && *(s+1) \
- X )
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: get_prefixes - determine short and long keyword prefixes
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static VOID get_prefixes()
- X#endif
- X/*
- X** ^PARAMETERS:
- X** None.
- X**
- X** ^DESCRIPTION:
- X** Get_prefixes will determine the prefixes to used to denote option
- X** switches and keyword switches on the command-line. The prefixes
- X** are determined by the $SWITCHAR environment varaible. The first
- X** character of the variable is the option-switch prefix and the second
- X** character is the keyword-switch prefix.
- X**
- X** If The option-switch prefix is '-' then Unix-style command-line parsing
- X** is performed, otherwise MS-DOS style command-line parsing is used.
- X**
- X** ^REQUIREMENTS:
- X** None.
- X**
- X** ^SIDE-EFFECTS:
- X** Sets the global variables "OptPrefix" and "KwdPrefix'.
- X**
- X** ^RETURN-VALUE:
- X** None.
- X**
- X** ^ALGORITHM:
- X** - If $SWITCHAR is NULL or empty
- X** - use the defaults ('/' and '/').
- X** - Else
- X** - set the OptPrefix to the first character in SWITCHAR
- X** End-if
- X**
- X** - If there is a second character in SWITCHAR
- X** - assign it to KwdPrefix
- X** - Else if OptPrefix is '-'
- X** - then use '+' as the default KwdPrefix
- X** - Else
- X** - use '/' as the default KwdPrefix
- X** End-if
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static VOID get_prefixes( void )
- X#endif
- X{
- X char *prefixes = getenv( "SWITCHAR" );
- X
- X if ( prefixes && *prefixes ) {
- X OptPrefix = *prefixes;
- X KwdPrefix = *(prefixes + 1);
- X if ( !KwdPrefix ) KwdPrefix = (( OptPrefix == '-' ) ? '+' : '/');
- X }
- X else {
- X OptPrefix = '/';
- X KwdPrefix = '/';
- X }
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: ibm_parse - parse MS-DOS and OS/2 arg-vectors
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X int ibm_parse( argv, argd )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *argv[];
- X/* -- the vector of string arguments from the command-line
- X*/
- X ARGDESC argd[];
- X/* -- the programmer description of the command and its args
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Ibm_parse will parse the arguments in the given vector of strings,
- X** assign the corresponding values to the command-line arguments specified
- X** in argd, and check the syntax of the command-line.
- X**
- X** ^REQUIREMENTS:
- X** The final element in argv must be a NULL pointer.
- X**
- X** ^SIDE-EFFECTS:
- X** argd is modified according to the command-line description and parameters
- X**
- X** ^RETURN-VALUE:
- X** pe_SUCCESS (0) if no errors are encountered
- X** pe_SYSTEM (-1) if a system error is encountered
- X** pe_SYNTAX if a syntax error is encountered
- X**
- X** ^ALGORITHM:
- X** - get the active option and keyword prefixes
- X** - determine whether to use Unix style or not (based on the prefixes)
- X** - for each command-line argument
- X** - attempt to match the argument as a keyword
- X** - if it is a keyword argument
- X** - record and convert its value (if any)
- X** else attempt to match the argument as an option
- X** if it is an option
- X** - record and convert its value (if any)
- X** else it is a positional parameter
- X** - record and convert its value (if any)
- X** else there are too many arguments
- X** - return pe_SYNTAX
- X** end-if
- X** end-for
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X int ibm_parse( char *argv[], ARGDESC argd[] )
- X#endif
- X{
- X register ARGDESC *ad, *args, *cmd;
- X register char **av = argv;
- X register char *p;
- X argName_t name;
- X argMask_t flags;
- X int parse_error = pe_SUCCESS;
- X BOOL ad_okay, 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
- X get_prefixes();
- X
- X while ( av && (p = *av++) ) {
- X /* is this a keyword */
- X if ( isKWD(p) &&
- X ( (OptPrefix != KwdPrefix) || *(p+2) && !strchr(s_ARG_SEP, *(p+2)) )
- X ) {
- X char *s, c = '\0';
- X
- X /* check for `++' to end flags */
- X if ( *(p+1) == KwdPrefix && !*(p+2) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X /* get past prefix and look for possible argument */
- X s = strpbrk(++p, s_ARG_SEP);
- X if(s) {
- X c = *s;
- X *s++ = '\0';
- 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(p, arg_sname(ad)) == 0 ) {
- X is_match = TRUE;
- X break;
- X }/*if*/
- X }
- X }
- X
- X if ( c ) *(s-1) = c; /* restore the equal sign */
- X
- X if ( !is_match ) {
- X if ( OptPrefix == KwdPrefix ) {
- X goto MATCHOPT; /* maybe its an option (and NOT a keyword) */
- X }
- X usrerr("%c%s switch unknown", KwdPrefix, p);
- X parse_error = pe_SYNTAX;
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X /* reset the argument flags - if this arg was already given, some
- X ** of its flags may be set to indicate how it was given before.
- X ** we need to know how it was given now (but save the old ones
- X ** just in case the new one fails).
- X */
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
- X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- X }
- X
- X BSET( arg_flags(ad), ARGKEYWORD );
- X
- X if( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad; /* we matched a lst or a vector */
- X }
- X else {
- X cmd_list(cmd) = ARGDESCNULL;
- X }
- X
- X /* if usage - just print usage and exit */
- X if ( arg_type(ad) == argUsage ) {
- X Usage_Requested = TRUE;
- X usage(argd);
- X exit(exit_USAGE);
- X }
- X
- X /* ARGNOVALs are special, having no value */
- X if ( ! ARG_isVALTAKEN(ad) ) {
- X ad_okay = HANDLE(ad, s, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN );
- X ad = ARGDESCNULL;
- X }
- X continue;
- X }/*if ARGNOVAL*/
- X
- X /* now get the real value */
- X if (!s) {
- X if ( isUNIXISH ) s = *av++;
- X if ( !isUNIXISH || !s || isOPT(s) || isKWD(s) ) {
- X if ( ARG_isVALOPTIONAL(ad) ) {
- X BSET( arg_flags(ad), ARGGIVEN );
- X }
- X else {
- X (VOID) get_kwdname( arg_sname(ad), name );
- X usrerr("%c%s switch requires an argument", KwdPrefix, name);
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X
- X if ( isUNIXISH ) av--;
- X continue;
- X }/*if arg*/
- X if ( isUNIXISH ) BSET( arg_flags(ad), ARGVALSEP );
- X }/*if empty*/
- X
- X /* try to convert the type */
- X ad_okay = HANDLE(ad, s, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X
- X continue;
- X }/*if keyword*/
- X else if ( isOPT(p) ) {
- X p++; /* skip over option prefix */
- X
- XMATCHOPT:
- X /* check for `--' to end flags */
- X if ( *p == OptPrefix && !*(p+1) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X cmd_list(cmd) = ARGDESCNULL;
- X continue;
- X }
- X
- X /* We have a flag argument;
- X ** remember that in the case of single character keywords,
- X ** the conversion function (ad_type) tells us how many characters
- X ** were used. We need that information to decide how many
- X ** characters to skip before the next iteration of the while loop.
- X */
- X while (*p) { /* while not end of switch-chars */
- X
- X /* find the flag in the list */
- 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 register char c1 = arg_cname(ad);
- X register char c2 = *p;
- X
- X if ( arg_type(ad) == argDummy ) continue;
- X if ( ARG_isPOSONLY(ad) ) continue;
- X
- X if ( BTEST(cmd_flags(cmd), pa_ANYCASE) ) {
- X c1 = TOUPPER( c1 );
- X c2 = TOUPPER( c2 );
- X }/*if*/
- X
- X if ( c1 == c2 ) {
- X is_match = TRUE;
- X break;
- X }/*if*/
- X }
- X }
- X if ( !is_match ) {
- X usrerr("%c%c switch unknown", OptPrefix, *p++);
- X parse_error = pe_SYNTAX;
- X cmd_list(cmd) = ARGDESCNULL;
- X if ( !isUNIXISH && *p == *s_ARG_SEP ) p += strlen(p);
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X continue;
- X }/* if unknown-option */
- X
- X /* reset the argument flags - if this arg was already given, some
- X ** of its flags may be set to indicate how it was given before.
- X ** we need to know how it was given now (but save the old ones
- X ** just in case the new one fails).
- X */
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
- X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- X }
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad; /* we matched a list (or a vector) */
- X }
- X else {
- X cmd_list(cmd) = ARGDESCNULL;
- X }
- X
- X /* move p up to point to the (possible) value */
- X p++;
- X if ( !isUNIXISH && *p && strchr(s_ARG_SEP, *p) ) ++p;
- X
- X /* if usage - just print usage and exit */
- X if (arg_type(ad) == argUsage) {
- X Usage_Requested = TRUE;
- X usage(argd);
- X exit(exit_USAGE);
- X }
- X
- X /* ARGNOVALs are special, having no value */
- X if (! ARG_isVALTAKEN(ad)) {
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }/*if*/
- X else {
- X BSET( arg_flags(ad), ARGGIVEN );
- X ad = ARGDESCNULL;
- X if ( ad_okay < 0 ) p -= ad_okay;
- X }/*else*/
- X
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X continue;
- X }/*if*/
- X
- X /* now get the real value */
- X if ( !(*p) ) {
- X if ( isUNIXISH ) p = *av++;
- X if ( !isUNIXISH || !p || isOPT(p) || isKWD(p) ) {
- X if ( ARG_isVALOPTIONAL(ad) ) {
- X BSET( arg_flags(ad), ARGGIVEN );
- X }
- X else {
- X (VOID) get_argname(arg_sname(ad), name);
- X usrerr( "%s required for %c%c flag",
- X name, OptPrefix, arg_cname(ad) );
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }/*else*/
- X
- X if ( isUNIXISH ) av--;
- X break;
- X }/*if arg*/
- X if ( isUNIXISH ) BSET( arg_flags(ad), ARGVALSEP );
- X }/*if empty*/
- X
- X /* try to convert the type */
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X p += strlen(p);
- X }/*if*/
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X if ( isUNIXISH && ad_okay < 0 && !ARG_isVALSEPARATE(ad) ) {
- X p -= ad_okay;
- X }
- X else {
- X p += strlen(p);
- X }
- X }/*else*/
- X
- X if ( !isUNIXISH && *p == OptPrefix ) ++p;
- X }/*while*/
- X }/*elif option*/
- X else {
- X /* parsing a list of arguments */
- X if ( cmd_list(cmd) ) { /* we're in the middle of a list/vector */
- X ad = cmd_list(cmd);
- X flags = arg_flags(ad); /* reset flags for this argv-item */
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
- X }
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X
- X continue;
- X }
- X /* positional argument */
- 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 many arguments");
- X parse_error = pe_SYNTAX;
- X continue;
- X }
- X
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
- X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- X }
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X cmd_list(cmd) = ad;
- X }
- X
- X /* if FLAGS1ST is set then first positional marks end-of-flags */
- X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X }
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X /* try to convert */
- X ad_okay = HANDLE(ad, p, cmd_flags(cmd));
- X if ( !ad_okay ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X }/*else*/
- X }/*while*/
- X
- X return parse_error;
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: fmtarg - format command-argument syntax
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static int fmtarg( ad, buf, usgflags )
- X/*
- X** ^PARAMETERS:
- X*/
- X ARGDESC *ad;
- X/* -- pointer to the argument to format
- X*/
- X char *buf;
- X/* -- character buffer to hold the formatted result
- X*/
- X argMask_t usgflags;
- X/* -- set of bitmasks corresponding to the value of the user's USAGECNTL
- X** environment variable
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Fmtarg will determine the proper command-line syntax for the
- X** given argument and write the result to the given buffer.
- X**
- X** ^REQUIREMENTS:
- X** buf must be large enough to hold the formatted result (100 characters
- X** should do the trick).
- X**
- X** ^SIDE-EFFECTS:
- X** buf is overwritten.
- X**
- X** ^RETURN-VALUE:
- X** The number of printable characters in the argument-syntax-string
- X**
- X** ^ALGORITHM:
- X** Print argument usage based on whether or not the argument is
- X** positional, hidden, multi-valued (list or vector), etc ....
- X** Optional arguments and values are enclosed in square braces.
- X**
- X** Any syntax biases reflected in usgflags will be used.
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static int fmtarg( const ARGDESC *ad, char *buf, argMask_t usgflags )
- X#endif
- X{
- X /* buf must already be large enough */
- X char *pos;
- X argName_t name, keyword;
- X
- X (VOID) get_argname( arg_sname(ad), name );
- X
- X if (ARG_isPOSITIONAL(ad)) {
- X sprintf( buf, "<%s>", name );
- X }
- X else {
- X (VOID) get_kwdname( arg_sname(ad), keyword );
- X
- X if ( isupper(arg_cname(ad)) && toupper(*keyword) == arg_cname(ad) ) {
- X *keyword = toupper(*keyword);
- X }
- X
- X if ( !(usgflags & usg_LONGOPTS) ) {
- X sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
- X }
- X else if ( !(usgflags & usg_OPTS) ) {
- X sprintf( buf, "%c%s", KwdPrefix, keyword );
- X }
- X else { /* use both */
- X if ( OptPrefix == KwdPrefix && *keyword == arg_cname(ad) ) {
- X if ( !*(keyword+1) )
- X sprintf( buf, "%c%c", OptPrefix, arg_cname(ad) );
- X else
- X sprintf( buf, "%c%c[%s]", OptPrefix, arg_cname(ad), keyword+1 );
- X }
- X else {
- X sprintf( buf, "%c%c|%c%s", OptPrefix, arg_cname(ad),
- X KwdPrefix, keyword );
- X }
- X }
- X
- X pos = buf + strlen(buf);
- X
- X if ( ARG_isVALTAKEN(ad) && !ARG_isBOOLEAN(ad) && !ARG_isPSEUDOARG(ad) ) {
- X if ( isUNIXISH ) *(pos++) = ' ';
- X if ( ARG_isVALOPTIONAL(ad) ) *(pos++) = '[';
- X if ( !isUNIXISH ) *(pos++) = *s_ARG_SEP;
- X sprintf( pos, "<%s>", name );
- X if ( ARG_isVALOPTIONAL(ad) ) strcat(pos, "]");
- X }/*if*/
- X }/*else*/
- X
- X return strlen(buf);
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: ibm_usage - print a usage message
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X VOID ibm_usage( argd, usage_flags )
- X/*
- X** ^PARAMETERS:
- X*/
- X ARGDESC *argd;
- X/* -- the command-descriptor array
- X*/
- X argMask_t usage_flags;
- X/* -- flags set by $USAGECNTL
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Ibm_usage will print the Unix command-line usage of the given
- X** command on standard diagnostic output (stderr). The content of the
- X** usage message is controlled by the bitmasks in usage_flags which
- X** correspond to the settings in the user's USAGECNTL variable.
- X**
- X** ^REQUIREMENTS:
- X** argd should be a non-null command-line argument-descriptor array
- X**
- X** ^SIDE-EFFECTS:
- X** Prints on stderr.
- X**
- X** ^RETURN-VALUE:
- X** None.
- X**
- X** ^ALGORITHM:
- X** - if no usage is desired then exit
- X** - if paging is requested print to the pager instead of stderr
- X** - print the command-line syntax
- X** - if the description is requested print it
- X** - if verbose mode is requested, print the description of each argument
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X void ibm_usage( const ARGDESC *argd, argMask_t usage_flags )
- X#endif
- X{
- X register CONST ARGDESC *ad, *args, *cmd;
- X int max_cols = 80, max_lines = 24;
- X int ll, margin, options, 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(fp), &max_lines, &max_cols );
- X
- X fprintf(fp, "Usage: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
- X
- X ll = ProgNameLen + 7;
- X margin = ll + 1;
- X longest = 0;
- X
- X /* print Synopsis */
- 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 int pl;
- 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, usage_flags);
- X
- X if ( pl > longest) longest = pl;
- X
- X if ( ARG_isMULTIVAL(ad) ) {
- X strcat( buf, "..." );
- X pl += 3;
- X }
- X if ( !ARG_isREQUIRED(ad) ) {
- X pl += 2;
- 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, 0);
- 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 options = 0;
- X
- X /* print Argument descriptions */
- 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 char *desc;
- X int desclen;
- 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 ( !options++ ) fprintf(fp, "Options/Arguments:\n");
- X fmtarg(ad, buf, usage_flags);
- X desc = get_argdesc(arg_description(ad), &desclen);
- X indent_para( fp, max_cols, 8, buf, longest+2, desc, desclen );
- X }/*for each ad */
- X }/* for each argd */
- X }/* for each parm-type */
- X
- X if ( pgactive(fp) ) (VOID) pgclose( fp );
- X}
- X
- END_OF_FILE
- if test 25618 -ne `wc -c <'ibm_args.c'`; then
- echo shar: \"'ibm_args.c'\" unpacked with wrong size!
- fi
- # end of 'ibm_args.c'
- fi
- if test -f 'vms_args.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vms_args.c'\"
- else
- echo shar: Extracting \"'vms_args.c'\" \(32340 characters\)
- sed "s/^X//" >'vms_args.c' <<'END_OF_FILE'
- X/*************************************************************************
- X** ^FILE: vms_args.c - parse VMS/DCL argument vectors
- X**
- X** ^DESCRIPTION:
- X** This file contains the routines used to parse VMS/DCL argument
- X** vectors and to print VMS/DCL usage messages.
- X**
- X** ^HISTORY:
- X** 11/21/91 Brad Appleton <brad@ssd.csd.harris.com>
- X** - added Mike Levins fix to is_cmdline() to check for 0 length
- X** returned by lib$get_foreign.
- X** - added check of ps_NOTCMDLINE state-flag before calling is_cmdline()
- X** - fixed problem in vms_parse() where ARGVALGIVEN was getting set in
- X** place of ARGGIVEN.
- X**
- X** 08/27/91 Earl Chew <cechew@bruce.cs.monash.edu.au>
- X** - Use ProgNameLen when accessing ProgName
- X** - Use get_argdesc() to access description
- X**
- X** 12/03/90 Brad Appleton <brad@ssd.csd.harris.com> Created
- X***^^**********************************************************************/
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <useful.h>
- X
- X#ifdef vms
- X# include <descrip.h>
- X#endif
- X
- X#include "strfuncs.h"
- X#include "pgopen.h"
- X#include "exit_codes.h"
- X
- X#define PARSEARGS_PRIVATE /* include private definitions */
- X#include "parseargs.h"
- X
- XEXTERN VOID syserr ARGS((const char *, ...));
- XEXTERN VOID usrerr ARGS((const char *, ...));
- XEXTERN VOID get_winsize ARGS((int, int *, int *));
- XEXTERN BOOL argInput ARGS((ARGDESC *, char *, BOOL));
- XEXTERN BOOL argOutput ARGS((ARGDESC *, char *, BOOL));
- X
- XVERSIONID("$Header: vms_args.c,v 1.1 90/08/23 18:00:00 brad Exp $");
- X
- X/***************************************************************************
- X** ^GLOBAL-VARIABLE: Usage_Requested
- X**
- X** ^VISIBILITY:
- X** static-global (visible to all functions in this file).
- X**
- X** ^DESCRIPTION:
- X** Indicates whether a usage message was requested by the user
- X** (as opposed to triggerred by a syntax error). If the message
- X** is requested by the user then it is always printed in verbose
- X** mode and does not return an error-status-code.
- X***^^**********************************************************************/
- Xstatic BOOL Usage_Requested = FALSE;
- X
- X
- X#define MAXCMDLINE 255
- X#define VNULL (VOID *) 0
- X
- X#define TOGGLE(flag) flag = (flag) ? FALSE : TRUE
- X
- X /* define mappings */
- X#define c_SPACE '\001' /* whitespace */
- X#define c_QUAL '\002' /* qualifier-delimiter */
- X#define c_EQUAL '\003' /* qualifier-argument separator */
- X#define c_COLON '\004' /* qualifier-argument separator */
- X#define c_PLUS '\005' /* list-item separator character */
- X#define c_COMMA '\006' /* list-item separator character */
- X
- X
- Xtypedef enum {
- X Parameter, /* token is a parameter */
- X Qualifier, /* token is a qualifier */
- X EndOfLine /* NUL-token (signifies end of tokens) */
- X} dcl_arg_t;
- X
- X
- Xtypedef struct {
- X dcl_arg_t type; /* token type */
- X char *token; /* token value */
- X} dcl_token_t;
- X
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: is_cmdline - retrieve the original command-line
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static BOOL is_cmdline( argv, result )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *argv[];
- X/* -- array of strings
- X*/
- X char **result;
- X/* -- pointer to resultant command-line
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Is_cmdline will compare the given vector of strings to the actual
- X** string given on the command-line. If the two are approximately
- X** equivalent (modulo quotes and case) then the original command-line
- X** is copied to result, otherwise all the elements of argv are concat-
- X** enated together (in order and separated by whitespace) and assigned
- X** to *result.
- X**
- X** ^REQUIREMENTS:
- X** argv must be non-null
- X**
- X** ^SIDE-EFFECTS:
- X** *result is assigned to either the concatenated argv string or the
- X** original command-line. The result should be freed using free().
- X**
- X** ^RETURN-VALUE:
- X** FALSE if the argv given is different from the command-line;
- X** TRUE otherwise.
- X**
- X** ^CAVEATS:
- X** The comparison is case blind and double quotes are ignored in the
- X** command-line. This is because lib$get_foreign returns double quotes
- X** intact, while VAX-C strips them off.
- X**
- X** ^ACKNOWLEDGEMENTS:
- X** Thanx to Jim Barbour for writing most of this code. --BDA
- X**
- X** ^ALGORITHM:
- X** - Make a single string out of argv
- X** - compare the "big" string to the command-line
- X** - IF they are "equivalent" assign command-line to result & return TRUE.
- X** ELSE assign the "big" string to result and return FALSE.
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static BOOL is_cmdline( const char *argv[], char **result )
- X#endif
- X{
- X register CONST char *avstr;
- X#ifdef vms
- X unsigned long int stat;
- X unsigned short int len;
- X register CONST char *aptr, *sptr;
- X static char str[ MAXCMDLINE ];
- X static BOOL got_cmd_line = FALSE;
- X $DESCRIPTOR(str_d, str);
- X#endif
- X
- X /* make a single string out of argv */
- X avstr = strjoin( argv, " " );
- X
- X#ifndef vms
- X *result = (char *)avstr;
- X return FALSE;
- X
- X#else
- X /* get the original command-line */
- X if ( ! got_cmd_line ) {
- X stat = lib$get_foreign( &str_d, VNULL, &len, VNULL );
- X str[len] = '\0';
- X got_cmd_line = TRUE;
- X if (! (stat & 1)) exit( stat );
- X }
- X
- X /* if we didnt have a command-line, dont bother comparing */
- X if ( !*str ) {
- X *result = (char *)avstr;
- X return FALSE;
- X }
- X
- X /* compare the two */
- X for ( aptr = avstr, sptr = str ; *aptr && *sptr ; sptr++ ) {
- X if ( toupper(*sptr) == toupper(*aptr) ) {
- X ++aptr;
- X }
- X else if ( *sptr != '"' ) {
- X *result = (char *)avstr;
- X return FALSE;
- X }
- X }
- X
- X *result = strdup( str );
- X free( avstr );
- X return TRUE;
- X#endif
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: dcl_strxlat - translate a string according to DCL syntax
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static char *dcl_strxlat( str )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *str;
- X/* -- the string to translate.
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Dcl_strxlat will attempt to convert the given string to canonical
- X** form by escaping any unquoted special characters, and removing any
- X** unquoted whitespace around special characters (such as '=' and '/').
- X** Since the special characters are replaced with special codes, quotes
- X** are also removed.
- X**
- X** ^REQUIREMENTS:
- X** <str> should be non-null and non-empty
- X**
- X** ^SIDE-EFFECTS:
- X** <str> is "trimmed" to canonical form and special characters are mapped
- X** to a unique code.
- X**
- X** ^RETURN-VALUE:
- X** The address of the translated string.
- X**
- X** ^ALGORITHM:
- X** - remove all unquoted whitespace following any unquoted "/:=+("
- X** - remove all unquoted whitespace preceding any unquoted "/:=+)"
- X** - compress all unquoted whitespace,
- X** - remove all unquoted parentheses,
- X** - re-map all other unquoted special characters and remove quotes.
- X** use the following mapping:
- X** whitespace ==> '\001'
- X** '/' ==> '\002'
- X** ':' & '=' ==> '\003'
- X** ',' & '+' ==> '\004'
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static char *dcl_strxlat( char *str )
- X#endif
- X{
- X register char c, *pread = str, *pwrite = str;
- X BOOL quoted = FALSE;
- X
- X /*
- X ** pass1 - scan forward, removing all whitespace after unquoted "/:=+,("
- X */
- X while ( c = *pwrite++ = *pread++ ) {
- X if ( c == '"' ) TOGGLE(quoted);
- X if ( !quoted && strchr("/:=+,(", c) )
- X while( isspace(*pread) ) ++pread;
- X }
- X *--pwrite = '\0'; /* NUL terminate */
- X
- X /*
- X ** pass2 - scan backward, removing all whitespace before unquoted "/:=+,)"
- X */
- X pread = --pwrite; /* set to last NON-NUL char */
- X quoted = FALSE;
- X while ( pread >= str ) {
- X c = *pwrite-- = *pread--;
- X if ( c == '"' ) TOGGLE(quoted);
- X if ( !quoted && strchr("/:=+,)", c) )
- X while( isspace(*pread) ) --pread;
- X }
- X strcpy(str, ++pwrite); /* reset BOS */
- X
- X /*
- X ** pass3 - compress all unquoted whitespace,
- X ** remove all unquoted parentheses,
- X ** re-map all other unquoted special characters and remove quotes.
- X ** use the following mapping:
- X ** whitespace -> '\001'
- X ** '/' -> '\002'
- X ** ':' & '=' -> '\003'
- X ** ',' & '+' -> '\004'
- X */
- X pread = pwrite = str;
- X quoted = FALSE;
- X while ( c = *pread++ ) {
- X if ( c == '"' )
- X TOGGLE(quoted);
- X else if ( !quoted && isspace(c) ) {
- X *pwrite++ = c_SPACE;
- X while( isspace(*pread) ) ++pread;
- X }
- X else if ( !quoted && (c == '(' || c == ')') )
- X continue;
- X else if ( !quoted && c == '/' )
- X *pwrite++ = c_QUAL;
- X else if ( !quoted && c == ':' )
- X *pwrite++ = c_COLON;
- X else if ( !quoted && c == '=' )
- X *pwrite++ = c_EQUAL;
- X else if ( !quoted && c == '+' )
- X *pwrite++ = c_PLUS;
- X else if ( !quoted && c == ',' )
- X *pwrite++ = c_COMMA;
- X else
- X *pwrite++ = c;
- X }/*while*/
- X
- X *pwrite = '\0'; /* NUL-terminate */
- X return str;
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: dcl_split - split a string up into a vector of DCL tokens
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static dcl_token_t *dcl_split( str )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *str;
- X/* -- the string to split up into tokens
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Dcl_split will split a string up into tokens (according to DCL grammar
- X** rules) and will additionally associate each token with a type (namely:
- X** a qualifier, a positional paramater, or the End-of-Tokens symbol).
- X**
- X** ^REQUIREMENTS:
- X** Assume dcl_strxlat(str) has already been performed.
- X**
- X** ^SIDE-EFFECTS:
- X** <str> is modified in much the same manner as it would have
- X** been modified if it were passed as the vector_string to strsplit().
- X**
- X** ^RETURN-VALUE:
- X** A vector of dcl_tokens.
- X**
- X** ^ALGORITHM:
- X** - first count the number of tokens and also try to interpret stuff
- X** like "parm1.1/qual1,parm1.2" by replacing the comma with a space.
- X** - allocate space for the vector of DCL tokens.
- X** - assign the approriate value and type for each token.
- X**
- X** ^CAVEATS:
- X** Does not treate "/qual=(val1,val2/str,..)" as illegal
- X** ( parses it as if it were "/qual=(val1,val2)/str" )
- X**
- X** Replaces "parm1.1/qual,parm1.2" with "parm1.1/qual parm1.2"
- X** which works only because parseargs requires a VMS
- X** positional list to be comma OR whitespace separated
- X** (not just comma separated).
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static dcl_token_t *dcl_split( char *str )
- X#endif
- X{
- X int tokc = 1; /* number of tokens */
- X dcl_token_t *tokv = (dcl_token_t *)NULL; /* vector of tokens */
- X register char *pread, c;
- X register int i;
- X
- X if ( !str || !(*str) ) return (dcl_token_t *)NULL;
- X
- X /* 1st pass (left-to-right) : count tokens */
- X pread = ( *str == c_QUAL ) ? (str + 1) : str;
- X while ( c = *pread++ ) {
- X if ( c == c_QUAL || c == c_SPACE ) ++tokc;
- X if ( c == c_QUAL ) {
- X /* replace "p1.1/qual,p1.2" with "p1.1/qual p1.2" */
- X char *p, delims[5];
- X
- X sprintf( delims, "%c%c%c%c", c_EQUAL, c_PLUS, c_QUAL, c_SPACE );
- X if ( (p = strpbrk((str + 1), delims)) &&
- X ((*p == c_PLUS) || (*p == c_COMMA)) )
- X *p == c_SPACE;
- X }
- X }
- X
- X
- X /* allocate vector */
- X tokv = (dcl_token_t *)malloc( (tokc + 1) * sizeof(dcl_token_t) );
- X if ( tokv == (dcl_token_t *)NULL ) {
- X syserr( "malloc() failed in dcl_split()" );
- X }
- X tokv[ tokc ].type = EndOfLine;
- X tokv[ tokc ].token = CHARNULL;
- X
- X /* 2nd pass (right-to-left) : assign tokens to strings */
- X for ( i = 1, --pread ; pread >= str ; pread-- ) {
- X if ( *pread == c_SPACE || *pread == c_QUAL ) {
- X tokv[ tokc - i ].token = pread + 1;
- X tokv[ tokc - i ].type = ( *pread == c_QUAL ) ? Qualifier : Parameter;
- X *pread = '\0';
- X ++i;
- X }
- X }
- X
- X if ( *str ) { /* then 1st char could NOT have been '/' */
- X tokv -> token = str;
- X tokv -> type = Parameter;
- X }
- X
- X return tokv;
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: dcl_restore - restore the `escaped' characters in a token
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static char *dcl_restore( tokstr )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *tokstr;
- X/* -- the token string to restore
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Dcl_restore will attempt to restore any DCL special characters (such as
- X** '/' and '=') that may have been escaped by dcl_strxlat().
- X**
- X** ^REQUIREMENTS:
- X** tokstr should be non-null and non-empty
- X**
- X** ^SIDE-EFFECTS:
- X** Any escape characters (such as c_QUAL) are restored to their ascii
- X** representation.
- X**
- X** ^RETURN-VALUE:
- X** The address of the restored string
- X**
- X** ^ALGORITHM:
- X** - for each character in tokstr
- X** - if it is special then replace it with its ascii code
- X** end-if
- X** end-for
- X**
- X** ^CAVEATS:
- X** The string is not restored to way it was before it was processed by
- X** dcl_strxlat(). Any characters that were removed are still missing.
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static char *dcl_restore( char *tokstr )
- X#endif
- X{
- X register char *str = tokstr;
- X
- X if ( !str || !*str ) return str;
- X
- X for ( ; *str ; str++ ) {
- X switch( *str ) {
- X case c_SPACE : *str = ' '; break;
- X case c_QUAL : *str = '/'; break;
- X case c_EQUAL : *str = '='; break;
- X case c_COLON : *str = ':'; break;
- X case c_PLUS : *str = '+'; break;
- X case c_COMMA : *str = ','; break;
- X default : break;
- X }
- X }
- X
- X return tokstr;
- X}
- X
- X
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: split_list - function to handle ARGLISTs and ARGVECs
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static BOOL split_list( ad, vp, cmd )
- X/*
- X** ^PARAMETERS:
- X*/
- X ARGDESC *ad;
- X/* -- the argument which takes multiple values
- X*/
- X char *vp;
- X/* -- the string of values for the argument
- X*/
- X ARGDESC *cmd;
- X/* -- the command to which the argument belongs
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Split_list will split the string containing the set of values into
- X** a set of tokens and will then attempt to convert each token (in the
- X** order given) using the ad_type function of the argument structure.
- X**
- X** ^REQUIREMENTS:
- X** <vp> must already be preprocessed by dcl_strxlat to escape any quoted
- X** characters and to map special characters to their corresponding values.
- X**
- X** ^SIDE-EFFECTS:
- X** Ad has some of its flags modified as well as any modifications that
- X** are made by the ad_type function.
- X**
- X** <vp> is modified by strsplit().
- X**
- X** ^RETURN-VALUE:
- X** TRUE if all is hunky-dory; FALSE otherwise
- X**
- X** ^ALGORITHM:
- X** - Split vp into a vector of tokens
- X** - foreach token
- X** - call ad_type(ad, token, copyf)
- X** end-if
- X** - set the ARGGIVEN and ARGVALGIVEN flags accordingly
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static BOOL split_list( ARGDESC *ad, char *vp, ARGDESC *cmd )
- X#endif
- X{
- X char **arg_vec = (char **)NULL;
- X int i, arg_num = 0;
- X BOOL err = FALSE;
- X char delims[3];
- X
- X /* set-up delimiter string */
- X *delims = c_PLUS;
- X *(delims + 1) = c_COMMA;
- X *(delims + 2) = '\0';
- X
- X /* break string up into to tokens and handle each one */
- X arg_num = strsplit( &arg_vec, vp, delims );
- X for ( i = 0 ; i < arg_num ; i++ ) {
- X vp = arg_vec[i];
- X
- X /* try to convert the type */
- X if ( !HANDLE(ad, dcl_restore(vp), cmd_flags(cmd)) ) err = TRUE;
- X }
- X if ( !err ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X
- X if ( ARG_isPOSITIONAL(ad) ) {
- X cmd_list(cmd) = ad;
- X }
- X else {
- X cmd_list(cmd) = ARGDESCNULL;
- X }
- X
- X free( arg_vec );
- X
- X return !err;
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: vms_parse - parse VMS/DCL arg-vectors
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X int vms_parse( argv, argd )
- X/*
- X** ^PARAMETERS:
- X*/
- X char *argv[];
- X/* -- the vector of string arguments from the command-line
- X*/
- X ARGDESC argd[];
- X/* -- the programmer description of the command and its args
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Vms_parse will parse the arguments in the given vector of strings,
- X** assign the corresponding values to the command-line arguments specified
- X** in argd, and check the syntax of the command-line.
- X**
- X** ^REQUIREMENTS:
- X** The final element in argv must be a NULL pointer.
- X**
- X** ^SIDE-EFFECTS:
- X** argd is modified according to the command-line description and parameters
- X**
- X** ^RETURN-VALUE:
- X** pe_SUCCESS (0) if no errors are encountered
- X** pe_SYSTEM (-1) if a system error is encountered
- X** pe_SYNTAX if a syntax error is encountered
- X**
- X** ^ALGORITHM:
- X** - compare argv to the command-line (use the command-line if equal)
- X** - put argv back into a single string and translate it using dcl_strxlat
- X** - reparse the string into DCL tokens using dcl_strsplit
- X** - for each DCL token
- X** - attempt to match the token as a qualifier
- X** - if it is a qualifier
- X** - record and convert its value (if any)
- X** - else it is a positional parameter
- X** - record and convert its value (if any)
- X** - else there are too many arguments
- X** - return pe_SYNTAX
- X** end-if
- X** end-for
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X int vms_parse( char *argv[], ARGDESC argd[] )
- X#endif
- X{
- X register ARGDESC *ad, *args, *cmd;
- X register char *p;
- X char *avstr;
- X BOOL is_match = FALSE;
- X int parse_error = pe_SUCCESS;
- X dcl_token_t *tok, *tokvec;
- X argName_t keyword;
- X argMask_t saveflags, flags;
- X
- X if ( !argd ) return parse_error;
- X
- X /* initialize command-structure */
- X if ( !CMD_isINIT(argd) ) init_args( argd );
- X cmd = argd;
- X saveflags = cmd_flags(cmd);
- X
- X if ( !argv || !*argv ) return parse_error;
- X
- X if ( !BTEST(cmd_state(cmd), ps_NOTCMDLINE) ) {
- X (VOID) is_cmdline( (CONST char **)argv, &avstr );
- X }
- X else {
- X avstr = strjoin( argv, " " );
- X }
- X
- X BSET( cmd_flags(cmd), pa_COPYF );
- X (VOID) dcl_strxlat( avstr );
- X if ( !avstr || !*avstr ) return parse_error;
- X tokvec = dcl_split( avstr );
- X
- X /* run through the token vector */
- X for ( tok = tokvec ; (p = tok -> token) ; tok++ ) {
- X
- X if ( tok -> type == Qualifier && !BTEST(cmd_state(cmd), ps_NOFLAGS) ) {
- X char c = '\0', *s, delims[3];
- X
- X /* set-up delimiter string */
- X *delims = c_EQUAL;
- X *(delims + 1) = c_COLON;
- X *(delims + 2) = '\0';
- X
- X /* skip past qualifier prefix and look for possible argument */
- X s = strpbrk(p, delims);
- X if (s) {
- X c = *s;
- X *s++ = '\0';
- 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(p, arg_sname(ad)) == 0) {
- X is_match = TRUE;
- X break;
- X }/*if*/
- X }
- X }
- X
- X if (c) *(s-1) = c; /* restore the equal sign */
- X
- X if ( !is_match ) {
- X if (s) *(s-1) = '\0';
- X usrerr( "undefined qualifier %s", s_KWD_PFX, p );
- X if (s) *(s-1) = c;
- X parse_error = pe_SYNTAX;
- X continue;
- X }
- X
- X /* end-qualifiers */
- X if ( arg_type(ad) == argEnd ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X continue;
- X }
- X /* if usage - just print usage and exit */
- X if ( arg_type(ad) == argUsage ) {
- X Usage_Requested = TRUE;
- X usage( argd );
- X free( avstr );
- X if ( tokvec ) free( tokvec );
- X cmd_flags(cmd) = saveflags;
- X exit(exit_USAGE);
- X }
- X /* reset the argument flags - if this arg was already given, some
- X ** of its flags may be set to indicate how it was given before.
- X ** we need to know how it was given now (but save the old ones
- X ** just in case the new one fails).
- X */
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP );
- X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- X }
- X
- X /* ARGNOVALs are special, having no value */
- X if ( ! ARG_isVALTAKEN(ad) ) {
- X if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN );
- X ad = ARGDESCNULL;
- X }
- X continue;
- X }/*if ARGNOVAL*/
- X
- X /* now get the real value */
- X if ( !s || !(*s) ) {
- X if ( ARG_isVALOPTIONAL(ad) ) {
- X BSET( arg_flags(ad), ARGGIVEN );
- X }
- X else {
- X (VOID) get_kwdname( arg_sname(ad), keyword );
- X usrerr("qualifier %s requires an argument", keyword);
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X continue;
- X }/*if*/
- X
- X if( ARG_isMULTIVAL(ad) ) {
- X if( !split_list(ad, s, cmd) ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X continue;
- X }/*if list*/
- X
- X /* try to convert the type */
- X if ( !HANDLE(ad, dcl_restore(s), cmd_flags(cmd)) ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X
- X continue;
- X }/*if qual*/
- X else {
- X /* parsing a vector of arguments */
- X if ( cmd_list(cmd) ) {
- X ad = cmd_list(cmd);
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP );
- X }
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X if( ARG_isMULTIVAL(ad) ) {
- X if( !split_list(ad, p, cmd) ) parse_error = pe_SYNTAX;
- X }
- X else if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X
- X if ( !parse_error ) BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X
- X continue;
- X }
- X /* positional argument */
- 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 many arguments");
- X parse_error = pe_SYNTAX;
- X continue;
- X }
- X
- X /* if FLAGS1ST is set then first positional marks end-of-flags */
- X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
- X BSET( cmd_state(cmd), ps_NOFLAGS );
- X }
- X
- X /* reset the argument flags - if this arg was already given, some
- X ** of its flags may be set to indicate how it was given before.
- X ** we need to know how it was given now (but save the old ones
- X ** just in case the new one fails).
- X */
- X flags = arg_flags(ad);
- X if ( ARG_isGIVEN(ad) ) {
- X BCLEAR( arg_flags(ad), ARGVALSEP );
- X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
- X }
- X
- X BSET( arg_flags(ad), ARGVALSEP );
- X
- X if( ARG_isMULTIVAL(ad) ) {
- X if( !split_list(ad, p, cmd) ) {
- X arg_flags(ad) = flags;
- X parse_error = pe_SYNTAX;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X continue;
- X }/*if list*/
- X
- X /* try to convert */
- X if ( !HANDLE(ad, dcl_restore(p), cmd_flags(cmd)) ) {
- X arg_flags(ad) = flags;
- X parse_error = TRUE;
- X }
- X else {
- X BSET( arg_flags(ad), ARGGIVEN | ARGVALGIVEN );
- X }
- X
- X }/*if parameter*/
- X }/*while*/
- X
- X free( avstr );
- X if ( tokvec ) free( tokvec );
- X cmd_flags(cmd) = saveflags;
- X return parse_error;
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: fmtarg - format command-argument syntax
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X static int fmtarg( ad, buf )
- X/*
- X** ^PARAMETERS:
- X*/
- X ARGDESC *ad;
- X/* -- pointer to the argument to format
- X*/
- X char *buf;
- X/* -- character buffer to hold the formatted result
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Fmtarg will determine the proper command-line syntax for the
- X** given argument and write the result to the given buffer.
- X**
- X** ^REQUIREMENTS:
- X** buf must be large enough to hold the formatted result (100 characters
- X** should do the trick).
- X**
- X** ^SIDE-EFFECTS:
- X** buf is overwritten.
- X**
- X** ^RETURN-VALUE:
- X** The number of printable characters in the argument-syntax-string
- X**
- X** ^ALGORITHM:
- X** Print argument usage based on whether or not the argument is
- X** positional, hidden, multi-valued (list or vector), etc ....
- X** Optional arguments and values are enclosed in square braces.
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X static int fmtarg( const ARGDESC *ad, char *buf )
- X#endif
- X{
- X /* buf must already be large enough */
- X char * pos;
- X argName_t keyword, name;
- X
- X (VOID) get_argname( arg_sname(ad), name );
- X
- X if (ARG_isPOSITIONAL(ad)) {
- X sprintf( buf, "<%s>", name );
- X }
- X else {
- X (VOID) get_kwdname( arg_sname(ad), keyword );
- X sprintf( buf, "%c%s", *s_KWD_PFX, 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, "[%c<%s>]", *s_ARG_SEP, name );
- X }
- X else {
- X sprintf( pos, "%c<%s>", *s_ARG_SEP, name );
- X }
- X }/*if*/
- X }/*else*/
- X
- X return (int) strlen(buf);
- X}
- X
- X
- X/***************************************************************************
- X** ^FUNCTION: vms_usage - print a usage message
- X**
- X** ^SYNOPSIS:
- X*/
- X#ifndef __ANSI_C__
- X VOID vms_usage( argd, usage_flags )
- X/*
- X** ^PARAMETERS:
- X*/
- X ARGDESC *argd;
- X/* -- the command-descriptor array
- X*/
- X argMask_t usage_flags;
- X/* -- flags set by $USAGECNTL
- X*/
- X#endif /* !__ANSI_C__ */
- X
- X/* ^DESCRIPTION:
- X** Vms_usage will print the VMS/DCL command-line usage of the given
- X** command on standard diagnostic output (stderr). The content of the
- X** usage message is controlled by the bitmasks in usage_flags which
- X** correspond to the settings in the user's USAGECNTL symbol.
- X**
- X** ^REQUIREMENTS:
- X** argd should be a non-null command-line argument-descriptor array
- X**
- X** ^SIDE-EFFECTS:
- X** Prints on stderr.
- X**
- X** ^RETURN-VALUE:
- X** None.
- X**
- X** ^ALGORITHM:
- X** - if no usage is desired then exit
- X** - if paging is requested print to the pager instead of stderr
- X** - print the command-line syntax
- X** - if the description is requested print it
- X** - if verbose mode is requested, print the description of each argument
- X***^^**********************************************************************/
- X#ifdef __ANSI_C__
- X void vms_usage( const ARGDESC *argd, argMask_t usage_flags )
- X#endif
- X{
- X register CONST ARGDESC *ad, *args, *cmd;
- X int max_cols = 80, max_lines = 24;
- X int margin, ll, pl, qualifiers, 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 /* get screen size */
- X get_winsize( fileno(stderr), &max_lines, &max_cols );
- 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 /* allow null argument descriptor */
- X fprintf(fp, "Format: %.*s", ProgNameLen, (ProgName) ? ProgName : "");
- X
- X ll = ProgNameLen + 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, name;
- 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
- X if ( ARG_isMULTIVAL(ad) ) {
- X (VOID) get_argname( arg_sname(ad), name );
- X strcat(buf, "[,<");
- X strcat(buf, name);
- X strcat(buf, ">...]");
- X pl += 8 + strlen(name);
- X }
- X if ( !ARG_isREQUIRED(ad) ) {
- X pl += 2; /* [] */
- 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, 0);
- 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 qualifiers = 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 char *desc;
- X int desclen;
- 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 ( !qualifiers++ ) fprintf(fp, "Qualifiers/Parameters:\n");
- X (VOID) fmtarg(ad, buf);
- X desc = get_argdesc(arg_description(ad), &desclen);
- X indent_para(fp, max_cols, 8, buf, longest+2, desc, desclen );
- X }/*for each ad */
- X }/* for each argd */
- X }/* for each parm-type */
- X
- X if ( pgactive(fp) ) (VOID) pgclose( fp );
- X}
- X
- END_OF_FILE
- if test 32340 -ne `wc -c <'vms_args.c'`; then
- echo shar: \"'vms_args.c'\" unpacked with wrong size!
- fi
- # end of 'vms_args.c'
- fi
- echo shar: End of archive 6 \(of 10\).
- cp /dev/null ark6isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 10 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
-