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