v17i056: parseargs - functions to parse command line arguments, Part11/12
Brad Appleton
brad at hcx1.ssd.csd.harris.com
Tue Mar 19 01:57:57 AEST 1991
Submitted-by: Brad Appleton <brad at hcx1.ssd.csd.harris.com>
Posting-number: Volume 17, Issue 56
Archive-name: parseargs/part11
This is part 11 of parseargs
#!/bin/sh
# this is Part.11 (part 11 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file parseargs/useful.h continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 11; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping parseargs/useful.h'
else
echo 'x - continuing file parseargs/useful.h'
sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/useful.h' &&
X EXTERN ARBPTR memcpy ARGS(( ARBPTR, const ARBPTR, int ));
X EXTERN ARBPTR memmove ARGS(( ARBPTR, const ARBPTR, int ));
X EXTERN ARBPTR memset ARGS(( ARBPTR, int, int ));
# endif /* MEMORY_H */
X
# else
# define memcmp(b1,b2,n) bcmp(b1,b2,n)
# define memcpy(b1,b2,n) bcopy(b2,b1,n)
# ifndef BSTRING_H
# define BSTRING_H
X EXTERN VOID bcopy ARGS(( const ARBPTR, ARBPTR, int ));
X EXTERN int bcmp ARGS(( const ARBPTR, const ARBPTR, int ));
X EXTERN VOID bzero ARGS(( ARBPTR, int ));
X EXTERN int ffs ARGS(( int ));
# endif /* BSTRING_H */
# endif /* !BSD */
#endif /* STRING_H */
X
EXTERN ARBPTR malloc ARGS(( size_t ));
EXTERN ARBPTR ckalloc ARGS(( size_t ));
EXTERN ARBPTR realloc ARGS(( ARBPTR, size_t ));
EXTERN ARBPTR free ARGS(( ARBPTR ));
EXTERN VOID exit ARGS(( int ));
X
#define MAXINPUTLINE 200 /* maximum string input line */
#define MAXWORDLEN 100 /* maximum word (token) length */
X
#endif /* _USEFUL_H_ */
SHAR_EOF
echo 'File parseargs/useful.h is complete' &&
chmod 0664 parseargs/useful.h ||
echo 'restore of parseargs/useful.h failed'
Wc_c="`wc -c < 'parseargs/useful.h'`"
test 7432 -eq "$Wc_c" ||
echo 'parseargs/useful.h: original size 7432, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/vms_args.c ==============
if test -f 'parseargs/vms_args.c' -a X"$1" != X"-c"; then
echo 'x - skipping parseargs/vms_args.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/vms_args.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/vms_args.c' &&
/*************************************************************************
** ^FILE: vms_args.c - parse VMS/DCL argument vectors
**
** ^DESCRIPTION:
** This file contains the routines used to parse VMS/DCL argument
** vectors and to print VMS/DCL usage messages.
**
** ^HISTORY:
** 12/03/90 Brad Appleton <brad at ssd.csd.harris.com> Created
***^^**********************************************************************/
X
#include <stdio.h>
#include <ctype.h>
#include <useful.h>
X
#ifdef vms
# include <descrip.h>
#endif
X
#include "strfuncs.h"
#include "pgopen.h"
X
#define PARSEARGS_PRIVATE /* include private definitions */
#include "parseargs.h"
X
EXTERN VOID syserr ARGS((const char *, ...));
EXTERN VOID usrerr ARGS((const char *, ...));
EXTERN VOID get_winsize ARGS((int, int *, int *));
EXTERN BOOL argInput ARGS((ARGDESC *, char *, BOOL));
EXTERN BOOL argOutput ARGS((ARGDESC *, char *, BOOL));
X
VERSIONID("$Header: vms_args.c,v 1.1 90/08/23 18:00:00 brad Exp $");
X
/***************************************************************************
** ^GLOBAL-VARIABLE: Usage_Requested
**
** ^VISIBILITY:
** static-global (visible to all functions in this file).
**
** ^DESCRIPTION:
** Indicates whether a usage message was requested by the user
** (as opposed to triggerred by a syntax error). If the message
** is requested by the user then it is always printed in verbose
** mode and does not return an error-status-code.
***^^**********************************************************************/
static BOOL Usage_Requested = FALSE;
X
X
#define MAXCMDLINE 255
#define VNULL (VOID *) 0
X
#define TOGGLE(flag) flag = (flag) ? FALSE : TRUE
X
X /* define mappings */
#define c_SPACE '\001' /* whitespace */
#define c_QUAL '\002' /* qualifier-delimiter */
#define c_QSEP '\003' /* qualifier-argument separator */
#define c_LSEP '\004' /* list-item separator character */
X
X
typedef enum {
X Parameter, /* token is a parameter */
X Qualifier, /* token is a qualifier */
X EndOfLine /* NUL-token (signifies end of tokens) */
} dcl_arg_t;
X
X
typedef struct {
X dcl_arg_t type; /* token type */
X char *token; /* token value */
} dcl_token_t;
X
X
X
/***************************************************************************
** ^FUNCTION: is_cmdline - retrieve the original command-line
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static BOOL is_cmdline( argv, result )
/*
** ^PARAMETERS:
*/
X char *argv[];
/* -- array of strings
*/
X char **result;
/* -- pointer to resultant command-line
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Is_cmdline will compare the given vector of strings to the actual
** string given on the command-line. If the two are approximately
** equivalent (modulo quotes and case) then the original command-line
** is copied to result, otherwise all the elements of argv are concat-
** enated together (in order and separated by whitespace) and assigned
** to *result.
**
** ^REQUIREMENTS:
** argv must be non-null
**
** ^SIDE-EFECTS:
** *result is assigned to either the concatenated argv string or the
** original command-line. The result shoub be freed using free().
**
** ^RETURN-VALUE:
** FALSE if the argv given is different from the command-line;
** TRUE otherwise.
**
** ^CAVEATS:
** The comparison is case blind and double quotes are ignored in the
** command-line. This is because lib$get_foreign returns double quotes
** intact, while VAX-C strips them off.
**
** ^ACKNOWLEDGEMENTS:
** Thanx to Jim Barbour for writing most of this code. --BDA
**
** ^ALGORITHM:
** - Make a single string out of argv
** - compare the "big" string to the command-line
** - IF they are "equivalent" assign command-line to result & return TRUE.
** ELSE assign the "big" string to result and return FALSE.
***^^**********************************************************************/
#ifdef __ANSI_C__
X static BOOL is_cmdline( const char *argv[], char **result )
#endif
{
X unsigned long int stat;
X unsigned short int len;
X register CONST char *aptr, *sptr, *avstr;
X static char str[ MAXCMDLINE ] = "" ;
#ifdef vms
X $DESCRIPTOR(str_d, str);
#endif
X
X /* make a single string out of argv */
X avstr = strjoin( argv, " " );
X
#ifndef vms
X *result = (char *)avstr;
X return FALSE;
X
#else
X /* get the original command-line */
X if ( !*str ) {
X stat = lib$get_foreign( &str_d, VNULL, &len, VNULL );
X str[len] = '\0';
X if (! (stat & 1)) exit( stat );
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;
#endif
}
X
X
/***************************************************************************
** ^FUNCTION: dcl_strxlat - translate a string according to DCL syntax
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static char *dcl_strxlat( str )
/*
** ^PARAMETERS:
*/
X char *str;
/* -- the string to translate.
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Dcl_strxlat will attempt to convert the given string to canonical
** form by escaping any unquoted special characters, and removing any
** unquoted whitespace around special characters (such as '=' and '/').
** Since the special characters are replaced with special codes, quotes
** are also removed.
**
** ^REQUIREMENTS:
** <str> should be non-null and non-empty
**
** ^SIDE-EFECTS:
** <str> is "trimmed" to canonical form and special characters are mapped
** to a unique code.
**
** ^RETURN-VALUE:
** The address of the translated string.
**
** ^ALGORITHM:
** - remove all unquoted whitespace following any unquoted "/:=+("
** - remove all unquoted whitespace preceding any unquoted "/:=+)"
** - compress all unquoted whitespace,
** - remove all unquoted parentheses,
** - re-map all other unquoted special characters and remove quotes.
** use the following mapping:
** whitespace ==> '\001'
** '/' ==> '\002'
** ':' & '=' ==> '\003'
** ',' & '+' ==> '\004'
***^^**********************************************************************/
#ifdef __ANSI_C__
X static char *dcl_strxlat( char *str )
#endif
{
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 == ':' || c == '=') )
X *pwrite++ = c_QSEP;
X else if ( !quoted && (c == ',' || c == '+') )
X *pwrite++ = c_LSEP;
X else
X *pwrite++ = c;
X }/*while*/
X
X *pwrite = '\0'; /* NUL-terminate */
X return str;
}
X
X
/***************************************************************************
** ^FUNCTION: dcl_split - split a string up into a vector of DCL tokens
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static dcl_token_t *dcl_split( str )
/*
** ^PARAMETERS:
*/
X char *str;
/* -- the string to split up into tokens
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Dcl_split will split a string up into tokens (according to DCL grammar
** rules) and will additionally associate each token with a type (namely:
** a qualifier, a positional paramater, or the End-of-Tokens symbol).
**
** ^REQUIREMENTS:
** Assume dcl_strxlat(str) has already been performed.
**
** ^SIDE-EFFECTS:
** <str> is modified in much the same manner as it would have
** been modified if it were passed as the vector_string to strsplit().
**
** ^RETURN-VALUE:
** A vector of dcl_tokens.
**
** ^ALGORITHM:
** - first count the number of tokens and also try to interpret stuff
** like "parm1.1/qual1,parm1.2" by replacing the comma with a space.
** - allocate space for the vector of DCL tokens.
** - assign the approriate value and type for each token.
**
** ^CAVEATS:
** Does not treate "/qual=(val1,val2/str,..)" as illegal
** ( parses it as if it were "/qual=(val1,val2)/str" )
**
** Replaces "parm1.1/qual,parm1.2" with "parm1.1/qual parm1.2"
** which works only because parseargs requires a VMS
** positional list to be comma OR whitespace separated
** (not just comma separated).
***^^**********************************************************************/
#ifdef __ANSI_C__
X static dcl_token_t *dcl_split( char *str )
#endif
{
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_QSEP, c_LSEP, c_QUAL, c_SPACE );
X if ( (p = strpbrk((str + 1), delims)) && (*p == c_LSEP) )
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
/***************************************************************************
** ^FUNCTION: dcl_restore - restore the `escaped' characters in a token
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static char *dcl_restore( tokstr )
/*
** ^PARAMETERS:
*/
X char *tokstr;
/* -- the token string to restore
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Dcl_restore will attempt to restore any DCL special characters (such as
** '/' and '=') that may have been escaped by dcl_strxlat().
**
** ^REQUIREMENTS:
** tokstr should be non-null and non-empty
**
** ^SIDE-EFFECTS:
** Any escape characters (such as c_QUAL) are restored to their ascii
** representation.
**
** ^RETURN-VALUE:
** The address of the restored string
**
** ^ALGORITHM:
** - for each character in tokstr
** - if it is special then replace it with its ascii code
** end-if
** end-for
**
** ^CAVEATS:
** The string is not restored to way it was before it was processed by
** dcl_strxlat(). Any characters that were removed are still missing.
** Furthermore, characters such as ':' and '=' which map to the same
** code are not always restored to what they were before but are always
** restored to one of the characters (e.g. c_QSEP is always restored to
** an '=' character even though it could have been '=' OR ':').
***^^**********************************************************************/
#ifdef __ANSI_C__
X static char *dcl_restore( char *tokstr )
#endif
{
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_QSEP : *str = '='; break;
X case c_LSEP : *str = ','; break;
X default : break;
X }
X }
X
X return tokstr;
}
X
X
X
X
/***************************************************************************
** ^FUNCTION: split_list - function to handle ARGLISTs and ARGVECs
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static BOOL split_list( ad, vp, cmd )
/*
** ^PARAMETERS:
*/
X ARGDESC *ad;
/* -- the argument which takes multiple values
*/
X char *vp;
/* -- the string of values for the argument
*/
X ARGDESC *cmd;
/* -- the command to which the argument belongs
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Split_list will split the string containing the set of values into
** a set of tokens and will then attempt to convert each token (in the
** order given) using the ad_type function of the argument structure.
**
** ^REQUIREMENTS:
** <vp> must already be preprocessed by dcl_strxlat to escape any quoted
** characters and to map special characters to their corresponding values.
**
** ^SIDE-EFECTS:
** Ad has some of its flags modified as well as any modifications that
** are made by the ad_type function.
**
** <vp> is modified by strsplit().
**
** ^RETURN-VALUE:
** TRUE if all is hunky-dory; FALSE otherwise
**
** ^ALGORITHM:
** - Split vp into a vector of tokens
** - foreach token
** - call ad_type(ad, token, copyf)
** end-if
** - set the ARGGIVEN and ARGVALGIVEN flags accordingly
***^^**********************************************************************/
#ifdef __ANSI_C__
X static BOOL split_list( ARGDESC *ad, char *vp, ARGDESC *cmd )
#endif
{
X char **arg_vec = (char **)NULL;
X int i, arg_num = 0;
X BOOL err = FALSE;
X char delims[2];
X
X /* set-up delimiter string */
X *delims = c_LSEP;
X *(delims + 1) = '\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
/***************************************************************************
** ^FUNCTION: vms_parse - parse VMS/DCL arg-vectors
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X int vms_parse( argv, argd )
/*
** ^PARAMETERS:
*/
X char *argv[];
/* -- the vector of string arguments from the command-line
*/
X ARGDESC argd[];
/* -- the programmer description of the command and its args
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Vms_parse will parse the arguments in the given vector of strings,
** assign the corresponding values to the command-line arguments specified
** in argd, and check the syntax of the command-line.
**
** ^REQUIREMENTS:
** The final element in argv must be a NULL pointer.
**
** ^SIDE-EFECTS:
** argd is modified according to the command-line description and parameters
**
** ^RETURN-VALUE:
** pe_SUCCESS (0) if no errors are encountered
** pe_SYSTEM (-1) if a system error is encountered
** pe_SYNTAX if a syntax error is encountered
**
** ^ALGORITHM:
** - compare argv to the command-line (use the command-line if equal)
** - put argv back into a single string and translate it using dcl_strxlat
** - reparse the string into DCL tokens using dcl_strsplit
** - for each DCL token
** - attempt to match the token as a qualifier
** - if it is a qualifier
** - record and convert its value (if any)
** - else it is a positional parameter
** - record and convert its value (if any)
** - else there are too many arguments
** - return pe_SYNTAX
** end-if
** end-for
***^^**********************************************************************/
#ifdef __ANSI_C__
X int vms_parse( char *argv[], ARGDESC argd[] )
#endif
{
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 (VOID) is_cmdline( (CONST char **)argv, &avstr );
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[2];
X
X /* set-up delimiter string */
X *delims = c_QSEP;
X *(delims + 1) = '\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 usrerr("qualifier %s unknown", p);
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(1);
X }
X /* have we seen this one before */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) )
X BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP );
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), ARGVALGIVEN );
X }
X else {
X (VOID) get_keyword( 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, 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), ARGVALGIVEN | ARGVALSEP );
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 ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
X BSET( cmd_state(cmd), ps_NOFLAGS );
X }
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) )
X BCLEAR( arg_flags(ad), ARGVALGIVEN | ARGVALSEP );
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
/***************************************************************************
** ^FUNCTION: fmtarg - format command-argument syntax
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static int fmtarg( ad, buf )
/*
** ^PARAMETERS:
*/
X ARGDESC *ad;
/* -- pointer to the argument to format
*/
X char *buf;
/* -- character buffer to hold the formatted result
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Fmtarg will determine the proper command-line syntax for the
** given argument and write the result to the given buffer.
**
** ^REQUIREMENTS:
** buf must be large enough to hold the formatted result (100 characters
** should do the trick).
**
** ^SIDE-EFECTS:
** buf is overwritten.
**
** ^RETURN-VALUE:
** The number of printable characters in the argument-syntax-string
**
** ^ALGORITHM:
** Print argument usage based on whether or not the argument is
** positional, hidden, multi-valued (list or vector), etc ....
** Optional arguments and values are enclosed in square braces.
***^^**********************************************************************/
#ifdef __ANSI_C__
X static int fmtarg( const ARGDESC *ad, char *buf )
#endif
{
X /* buf must already be large enough */
X char * pos;
X argName_t keyword, name;
X
X (VOID) get_name( arg_sname(ad), name );
X
X if (ARG_isPOSITIONAL(ad)) {
X sprintf( buf, "<%s>", name );
X }
X else {
X (VOID) get_keyword( arg_sname(ad), keyword );
X 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
/***************************************************************************
** ^FUNCTION: vms_usage - print a usage message
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X VOID vms_usage( argd, usage_flags )
/*
** ^PARAMETERS:
*/
X ARGDESC *argd;
/* -- the command-descriptor array
*/
X argMask_t usage_flags;
/* -- flags set by $USAGECNTL
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Vms_usage will print the VMS/DCL command-line usage of the given
** command on standard diagnostic output (stderr). The content of the
** usage message is controlled by the bitmasks in usage_flags which
** correspond to the settings in the user's USAGECNTL symbol.
**
** ^REQUIREMENTS:
** argd should be a non-null command-line argument-descriptor array
**
** ^SIDE-EFECTS:
** Prints on stderr.
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** - if no usage is desired then exit
** - if paging is requested print to the pager instead of stderr
** - print the command-line syntax
** - if the description is requested print it
** - if verbose mode is requested, print the description of each argument
***^^**********************************************************************/
#ifdef __ANSI_C__
X void vms_usage( const ARGDESC *argd, argMask_t usage_flags )
#endif
{
X register CONST ARGDESC *ad, *args, *cmd;
X int max_cols = 80, max_lines = 24;
X int margin, ll, pl, 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", ProgName);
X
X ll = strlen( ProgName ) + 8;
X margin = ll + 1;
X longest = 0;
X
X for ( positionals = 0 ; positionals < 2 ; positionals++ ) {
X for ( args = argd ; args ; args = cmd_defargs(args) ) {
X for ( ad = ARG_FIRST(args) ; !ARG_isEND(ad) ; ARG_ADVANCE(ad) ) {
X argName_t buf, 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_name( 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);
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
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 indent_para(fp, max_cols, 8, buf, longest+2, arg_description(ad) );
X }/*for each ad */
X }/* for each argd */
X }/* for each parm-type */
X
X if ( pgactive(fp) ) (VOID) pgclose( fp );
}
X
SHAR_EOF
chmod 0664 parseargs/vms_args.c ||
echo 'restore of parseargs/vms_args.c failed'
Wc_c="`wc -c < 'parseargs/vms_args.c'`"
test 30360 -eq "$Wc_c" ||
echo 'parseargs/vms_args.c: original size 30360, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/vprintf.c ==============
if test -f 'parseargs/vprintf.c' -a X"$1" != X"-c"; then
echo 'x - skipping parseargs/vprintf.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/vprintf.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/vprintf.c' &&
/* Portable vsprintf by Robert A. Larson <blarson at skat.usc.edu> */
X
/* Copyright 1989 Robert A. Larson.
X * Distribution in any form is allowed as long as the author
X * retains credit, changes are noted by their author and the
X * copyright message remains intact. This program comes as-is
X * with no warentee of fitness for any purpose.
X *
X * Thanks to Doug Gwyn, Chris Torek, and others who helped clarify
X * the ansi printf specs.
X *
X * Please send any bug fixes and improvements to blarson at skat.usc.edu .
X * The use of goto is NOT a bug.
X */
X
/* Feb 7, 1989 blarson First usenet release */
/* Oct 20, 1990 Brad Appleton -- enclosed in #ifdef BSD for parseargs */
/* Oct 21, 1990 Brad Appleton -- added test in #ifdef VPRINTF_TEST */
/* Feb 25, 1990 Brad Appleton -- #included "useful.h" and added #ifdefs
X * to compile for ANSI-C as well as K&R
X */
X
X
/* This code implements the vsprintf function, without relying on
X * the existance of _doprint or other system specific code.
X *
X * Define NOVOID if void * is not a supported type.
X *
X * Two compile options are available for efficency:
X * INTSPRINTF should be defined if sprintf is int and returns
X * the number of chacters formated.
X * LONGINT should be defined if sizeof(long) == sizeof(int)
X *
X * They only make the code smaller and faster, they need not be
X * defined.
X *
X * UNSIGNEDSPECIAL should be defined if unsigned is treated differently
X * than int in argument passing. If this is definded, and LONGINT is not,
X * the compiler must support the type unsingned long.
X *
X * Most quirks and bugs of the available sprintf fuction are duplicated,
X * however * in the width and precision fields will work correctly
X * even if sprintf does not support this, as will the n format.
X *
X * Bad format strings, or those with very long width and precision
X * fields (including expanded * fields) will cause undesired results.
X */
X
X /* Parseargs only needs this stuff for BSD Unix -- Brad Appleton */
#include <useful.h>
X
#ifdef BSD
#include <stdio.h>
#include <ctype.h>
X
#ifdef OSK /* os9/68k can take advantage of both */
# define LONGINT
# define INTSPRINTF
#endif
X
/* This must be a typedef not a #define! */
#ifdef NOVOID
X typedef char *pointer;
#else
X typedef void *pointer;
#endif
X
#ifdef INTSPRINTF
# define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
#else
# define Sprintf(string,format,arg) (\
X sprintf((string),(format),(arg)),\
X strlen(string)\
)
#endif
X
typedef int *intp;
X
#ifdef __ANSI_C__
X int vsprintf(char *dest, register const char *format, va_list args)
#else
X int vsprintf(dest, format, args)
X char *dest;
X register char *format;
X va_list args;
#endif
{
X register char *dp = dest;
X register char c;
X register char *tp;
X char tempfmt[64];
#ifndef LONGINT
X int longflag;
#endif
X
X tempfmt[0] = '%';
X while( (c = *format++) != 0) {
X if(c=='%') {
X tp = &tempfmt[1];
#ifndef LONGINT
X longflag = 0;
#endif
continue_format:
X switch(c = *format++) {
X case 's':
X *tp++ = c;
X *tp = '\0';
X dp += Sprintf(dp, tempfmt, VA_ARG(args, char *));
X break;
X case 'u':
X case 'x':
X case 'o':
X case 'X':
#ifdef UNSIGNEDSPECIAL
X *tp++ = c;
X *tp = '\0';
#ifndef LONGINT
X if(longflag)
X dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned long));
X else
#endif
X dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned));
X break;
#endif
X case 'd':
X case 'c':
X case 'i':
X *tp++ = c;
X *tp = '\0';
#ifndef LONGINT
X if(longflag)
X dp += Sprintf(dp, tempfmt, VA_ARG(args, long));
X else
#endif
X dp += Sprintf(dp, tempfmt, VA_ARG(args, int));
X break;
X case 'f':
X case 'e':
X case 'E':
X case 'g':
X case 'G':
X *tp++ = c;
X *tp = '\0';
X dp += Sprintf(dp, tempfmt, VA_ARG(args, double));
X break;
X case 'p':
X *tp++ = c;
X *tp = '\0';
X dp += Sprintf(dp, tempfmt, VA_ARG(args, pointer));
X break;
X case '-':
X case '+':
X case '0':
X case '1':
X case '2':
X case '3':
X case '4':
X case '5':
X case '6':
X case '7':
X case '8':
X case '9':
X case '.':
X case ' ':
X case '#':
X case 'h':
X *tp++ = c;
X goto continue_format;
X case 'l':
#ifndef LONGINT
X longflag = 1;
X *tp++ = c;
#endif
X goto continue_format;
X case '*':
X tp += Sprintf(tp, "%d", VA_ARG(args, int));
X goto continue_format;
X case 'n':
X *VA_ARG(args, intp) = dp - dest;
X break;
X case '%':
X default:
X *dp++ = c;
X break;
X }
X } else *dp++ = c;
X }
X *dp = '\0';
X return dp - dest;
}
X
X
#ifdef __ANSI_C__
X int vfprintf(FILE *dest, register const char *format, va_list args)
#else
X int vfprintf(dest, format, args)
X FILE *dest;
X register char *format;
X va_list args;
#endif
{
X register char c;
X register char *tp;
X register int count = 0;
X char tempfmt[64];
#ifndef LONGINT
X int longflag;
#endif
X
X tempfmt[0] = '%';
X while(c = *format++) {
X if(c=='%') {
X tp = &tempfmt[1];
#ifndef LONGINT
X longflag = 0;
#endif
continue_format:
X switch(c = *format++) {
X case 's':
X *tp++ = c;
X *tp = '\0';
X count += fprintf(dest, tempfmt, VA_ARG(args, char *));
X break;
X case 'u':
X case 'x':
X case 'o':
X case 'X':
#ifdef UNSIGNEDSPECIAL
X *tp++ = c;
X *tp = '\0';
#ifndef LONGINT
X if(longflag)
X count += fprintf(dest, tempfmt, VA_ARG(args, unsigned long));
X else
#endif
X count += fprintf(dest, tempfmt, VA_ARG(args, unsigned));
X break;
#endif
X case 'd':
X case 'c':
X case 'i':
X *tp++ = c;
X *tp = '\0';
#ifndef LONGINT
X if(longflag)
X count += fprintf(dest, tempfmt, VA_ARG(args, long));
X else
#endif
X count += fprintf(dest, tempfmt, VA_ARG(args, int));
X break;
X case 'f':
X case 'e':
X case 'E':
X case 'g':
X case 'G':
X *tp++ = c;
X *tp = '\0';
X count += fprintf(dest, tempfmt, VA_ARG(args, double));
X break;
X case 'p':
X *tp++ = c;
X *tp = '\0';
X count += fprintf(dest, tempfmt, VA_ARG(args, pointer));
X break;
X case '-':
X case '+':
X case '0':
X case '1':
X case '2':
X case '3':
X case '4':
X case '5':
X case '6':
X case '7':
X case '8':
X case '9':
X case '.':
X case ' ':
X case '#':
X case 'h':
X *tp++ = c;
X goto continue_format;
X case 'l':
#ifndef LONGINT
X longflag = 1;
X *tp++ = c;
#endif
X goto continue_format;
X case '*':
X tp += Sprintf(tp, "%d", VA_ARG(args, int));
X goto continue_format;
X case 'n':
X *VA_ARG(args, intp) = count;
X break;
X case '%':
X default:
X putc(c, dest);
X count++;
X break;
X }
X } else {
X putc(c, dest);
X count++;
X }
X }
X return count;
}
X
#ifdef __ANSI_C__
X int vprintf(const char *format, va_list args)
#else
X int vprintf(format, args)
X char *format;
X va_list args;
#endif
{
X return vfprintf(stdout, format, args);
}
#endif /* BSD Unix ONLY */
X
X /* use a VERY SIMPLE test case to test this out -- Brad Appleton */
#ifdef VPRINTF_TEST
X
/*VARARGS1*/
#ifdef __ANSI_C__
X int vtest( char *fmt, ... )
#else
X int vtest( fmt, va_alist )
X char *fmt;
X va_dcl
#endif
{
X va_list ap;
X int rc;
X
X VA_START(ap, fmt);
X rc = vprintf( fmt, ap );
X VA_END(ap);
X
X return rc;
}
X
void main()
{
X printf( "its a %s %% day in the %d neighborhood for %*s\n",
X "pitiful", 4, 8, "fun" );
X
X vtest( "its a %s %% day in the %d neighborhood for %*s\n",
X "pitiful", 4, 8, "fun" );
}
X
#endif /* VPRINTF_TEST */
SHAR_EOF
chmod 0664 parseargs/vprintf.c ||
echo 'restore of parseargs/vprintf.c failed'
Wc_c="`wc -c < 'parseargs/vprintf.c'`"
test 8146 -eq "$Wc_c" ||
echo 'parseargs/vprintf.c: original size 8146, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/winsize.c ==============
if test -f 'parseargs/winsize.c' -a X"$1" != X"-c"; then
echo 'x - skipping parseargs/winsize.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/winsize.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/winsize.c' &&
/*************************************************************************
** ^FILE: winsize.c - implement the routine get_winsize()
**
** ^DESCRIPTION:
** Implement the get_winsize() function for various windowing and
** operating systems.
**
** ^HISTORY:
** 10/01/90 Brad Appleton <brad at ssd.csd.harris.com> Created
***^^**********************************************************************/
X
X
/***************************************************************************
** ^FUNCTION: get_winsize - get the current window size
**
** ^SYNOPSIS:
** void get_winsize( fd, nrows, ncols )
**
** ^PARAMETERS:
** int fd;
** -- file-descriptor associated with the "output-window"
**
** int *nrows;
** -- pointer to number of rows in window
**
** int *ncols;
** -- pointer to number of columns in window
**
** ^DESCRIPTION:
** Get_winsize will attempt to determine the maximum number of
** rows and colums that will fit on one screen-full of the associated
** output device. If it fails to do this, it will assume the "window"
** is a 24x80 (rows by columns) display.
**
** ^REQUIREMENTS:
** fd must correspond to a valid output device.
**
** ^SIDE-EFFECTS:
** The memory addressed by nrows and ncols is assigned the corresponding
** appropriate value(s).
**
** ^RETURN-VALUE:
** None.
**
** ^ALGORITHM:
** System dependent.
***^^**********************************************************************/
X
#if ( defined(__STDC__) || defined(c_plusplus) || defined(__cplusplus) )
# define GET_WINSIZE(fd,nrows,ncols) \
X void get_winsize( int fd, int *nrows, int *ncols )
#else
# define GET_WINSIZE(fd,nrows,ncols) \
X void get_winsize( fd, nrows, ncols ) \
X int fd, *nrows, *ncols; /* nrows and ncols are passed by reference */
#endif
X
#include <stdio.h>
#include <useful.h>
X
#define DEFAULT_ROWS 24
#define DEFAULT_COLS 80
X
#ifdef vms
X
#include <stdio.h>
#include <iodef.h>
#include <ssdef.h>
#include <descrip.h>
X
X /* structure to contain terminal characteristics */
typedef struct {
X short garb1, cols;
X char garb2, garb3, garb4, rows;
} termchar_t;
X
int sys$assign();
int sys$qiow();
int sys$dassgn();
X
GET_WINSIZE( fd, nrows, ncols )
{
X int c, charlen = 8;
X termchar_t termchar;
X int chan;
X $DESCRIPTOR( devnam,"SYS$COMMAND" );
X
X sys$assign( &devnam, &chan, 0, 0 );
X sys$qiow( 0, chan, IO$_SENSEMODE, 0, 0, 0, &termchar, &charlen, 0, 0, 0, 0 );
X sys$dassgn( chan );
X
X *nrows = ( termchar.rows > 0 ) ? (int) termchar.rows : DEFAULT_ROWS;
X *ncols = ( termchar.cols > 0 ) ? (int) termchar.cols : DEFAULT_COLS;
}
X
#else
#ifdef unix
X
X /*
X ** we will either try to access terminfo through the termcap-interface
X ** in the curses library (which would require linking with -lcurses)
X ** or use termcap directly (which would require linking with -ltermcap)
X */
#ifndef USE_TERMCAP
#if ( defined(USE_TERMINFO) || defined(USE_CURSES) )
#define USE_TERMCAP
#endif
#endif
X
X
#ifdef USE_TERMCAP
# define TERMBUFSIZ 1024
# define UNKNOWN_TERM "unknown"
# define DUMB_TERMBUF "dumb:co#80:hc:"
extern int tgetent();
extern int tgetnum();
#endif
X
X
X /* try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */
#include <termios.h>
#if ( !defined(TIOCGWINSZ) && !defined(TIOCGSIZE) && !defined(WIOCGETD) )
#include <sys/ioctl.h>
#endif
X
X /* if still dont have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */
#if ( !defined(TIOCGWINSZ) && !defined(TIOCGSIZE) && !defined(WIOCGETD) )
#include <sgtty.h>
#endif
X
/*
** get_winsize() -- determine # of rows/columns that will fit on the screen.
**
** The environment variables $LINES and $COLUMNS will be used if they exist.
** If not, then the TIOCGWINSZ call to ioctl() is used (if it is defined).
** If not, then the TIOCGSIZE call to ioctl() is used (if it is defined).
** If not, then the WIOCGETD call to ioctl() is used (if it is defined).
** If not, then get the info from terminfo/termcap (if it is there)
** Otherwise, assume we have a 24x80 screen.
*/
X
extern int ioctl();
extern int isatty();
extern long atol();
extern char *getenv();
X
GET_WINSIZE( fd, nrows, ncols )
{
X char *lines_env, *cols_env;
X long lrow = 0, lcol = 0;
X int lines = 0, cols = 0;
#ifdef USE_TERMCAP
X char term_buf[ TERMBUFSIZ ], *term_env;
#endif
#ifdef TIOCGWINSZ
X struct winsize win;
#else
#ifdef TIOCGSIZE
X struct ttysize win;
#else
#ifdef WIOCGETD
X struct uwdata win;
#endif
#endif
#endif
X
X /* make sure that fd corresponds to a terminal */
X if ( !isatty( fd ) ) {
X *nrows = DEFAULT_ROWS;
X *ncols = DEFAULT_COLS;
X return;
X }
X
X /* LINES & COLUMNS environment variables override everything else */
X lines_env = getenv( "LINES" );
X if ( lines_env && (lrow = atol(lines_env)) > 0 ) {
X *nrows = lines = (int) lrow;
X }
X
X cols_env = getenv( "COLUMNS" );
X if ( cols_env && (lcol = atol(cols_env)) > 0 ) {
X *ncols = cols = (int) lcol;
X }
X
#ifdef TIOCGWINSZ
X /* see what ioctl() has to say (overrides terminfo & termcap) */
X if ( (!lines || !cols) && ioctl(fd, TIOCGWINSZ, &win) != -1 ) {
X if ( !lines && win.ws_row > 0 ) {
X *nrows = lines = (int) win.ws_row;
X }
X
X if ( !cols && win.ws_col > 0 ) {
X *ncols = cols = (int) win.ws_col;
X }
X }/*if*/
#else
#ifdef TIOCGSIZE
X /* see what ioctl() has to say (overrides terminfo & termcap) */
X if ( (!lines || !cols) && ioctl(fd, TIOCGSIZE, &win) != -1 ) {
X if ( !lines && win.ts_lines > 0 )
X *nrows = lines = (int) win.ts_lines;
X
X if ( !cols && win.ts_cols > 0 )
X *ncols = cols = (int) win.ts_cols;
X }/*if*/
#else
#ifdef WIOCGETD
X /* see what ioctl() has to say (overrides terminfo & termcap) */
X if ( (!lines || !cols) && ioctl(fd, WIOCGETD, &win) != -1 ) {
X if ( !lines && win.uw_height > 0 )
X *nrows = lines = (int) (win.uw_height / win.uw_vs);
X
X if ( !cols && win.uw_width > 0 )
X *ncols = cols = (int) (win.uw_width / win.uw_hs);
X }/*if*/
#endif
#endif
#endif
X
#ifdef USE_TERMCAP
X /* see what terminfo/termcap has to say */
X if ( !lines || !cols ) {
X if ( !(term_env = getenv("TERM")) )
X term_env = UNKNOWN_TERM;
X
X if ( (tgetent(term_buf, term_env) <= 0) )
X strcpy( term_buf, DUMB_TERMBUF );
X
X if ( !lines && (lrow = tgetnum("li")) > 0 )
X *nrows = lines = (int) lrow;
X
X if ( !cols && (lcol = tgetnum("co")) > 0 )
X *ncols = cols = (int) lcol;
X }
#endif
X
X /* use 80x24 if all else fails */
X if ( !lines ) *nrows = DEFAULT_ROWS;
X if ( !cols ) *ncols = DEFAULT_COLS;
X
}/*get_winsize()*/
X
#else
X
GET_WINSIZE( fd, nrows, ncols )
{
X /* just use 80x24 */
X *nrows = DEFAULT_ROWS;
X *ncols = DEFAULT_COLS;
}
X
#endif /* not a vms system */
#endif /* not a unix-system */
X
#ifdef WINSIZE_TEST
X /* test get_winsize to see if it works */
main()
{
X int rows, cols;
X
X get_winsize( fileno(stderr), &rows, &cols );
X printf( "Output will be %d rows by %d columns\n", rows, cols );
X exit( 0 );
}
X
#endif
SHAR_EOF
chmod 0664 parseargs/winsize.c ||
echo 'restore of parseargs/winsize.c failed'
Wc_c="`wc -c < 'parseargs/winsize.c'`"
test 7121 -eq "$Wc_c" ||
echo 'parseargs/winsize.c: original size 7121, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/xparse.c ==============
if test -f 'parseargs/xparse.c' -a X"$1" != X"-c"; then
echo 'x - skipping parseargs/xparse.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/xparse.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/xparse.c' &&
/*************************************************************************
** ^FILE: xparse.c - library functions for the parsargs(3) package
**
** ^DESCRIPTION:
** This file implements the following functions in the parseargs library:
**
** init_args() -- constructor for a command-object
** usage() -- pretty-print the command-usage
** parsecntl() -- control parsing, get/set command-attributes
** parseargs() -- parse argumenst from a string vector
** fparseargs() -- parse arguments from a file pointer
** lparseargs() -- parse arguments from an arglist
** sparseargs() -- parse arguyments in a string
** vparseargs() -- parse arguments from a variable argument list
**
** It should be noted that sparseargs() splits the given string up into
** a whitespace separated series of tokens, whereas vparseargs assumes
** that each parameter is already a single token (hence performs no
** token splitting).
**
** Each of these functions returns 0 upon success and non-zero otherwise
** (except for usage() & init_args, which have no return value).
**
** ^FILES:
** <useful.h>
** <parseargs.h>
**
** ^SEE_ALSO:
** argtype(3), parseargs(1), parseargs(3), parsecntl(3),
**
** ^CAVEATS:
** Because of the way argument parsing is implemented under UNIX, MS-DOS
** and OS/2, option arguments which contain a leading dash (`-') (or
** whatever the option prefix character is defined to be) may not be
** specified as a separate argument on the command line, it must be part
** of the same argument. That is to say that if a program has a -f option
** that requires a string argument, then the following:
** -f-arg
**
** will properly assign the string "-arg" to the option whereas the
** following:
** -f -arg
**
** will be interpreted by parseargs as two option strings: the first of
** which ("-f") is missing a required argument and the second of which
** ("-arg") will most likely be flagged as an invalid option.
**
** Similarly, if the user requires an ARGLIST option to take multiple
** arguments with leading dashes then the following method must be used:
** It is a "feature" of parseargs that ARGLIST arguments are always
** appended to the current list of arguments for the given option. Thus,
** if "-f" is an option taking a list of arguments, then the following
** are all equivalent:
** -farg1 arg2
** -f arg1 arg2
** -farg1 -farg2
** -f arg1 -f arg2
**
** Hence multiple "leading dash" arguments may specified as follows:
** -f-dash_arg1 -f-dash_arg2 ...
**
** ^BUGS:
** When a non-multivalued argument appears more than once on the
** command-line then only the last value supplied is used. A problem
** occurs however in the following scenario: suppose `-s' is an option
** that takes an optional string argument (nd suppose `-x' is some
** boolean flag). Then if the following command-line is issued:
**
** command -s string -x -s
**
** then, the argument flags will properly correspond to the second
** instance of the `-s' option (namely ARGGIVEN will be set but ARGVAL-
** GIVEN will be unset) but the value associated with the option will be
** "string" (because the first instance overwrote the default).
** Because of this, it may be safest to reassign the default value if
** ARGGIVEN is set but ARGVALGIVEN is unset.
**
** ^HISTORY:
** 01/02/91 Brad Appleton <brad at ssd.csd.harris.com> Created
***^^**********************************************************************/
X
#include <stdio.h>
#include <ctype.h>
#include <useful.h>
#include "strfuncs.h"
X
#define PARSEARGS_PRIVATE /* include private definitions */
#define PARSEARGS_NEXTERNS /* exclude external declarations */
#include "parseargs.h"
X
#ifdef amiga_style
# define pa_DEFAULTS 0x000
# define parse_argv_style amiga_parse
# define print_usage_style amiga_usage
X EXTERN int amiga_parse ARGS(( char **, ARGDESC * ));
X EXTERN VOID amiga_usage ARGS(( const ARGDESC *, argMask_t ));
#endif
#ifdef ibm_style
# define pa_DEFAULTS pa_ANYCASE
# define parse_argv_style ibm_parse
# define print_usage_style ibm_usage
X EXTERN int ibm_parse ARGS(( char **, ARGDESC * ));
X EXTERN VOID ibm_usage ARGS(( const ARGDESC *, argMask_t ));
#endif
#ifdef unix_style
# define pa_DEFAULTS pa_FLAGS1ST
# define parse_argv_style unix_parse
# define print_usage_style unix_usage
X EXTERN int unix_parse ARGS(( char **, ARGDESC * ));
X EXTERN VOID unix_usage ARGS(( const ARGDESC *, argMask_t ));
#endif
#ifdef vms_style
# define pa_DEFAULTS pa_PROMPT
# define parse_argv_style vms_parse
# define print_usage_style vms_usage
X EXTERN int vms_parse ARGS(( char **, ARGDESC * ));
X EXTERN VOID vms_usage ARGS(( const ARGDESC *, argMask_t ));
#endif
X
X
#if vms
# define USER_VARIABLE "symbol"
#else
# define USER_VARIABLE "environment variable"
#endif
X
X
/***************************************************************************
** ^MACRO: SYNTAX_ERROR - check for syntax errors & missing required arguments
**
** ^SYNOPSIS:
** SYNTAX_ERROR(status, argd)
**
** ^PARAMETERS:
** status
** -- current parsing status returned by last xparsexxx() call
**
** argd
** --argdesc-array
**
** ^RETURN-VALUE:
** Evaluates to TRUE if need to exit, FALSE otherwise
**
** ^ALGORITHM:
** - if (!pa_NOCHECK) and (verify_argreqs == error) then return TRUE
** - else return FALSE
***^^**********************************************************************/
#define SYNTAX_ERROR(status, argd) ( !verify_argreqs(argd, &status) )
X
X
/***************************************************************************
** ^GLOBAL-VARIABLE: ProgName
**
** ^VISIBILITY:
** external global (visible to functions in all files)
**
** ^DESCRIPTION:
** ProgName (which is initially NULL) will be used to point to the
** command-name (specified on the command-line) of the command that
** has most recently invoked a function in the parseargs library.
***^^**********************************************************************/
CONST char *ProgName = (char *)NULL;
X
EXTERN VOID syserr ARGS((const char *, ...));
EXTERN VOID usrerr ARGS((const char *, ...));
EXTERN VOID eprintf ARGS((const char *, ...));
X
#ifdef vms_style
X EXTERN BOOL argInput ARGS((ARGDESC *, char *, BOOL));
X EXTERN BOOL argOutput ARGS((ARGDESC *, char *, BOOL));
#endif
X
#define MAXLINE 256
X
X
/* override argument descriptor, if none given by user */
static ARGDESC Empty_ArgDesc[] = { START_ARGUMENTS, END_ARGUMENTS };
X
/***************************************************************************
** ^SECTION: DEFAULT-ARGUMENTS
** Each argdesc-array has an initial default argument list (which may be
** reset using the pc_DEFARGS function code with parsecntl). This initial
** default argument-list contains `?' and `H' which may be used as single
** character keywords to display command-usage for all command-line
** styles. Similarly, "?", "H", and "Help" may be used as long-keywords
** to display command-usage for all command-line styles. In Addition,
** for VMS style commands, the qualifiers /INPUT=file, /OUTPUT=file, and
** /ERROR=file, may be used to redirect stdin, stdout, and stderr
** (respectively) to a file. For AmigaDOS style commands, the keyword
** "ENDKWDS" may be used to disable parsing for any more keywords on
** the command-line.
***^^**********************************************************************/
static ARGDESC Default_ArgDesc[] = {
X START_ARGUMENTS,
X
/* <name> <flags> <type> <valp> <prompt> */
X { '?', ARGHIDDEN, argUsage, __ NULL, "? (print usage and exit)" },
X { 'H', ARGHIDDEN, argUsage, __ NULL, "Help (print usage and exit)" },
X
#ifdef amiga_style
X { '-', ARGHIDDEN, argEnd, __ NULL, "ENDKeyWorDS" },
#endif
X
#ifdef vms_style
X { '<', ARGHIDDEN, argInput, __ stdin, "INPUT (redirect SYS$INPUT)" },
X { '>', ARGHIDDEN, argOutput, __ stdout, "OUTPUT (redirect SYS$OUTPUT)" },
X { '%', ARGHIDDEN, argOutput, __ stderr, "ERROR (redirect SYS$ERROR)" },
#endif
X
X END_ARGUMENTS
};
X
X
#ifdef AmigaDOS
# define getenv(s) CHARNULL
# define envfree(s) s = CHARNULL
#endif
X
#if ( defined(MSDOS) || defined(OS2) )
X EXTERN char *getenv ARGS(( const char * ));
# define envfree(s) s = CHARNULL
#endif
X
#ifdef unix
X EXTERN char *getenv ARGS(( const char * ));
# define envfree(s) s = CHARNULL
#endif
X
#ifdef vms
# define getenv(s) getsymbol(s)
# define envfree(s) (s) = ( !(s) ) ? CHARNULL : (free(s), CHARNULL)
# include <descrip.h>
# include <libdef.h>
X
# define MAXLEN 255
X
X /***************************************************************************
X ** ^FUNCTION: get_symbol - retrieve the value of a VMS symbol
X **
X ** ^SYNOPSIS:
X */
# ifndef __ANSI_C__
X char *get_symbol( sym_name )
X /*
X ** ^PARAMETERS:
X */
X char *sym_name;
X /* -- name of the symbol to retrieve
X */
# endif /* !__ANSI_C__ */
X
X /* ^DESCRIPTION:
X ** Get_symbol will lookup the named symbol and return its value
X ** as a string.
X **
X ** ^REQUIREMENTS:
X ** sym_name should correspond to the name of a pre-defined symbol.
X **
X ** ^SIDE-EFECTS:
X ** None.
X **
X ** ^RETURN-VALUE:
X ** NULL if the symbol is not found, otherwise it copies the symbol
X ** value and returns the address of the copy (which may later be
X ** deallocated using free()).
X **
X ** ^ACKNOWLEDGEMENTS:
X ** Thanx to Jim Barbour for writing most of this code. --BDA
X **
X ** ^ALGORITHM:
X ** Trivial - just use the LIB$GET_SYMBOL system service.
X ***^^**********************************************************************/
# ifdef __ANSI_C__
X char *get_symbol( const char *sym_name )
# endif
X {
X unsigned long stat, lib$get_symbol();
X unsigned short buflen;
X char sym_value[ MAXLEN ];
X $DESCRIPTOR( sym_name_d, sym_name );
X $DESCRIPTOR( sym_value_d, sym_value );
X
X sym_value_d.dsc$w_length = MAXLEN;
X sym_name_d.dsc$w_length = strlen( sym_name );
X stat = lib$get_symbol( &sym_name_d, &sym_value_d, &buflen, (void *)0 );
X if ( stat == LIB$_NOSUCHSYM ) {
X return CHARNULL;
X }
X else if ( ! (stat & 1) ) {
X exit(stat);
X }
X sym_value[ buflen ] = '\0';
X return strdup( sym_value );
X }
#endif /* vms */
X
X
/***************************************************************************
** ^FUNCTION: is_interactive - determine if a stream is "interactive"
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X static BOOL is_interactive( fd )
/*
** ^PARAMETERS:
*/
X int fd;
/* -- file descriptor associated with the input stream
*/
#endif /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
** Is_interactive determines whether or not the given i/o stream is
** associated with a terminal.
**
** ^REQUIREMENTS:
** Fd must correspond to a valid, open, file-descriptor.
SHAR_EOF
true || echo 'restore of parseargs/xparse.c failed'
fi
echo 'End of part 11'
echo 'File parseargs/xparse.c is continued in part 12'
echo 12 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.
More information about the Comp.sources.misc
mailing list