v17i054: parseargs - functions to parse command line arguments, Part09/12

Brad Appleton brad at hcx1.ssd.csd.harris.com
Tue Mar 19 01:57:07 AEST 1991


Submitted-by: Brad Appleton <brad at hcx1.ssd.csd.harris.com>
Posting-number: Volume 17, Issue 54
Archive-name: parseargs/part09

This is part 9 of parseargs

#!/bin/sh
# this is Part.09 (part 9 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file parseargs/pgopen.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 9; 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/pgopen.c'
else
echo 'x - continuing file parseargs/pgopen.c'
sed 's/^X//' << 'SHAR_EOF' >> 'parseargs/pgopen.c' &&
**    pager-file-pointer.
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
**    Zero if the pager is active; non-zero otherwise.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int pgactive( const FILE *pager_fp )
#endif
{
X   return  ( (Pager_Type != PG_CLOSED)  &&  (pager_fp) );
}
X
X
/***************************************************************************
** ^FUNCTION: pgclose - close the pager.
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   int pgclose( pager_fp )
/*
** ^PARAMETERS:
*/
X   FILE *pager_fp;
/*    -- the file-pointer returned by pgopen()
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Pgclose will flush any remaining output and close the pager.
**
** ^REQUIREMENTS:
**    pgopen() must first be called in order to obtain a valid
**    pager-file-pointer.
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
**    Returns 0 if the pager was succesfully close; non-zero if it wasnt
**    in use to begin with.
**
** ^ALGORITHM:
**    - if ( pager-not-in-use )  return 1
**    - flush any remaining pager output
**    - if we used popen() to open this pager then
**       - call pclose to close the pager-program
**       - unset the SIGPIPE signal-handler
**       - wait for the pager-process to die
**      end-if
**    - reset the pager-file-pointer to NULL
**    - set the pager-state to closed
**    - return 0
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int pgclose( FILE *pager_fp )
#endif
{
X   if ( Pager_Type == PG_CLOSED  ||  !Pager_FP  ||  !pager_fp )  return  1;
X
X   fflush( Pager_FP );
X
X   if ( Pager_Type == PG_ENV  ||  Pager_Type == PG_DFLT ) {
X      signal( SIGPIPE, (void (*)())SIG_IGN );
X      wait( (int *) 0 );
X   }
X
X   Pager_FP = (FILE *)NULL;
X   Pager_Type = PG_CLOSED;
X
X   return  0;
}
X
X
/***************************************************************************
** ^FUNCTION: pgopen - open the pager
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   FILE *pgopen( fp, pager_cmd )
/*
** ^PARAMETERS:
*/
X   FILE *fp;
/*    -- the file pointer to use if popen() fails
*/
X   char *pager_cmd;
/*    -- name of the pager-program to pass to popen()
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Pgopen will attempt to "redirect" output from the given file
**    pointer to the pager specified by <pager_cmd>.  If <fp> is NOT
**    connected to a terminal or <pager_cmd> cannot be succesfully
**    opened, then <fp> is resturned output is sent to it unpaginated.
**    Otherwise, pgopen will try to open <pager_cmd> for input. If it
**    cannot succeed it tries to open $PAGER for input. If this also
**    fails then /usr/ucb/more is tried. If all else fails, return <fp>.
**
** ^REQUIREMENTS:
**    pager_cmd should be the full-pathname name of a valid, executable
**    program which reads from standard input and writes (one screenful
**    at a time) to the terminal.
**
** ^SIDE-EFECTS:
**    If popen() succeeds, the SIGPIPE signal is trapped.
**
** ^RETURN-VALUE:
**    returns 0 upon success, non-zero if the pager is already in use.
**
** ^ALGORITHM:
**    - if the pager is already in use, return 1
**    - if <fp> is not connected to a terminal, use it for output and return 0
**    - set up recovery point for SIGPIPE signal
**    - if we can open the pager_cmd, check for a SIGPIPE error
**    - if either of the above fails, then try the same with $PAGER
**    - if either of the above fails, then try the same with /usr/ucb/more
**    - if either of the above fails, just use <fp> and return
***^^**********************************************************************/
#ifdef __ANSI_C__
X   FILE *pgopen( FILE *fp, const char *pager_cmd )
#endif
{
X   pager_t  pg_type;
X   char     pg_name[ MAX_NAME_LEN ];
X
X      /* if a pager is already open - ignore this call */
X   if ( Pager_Type != PG_CLOSED  ||  Pager_FP )  return  fp;
X
X      /*
X      ** dont page output if it has been redirected
X      */
X   if ( !isTERMINAL(fileno(fp)) ) {
X      Pager_Type = PG_FILE;
X      Pager_FP = fp;
X      return  fp;
X   }
X
X   *pg_name = '\0';
X   if ( pager_cmd )  strcpy( pg_name, pager_cmd );
X   pg_type = pg_pathname( pg_name );
X   Pager_FP = (FILE *)NULL;
X
X      /* jump here after pg_error fields SIGPIPE */
X   if ( setjmp( pg_recover ) ) {
X      (void) pclose( Pager_FP );
X      Pager_FP = (FILE *)NULL;
X      pg_type = ( pg_type == PG_ENV ) ? PG_DFLT : PG_NONE;
X   }
X
X      /* keep trying till we get a valid file-pointer */
X   while ( !Pager_FP ) {
X      switch( pg_type ) {
X         case PG_DFLT:
X               /* jump here if both $PAGER and DEFAULT-PAGER fail */
X            if ( setjmp( pg_recover )) {
X               (void) pclose( Pager_FP );
X               Pager_FP = (FILE *)NULL;
X               pg_type = PG_NONE;
X               continue;
X            }
X               /* fall through to next case */
X
X         case PG_ENV:
X            signal( SIGPIPE, pg_error );
X            Pager_FP = (FILE *) popen( pg_name, "w" );
X            if ( !Pager_FP ) {
X               if ( pg_type == PG_ENV ) {
X                  Pager_FP = (FILE *)NULL;
X                  pg_type = PG_DFLT;
X               }
X               else {
X                  Pager_FP = fp;
X                  pg_type = PG_NONE;
X               }
X            }
X            else {
X                  /*
X                  ** Sleep for a bit, just so we block, and the child
X                  ** process can get moving. Then attempt to write to
X                  ** the pager pipeline. If the pager is bad then the
X                  ** pipe will be broken and pg_error() will handle
X                  ** the broken-pipe signal. Othwerwise, the write will
X                  ** succeed and we'll reset the handler to ignore the
X                  ** broken pipe signal.
X                  */
X               sleep( 1 );
X               fputc( '\n', Pager_FP );
X               fflush( Pager_FP );
X               signal( SIGPIPE, (void (*)())SIG_IGN );
X            }
X            break;
X
X         case PG_NONE:
X         case PG_FILE:
X            Pager_FP = fp;
X            break;
X
X         default:
X            fprintf( stderr, "Unrecognized state [%d] in pgopen()\n",
X                     pg_type );
X            exit( -1 );
X      }/*switch*/
X   }/*while*/
X
X   Pager_Type = pg_type;
X   return  Pager_FP;
}
X
X
/***************************************************************************
** ^FUNCTION: pg_error - handle error when trying to open a pager
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static void pg_error()
#endif
/*
** ^PARAMETERS:
**    None.
**
** ^DESCRIPTION:
**    Pgerror is called when the SIGPIPE signal is recieved. If SIGPIPE
**    is recieved, it means that popen succesfully forked the shell to
**    run the pager but the pager-command itself broke the read-end of
**    the pipe between us (i.e. it is an invalid pager-program or it crashed).
**
**    When SIGPIPE is recieved, this routine will reset the signal handler
**    to its previous value and jump to the recovery point set up by pgopen.
**
** ^REQUIREMENTS:
**    Pgopen must set up this function is the SIGPIPE handler function.
**
**    Pgopen must place the address of the desired recovery point in
**    pg_recover.
**
** ^SIDE-EFECTS:
**    Resets SIGPIPE signal-handler and performs a non-local goto.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   static void pg_error( void )
#endif
{
X   signal( SIGPIPE, (void (*)())SIG_IGN );
X   longjmp( pg_recover, 1 );
}
X
X
/***************************************************************************
** ^FUNCTION: pg_pathname - get name of pager-program to use
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static pager_t pg_pathname( pager_cmd )
/*
** ^PARAMETERS:
*/
X   char *pager_cmd;
/*    -- name of the pager-program to verify
*/
#endif  /* !__ANSI_C__ */
X 
/* ^DESCRIPTION:
**    Pg_pathname will determine the name of the pager-program to attempt to
**    open based on the values of pager_cmd, and $PAGER.
**
** ^REQUIREMENTS:
**    pager_cmd must be non-null and be large enough to hold any of the
**    possible pager program-names to be opened.
**
** ^SIDE-EFECTS:
**    pager_cmd is over-written with the name of the pager-command to
**    try to open for output
**
** ^RETURN-VALUE:
**    Returns PG_DFLT if /usr/ucb/more is to be used.
**    Returns PG_ENV if $PAGER or <pager_cmd> is to be used.
**
** ^ALGORITHM:
**    - If pager_cmd is executable then compare it to /usr/ucb/more
**        return PG_ENV if not-equal, else return PG_DFLT
**    - Else
**      - pager_cmd = $PAGER
**      - If $PAGER is executable then compare it to /usr/ucb/more
**          return PG_ENV if not-equal, else return PG_DFLT
**      - Else
**          pager_cmd = /usr/ucb/more
**          return  PG_DFLT
**        End-if
**      End-if
***^^**********************************************************************/
#ifdef __ANSI_C__
X   static pager_t  pg_pathname( char *pager_cmd )
#endif
{
X   char      *pg_name = pager_cmd, *getenv();
X   pager_t   pg_type;
X
X   if ( Pager_Type != PG_NONE )   pg_type = Pager_Type;
X
X      /* see if the given pager is okay */
X   if ( !pg_name  ||  !*pg_name  ||  !access(pg_name, X_OK) ) {
X      pg_name = getenv("PAGER");
X   }
X   else {
X      pg_type = ( strcmp(pager_cmd, DEFAULT_PAGER) ) ? PG_ENV : PG_DFLT;
X      return   pg_type;
X   }
X
X      /* see if $PAGER is ok */
X   if ( !access(pg_name, X_OK) ) {
X      pg_type = ( strcmp(pg_name, DEFAULT_PAGER) ) ? PG_ENV : PG_DFLT;
X      strcpy( pager_cmd, pg_name );
X   }
X   else {
X      pg_type = PG_DFLT;
X      strcpy( pager_cmd, DEFAULT_PAGER );
X   }
X
X   return   pg_type;
}/* pg_pathname */
X
X
#endif  /* USE_PAGER */
SHAR_EOF
echo 'File parseargs/pgopen.c is complete' &&
chmod 0664 parseargs/pgopen.c ||
echo 'restore of parseargs/pgopen.c failed'
Wc_c="`wc -c < 'parseargs/pgopen.c'`"
test 12588 -eq "$Wc_c" ||
	echo 'parseargs/pgopen.c: original size 12588, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/pgopen.h ==============
if test -f 'parseargs/pgopen.h' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/pgopen.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/pgopen.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/pgopen.h' &&
/*************************************************************************
** ^FILE: pgopen.h - include file for pgopen.c
**
** ^DESCRIPTION:
**    If USE_PAGER is #define'd then this file will define the function
**    prototypes needed to use the paging library implemented in pgopen.c;
**    Otherwise it will #define macros with the same name as the paging
**    library routines which do NOT perform any paging.
**
** ^HISTORY:
**    01/02/91 	Brad Appleton 	<brad at ssd.csd.harris.com> 	Created
***^^**********************************************************************/
X
#ifndef NULL
#  include <stdio.h>
#endif
#include <useful.h>
X
#ifdef  USE_PAGER
X   EXTERN   FILE *pgopen    ARGS(( FILE *, const char * ));
X   EXTERN   int   pgclose   ARGS(( FILE * ));
X   EXTERN   int   pgactive  ARGS(( const FILE * ));
#else
#  define  pgopen(fp,s)  (( !fp ) ? fp : (fflush(fp), fp))
#  define  pgclose(fp)   (( !fp ) ?  0 : (fflush(fp), 0))
#  define  pgactive(fp)  ( fp )
#endif
SHAR_EOF
chmod 0664 parseargs/pgopen.h ||
echo 'restore of parseargs/pgopen.h failed'
Wc_c="`wc -c < 'parseargs/pgopen.h'`"
test 977 -eq "$Wc_c" ||
	echo 'parseargs/pgopen.h: original size 977, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/stest.c ==============
if test -f 'parseargs/stest.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/stest.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/stest.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/stest.c' &&
/*************************************************************************
** ^FILE: stest.c - test program for parseargs()
**
** ^DESCRIPTION:
**    This file is the test program for the parseargs(3) function libarary.
**    It is used to test parseargs for all command-line styles (which presently
**    includes: UNIX, VMS, AmigaDOS, MS-DOS, and OS/2).
**
** ^HISTORY:
**    --/--/--	Brad Appleton	<brad at ssd.csd.harris.com>	
**    - Added structured block comments
**    - Added an extra test for both old-style and new-style argument arrays
**    - Added a test for triggers (ARGNOVAL arguments)
**    - Added a test for arguments with optional values (using parsecntl())
**    - Added arg-vector arguments
**
**    --/--/--	Peter da Silva	<peter at ferranti.com>	
**
**    --/--/--	Eric P. Allman	<eric at Berkeley.EDU> 	Created
***^^**********************************************************************/
X
#include <useful.h>
#include <parseargs.h>
X
VERSIONID("$Header: stest.c,v 2.0 89/12/24 00:56:29 eric Exp $");
X
static char Mode[4] = "OFF";
X
/***************************************************************************
** ^FUNCTION: argMine - example ARGNOVAL argument translation routine
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   BOOL argMine( ad, vp, copyf )
/*
** ^PARAMETERS:
*/
X   ARGDESC *ad;
/*    -- the argument descriptor for this parameter.
*/
X   char *vp;
/*    -- a pointer to the string input value.
*/
X   BOOL copyf;
/*    -- if TRUE, the value will be destroyed later, and so should be
**       copied if it will be retained (as for a string).
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    This routine is provided as a (very) simple example of how to use
**    the ARGNOVAL flag to set up "trigger" arguments. Depending upon the
**    implementation of the "trigger" function (this routine), the position
**    of the corresponding argument on the command line may (or may not) be
**    important.
**
** ^REQUIREMENTS:
**    ad should have ARGNOVAL set and this function as its ad_type.
**
** ^SIDE-EFFECTS:
**    The static global variable Mode is (re)written.
**
** ^RETURN-VALUE:
**    TRUE.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
/*ARGSUSED*/
#ifdef __ANSI_C__
X   BOOL argMine( ARGDESC *ad, char *vp, BOOL copyf )
#endif
{
X   strcpy(Mode, "ON");
X   return TRUE;
}
X
/*************************************************************************/
X   /* declare variables to hold values from the command-line */
#define DEF_STR "Default String"
X
typedef ARGVEC_T(char *)  strvec_t;
X
static int	RepCount;
static char	*Name;
static char	*Str     = DEF_STR;
static char	*DirName = ".";
static BOOL	XRated   = FALSE;
static BOOL	XFlag    = FALSE;
static BOOL	YFlag    = TRUE;
static BOOL	ZFlag    = FALSE;
static char	TabChar  = ':';
static ARGVEC_T(int) Integers = ARGVEC_EMPTY(int);
static strvec_t Groups = ARGVEC_EMPTY(char *);
static ArgList  *Argv  = (ArgList *)NULL;
X
/*************************************************************************/
X   /* declare a new style argument-descriptor array */
static
CMD_OBJECT
X   Cmd
X
CMD_NAME
X   "stest -- test program for parseargs"
X
CMD_DESCRIPTION
X   "This program is used to test parseargs for each desired command-line \
style and for both old and new style argument-array declarations.  The actual \
name of the command will be <os>_test.  parseargs will be called twice (with \
the same command-line description) in order to test both the old and the new \
syntax for declaring argument arrays."
X
CMD_ARGUMENTS
X   'n', ARGREQ|ARGPOS, argStr,  __ &Name,  "name (name to look for)",
X   's', ARGVALOPT, argStr,  __ &Str,       "STRing (optional string to use)",
X   'g', ARGVEC,    argStr,  __ &Groups,    "newsGROUPS (newsgroups to test)",
X   'c', ARGOPT,    argInt,  __ &RepCount,  "REPcount (repeat count per group)",
X   'd', ARGOPT,    argStr,   __ &DirName,  "DIRname (work directory)",
X   'i', ARGVEC,    argInt,   __ &Integers, "INTegerS (vector of numbers)",
X   '#', ARGHIDDEN, argBool,  __ &XRated,   "XratedMODE (naughty! naughty!)",
X
X   'x', ARGOPT, argSBool, __ &XFlag, "Xflag (set X flag)",
X   'y', ARGOPT, argUBool, __ &YFlag, "Yflag (unset Y flag)",
X   'z', ARGOPT, argTBool, __ &ZFlag, "Zflag (toggle Z flag)",
X
X   't', ARGOPT,   argChar, __ &TabChar, "TABchar (field delimiter)",
X   'r', ARGNOVAL, argMine, __ NULL,     "raw (trigger raw-mode \
before processing any more arguments on the command-line)",
X
X   ' ', ARGLIST, listStr, __ &Argv, "file (list of files)",
X
X   END_ARGUMENTS
CMD_END
X
X
/*************************************************************************/
X   /* declare an old style argument-descriptor array */
static ARGDESC	Args[] =
{
X   STARTOFARGS,
X
X   'n', ARGREQ|ARGPOS, argStr,  __ &Name,  "name (name to look for)",
X   's', ARGVALOPT, argStr,  __ &Str,       "STRing (optional string to use)",
X   'g', ARGVEC,    argStr,  __ &Groups,    "newsGROUPS (newsgroups to test)",
X   'c', ARGOPT,    argInt,  __ &RepCount,  "REPcount (repeat count per group)",
X   'd', ARGOPT,    argStr,   __ &DirName,  "DIRname (work directory)",
X   'i', ARGVEC,    argInt,   __ &Integers, "INTegerS (vector of numbers)",
X   '#', ARGHIDDEN, argBool,  __ &XRated,   "XratedMODE (naughty! naughty!)",
X
X   'x', ARGOPT, argSBool, __ &XFlag, "Xflag (set X flag)",
X   'y', ARGOPT, argUBool, __ &YFlag, "Yflag (unset Y flag)",
X   'z', ARGOPT, argTBool, __ &ZFlag, "Zflag (toggle Z flag)",
X
X   't', ARGOPT,   argChar, __ &TabChar, "TABchar (field delimiter)",
X   'r', ARGNOVAL, argMine, __ NULL,     "raw (trigger raw-mode \
before processing any more arguments on the command-line)",
X
X   ' ', ARGLIST, listStr, __ &Argv, "file (list of files)",
X
X   ENDOFARGS
};
X
X
/***************************************************************************
** ^FUNCTION: reset_args - reset argument values for another pass
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static VOID reset_args()
#endif
/*  
** ^PARAMETERS:
**    None.
**
** ^DESCRIPTION:
**    Reset_args resets all the argument values to their corresponding
**    default values so that we can (re)test the parseargs library.
**
** ^REQUIREMENTS:
**    None.
**
** ^SIDE-EFECTS:
**    All the static-global argument variables are rewritten.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   static void reset_args( void )
#endif
{
X   RepCount = 0;
X   Name     = CHARNULL;
X   Str      = DEF_STR;
X   DirName  = ".";
X   XRated   = FALSE;
X   XFlag    = FALSE;
X   YFlag    = TRUE;
X   ZFlag    = FALSE;
X   TabChar  = ':';
X
X   vecFree(Integers, int);
X   vecDeepFree(Groups, char *);
X   listFree( Argv );
X   Argv = ARGLISTNULL;
}
X
X
/***************************************************************************
** ^FUNCTION: print_args - print current argument values
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static void print_args( argd )
/*
** ^PARAMETERS:
*/
X   ARGDESC *argd;
/*    -- the command whose arg-values are to be printed
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Print the current values of all the command-line settings
**
** ^REQUIREMENTS:
**    The command-line should have already been parsed by one of the
**    Xparseargs functions.
**
** ^SIDE-EFECTS:
**    Prints on stdout.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   static void print_args( const ARGDESC *argd )
#endif
{
X   int  i, flags;
X   ArgList *ls;
X
X   printf( "Name = \"%s\", DirName = \"%s\", RepCount = %d,\n",
X           Name, DirName, RepCount );
X
X   printf( "XFlag = %d, YFlag = %d, ZFlag = %d, TabChar='%c'(%03o);\n",
X           XFlag, YFlag, ZFlag, TabChar, TabChar );
X
X   printf( "XRated=%d, Raw-Mode = \"%s\"\n", XRated, Mode );
X
X      /* to call parsecntl() to see if the optional value was supplied */
X   (VOID) parsecntl( (ARGDESC *)argd, pc_ARGFLAGS, pc_READ, "string", &flags);
X
X   if ( BTEST(flags, ARGGIVEN) && !BTEST(flags, ARGVALGIVEN) ) {
X      printf("String=!No Value Given on CmdLine!\n" );
X   }
X   else {
X      printf("String=\"%s\"\n", Str);
X   }
X
X   if (Groups.count) {
X      printf("Newsgroups:");
X      for (i = 0 ; i < Groups.count ; i++ ) {
X         printf(" %s", Groups.array[i]);
X      }
X      putchar('\n');
X   }
X
X   if (Integers.count) {
X      printf("Integers:");
X      for (i = 0 ; i < Integers.count ; i++ ) {
X         printf(" %d", Integers.array[i]);
X      }
X      putchar('\n');
X   }
X
X   if (Argv)  printf("Remaining args: ");
X   for ( ls = Argv ; ls ; L_ADVANCE(ls) ) {
X      printf("%s", L_STRING(ls));
X      if ( L_NEXT(ls) ) {
X         putchar(' ');
X      }
X      else {
X         putchar('\n');
X      }
X   }/*for*/
}
X
X
/*ARGSUSED*/
MAIN(argc, argv)
{
X   parseargs(argv, Cmd);   /* parse the command-line */
X   print_args(Cmd);        /* print what we found */
X
X   putchar('\n');
X   reset_args();           /* reset args for another pass */
X
X   parseargs(argv, Args);  /* parse same command-line using old-style argd */
X   print_args(Args);       /* print what we found (should be same as before) */
X
X   exit(0);  /* wave bye-bye */
}
SHAR_EOF
chmod 0664 parseargs/stest.c ||
echo 'restore of parseargs/stest.c failed'
Wc_c="`wc -c < 'parseargs/stest.c'`"
test 9196 -eq "$Wc_c" ||
	echo 'parseargs/stest.c: original size 9196, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/strfuncs.c ==============
if test -f 'parseargs/strfuncs.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/strfuncs.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/strfuncs.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/strfuncs.c' &&
/**************************************************************************
** ^FILE: strfuncs.c - Miscellaneous string functions for parseargs
**
** ^DESCRIPTION:
**    This file implements a wide variety of functions to manipulate
**    strings in way way or another. Some of the functions may already
**    be included in the standard library of some C compilers.
**
**    The following functions are implemented:
**
**       strucpy() -- copy a string and map to uppercase
**       strlcpy() -- copy a string and map to lowercase
**       strupr() -- convert a string to uppercase
**       strlwr() -- convert a string to lowercase
**       strdup() -- return a (newly allocated) copy of a string
**       strpbrk() -- return first occurrence of character in a set
**       strspn() -- return length of initial prefix of a character set
**       strcspn() -- return length of initial prefix of a character set
**       strltrim() -- trim leftmost (leading) characters in a string
**       strrtrim() -- trim rightmost (trailing) characters in a string
**       strtrim() -- trim leading and trailing characters in a string
**       strsplit() -- split a string up into a vector of tokens
**       strjoin() -- join a vector of token into a single string
**       get_name() -- return the aname (argument-name) of an argument
**       get_keyword() -- return the sname (keyword-name) of an argument
**       match() -- match two keywords (case insensitive) upto a unique prefix
**       stricmp() -- case insensitive comparison of strings
**       strnicmp() -- case insensitive length-limited comparison of strings
**       basename() -- remove the leading directories (and disks) from a path
**       indent_para() -- print an indented hanging paragraph
**
** ^HISTORY:
**    01/02/91 	Brad Appleton 	<brad at ssd.csd.harris.com> 	Created
**    - changed from file misc.c to this name and added all of the strxxx
**      functions (plus got rid of some unused functions).
**
**    --/--/--	Peter da Silva	<peter at ferranti.com>	
**
**    --/--/--	Eric P. Allman	<eric at Berkeley.EDU> 	Created
***^^**********************************************************************/
X
#include <stdio.h>
#include <ctype.h>
#include <useful.h>
X
EXTERN  VOID   syserr  ARGS((const char *, ...));
X
static CONST char WhiteSpace[] = " \t\n\r\v\f";
X
X
#if ( defined(unix_style)  ||  defined(ibm_style) )
# define  TO_KWDCASE(c)  TOLOWER(c)
#else
# define  TO_KWDCASE(c)  TOUPPER(c)
#endif
X
X
/***************************************************************************
** ^FUNCTION: strucpy, strlcpy - copy dest to src, mapping to upper/lower case
**
** ^SYNOPSIS:
**
**    char *strucpy( dest, src )
**    char *strlcpy( dest, src )
**
** ^PARAMETERS:
**    char *dest;
**    -- the address to start copying to
**
**    char *src;
**    -- the address to start copying from
**
** ^DESCRIPTION:
**    Strlcpy (strucpy) copies src into dest (upto and including the
**    terminating NUL byte) and all uppercase (lowercase) characters in
**    src are mapped to lowercase (uppercase) before being copied into dest.
**
** ^REQUIREMENTS:
**    Dest must be non-null, and large enough to hold the copied result.
**
** ^SIDE-EFECTS:
**    Dest is (re)written
**
** ^RETURN-VALUE:
**    Address of dest.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *strucpy( char *dest, const char *src )
#else
X   char *strucpy( dest, src )  char *dest, *src;
#endif
{
X   register char  *s1 = dest;
X   register CONST char  *s2 = src;
X
X   if ( !s2 )  return  CHARNULL;
X
X   for ( ; *s2 ; s1++, s2++ ) {
X      *s1 = TOUPPER( *s2 );
X   }
X   *s1 = '\0';
X
X   return   s1;
}
X
X
#ifdef __ANSI_C__
X   char *strlcpy( char *dest, const char *src )
#else
X   char *strlcpy( dest, src )  char *dest, *src;
#endif
{
X   register char  *s1 = dest;
X   register CONST char  *s2 = src;
X
X   if ( !s2 )  return  CHARNULL;
X
X   for ( ; *s2 ; s1++, s2++ ) {
X      *s1 = TOLOWER( *s2 );
X   }
X   *s1 = '\0';
X
X   return   s1;
}
X
X
/***************************************************************************
** ^FUNCTION: strupr, strlwr - convert a string to all upper/lower case
**
** ^SYNOPSIS:
**    char *strupr( str )
**    char *strlwr( str )
**
** ^PARAMETERS:
**    char *str;
**    -- the string to be converted
**
** ^DESCRIPTION:
**    Strupr (strlwr) converts all lowercase (uppercase) characters in <str>
**    to uppercase (lowercase) and returns the address of <str>.
**
** ^REQUIREMENTS:
**    str should be non-null and non-empty.
**
** ^SIDE-EFECTS:
**    str is overwritten with the uppercase (lowercase) result.
**
** ^RETURN-VALUE:
**    Address of str.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *strupr( char *str )
#else
X   char *strupr( str )  char *str;
#endif
{
X   char *p = str;
X
X   for ( ; p && *p ; p++ ) {
X      if ( islower(*p) )  *p = toupper(*p);
X   }
X
X   return   str;
}
X
X
#ifdef __ANSI_C__
X   char *strlwr( char *str )
#else
X   char *strlwr( str )  char *str;
#endif
{
X   char *p = str;
X
X   for ( ; p && *p ; p++ ) {
X      if ( isupper(*p) )  *p = tolower(*p);
X   }
X
X   return   str;
}
X
X
/***************************************************************************
** ^FUNCTION: stricmp, strnicmp - case insensitive string comparison
**
** ^SYNOPSIS:
**    int stricmp( s1, s2 )
**    int strnicmp( s1, s2, n )
**
** ^PARAMETERS:
**    char *s1;
**    -- first string to compare
**
**    char *s2;
**    -- second string to compare
**
**    size_t  n;
**    -- The number of characters to compare
**
** ^DESCRIPTION:
**    Stricmp (strnicmp) is identical to strcmp (strncmp) except that it
**    it performs a case-insensitive comparison of characters.
**
** ^REQUIREMENTS:
**    Both s1 and s2 should be non-null and non-empty
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
**    < 0    if s1 < s2
**    = 0    if s1 matches s2
**    > 0    if s1 > s2
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int stricmp( const char *str1, const char *str2 )
#else
X   int stricmp( str1, str2 ) char *str1, *str2;
#endif
{
X   register  CONST char *s1 = str1, *s2 = str2;
X   register  char  c1, c2;
X
X   if ( s1 == s2 )  return   0;
X   if ( !s1 )       return  -1;
X   if ( !s2 )       return   1;
X
X   for ( ; *s1 && *s2 ; s1++ , s2++ ) {
X      c1 = TOLOWER( *s1 );
X      c2 = TOLOWER( *s2 );
X
X      if (c1 != c2)  return  (int)(c1 -c2);
X   }
X   return   (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
}
X
X
#ifdef __ANSI_C__
X   int strnicmp( const char *str1, const char *str2, size_t len )
#else
X   int strnicmp( str1, str2, len ) char *str1, *str2; size_t  len;
#endif
{
X   register  CONST char *s1 = str1, *s2 = str2;
X   register  char  c1, c2;
X
X   if ( s1 == s2 )  return   0;
X   if ( !s1 )       return  -1;
X   if ( !s2 )       return   1;
X
X   for ( ; *s1 && *s2 && len ; s1++ , s2++ , len-- ) {
X      c1 = TOLOWER( *s1 );
X      c2 = TOLOWER( *s2 );
X
X      if (c1 != c2)  return  (int)(c1 -c2);
X   }
X   return   (*s1 == *s2) ? 0 : (int)(*s1 - *s2);
}
X
X
#ifdef BSD
X
/***************************************************************************
** ^FUNCTION: strdup - copy a string
**
** ^SYNOPSIS:
*/
# ifndef __ANSI_C__
X   char *strdup( str )
/*
** ^PARAMETERS:
*/
X   char *str;
/*    -- the string to replicate
*/
# endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Strdup allocates storrage and copies the given string into the
**    newly acquired space (returning its address). The returned result
**    should be deallocated using free().
**
** ^REQUIREMENTS:
**    str should be non-null
**
** ^SIDE-EFFECTS:
**    None.
**
** ^RETURN-VALUE:
**    Address of the newly allocated string.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
# ifdef __ANSI_C__
X   char *strdup( const char *str )
# endif
{
X  unsigned len = strlen(str) + 1;
X  char *p = malloc( len * sizeof(char) );
X
X  if ( !p )  syserr( "Fatal Error -- out of memory" );
X  strcpy(p, str);
X
X  return p;
}
X
X
/***************************************************************************
** ^FUNCTION: strpbrk - return the first occurrence of characters in a string
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   char *strpbrk( str1, str2 )
/*
** ^PARAMETERS:
*/
X   char *str1;
/*    -- the string to be searched
*/
X   char *str2;
/*    -- the set of characters to be located
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Strpbrk will attempt to locate the first occurence in str1 of any 
**    character from str2 and return the address of the first such
**    occurrence. If str1 contains NO characters from str2, then NULL
**    is returned.
**
** ^REQUIREMENTS:
**    Both str1 and str2 should be non-null and non-empty
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
**    A pointer to the first occurence in str1 of any char from str2.
**
** ^ALGORITHM:
**    - foreach char in str1
**       - if char is in str2, return the address of char
**      end-for
**    - if we have reached the end of str1, return NULL
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *strpbrk( const char *str1, const char *str2 )
#endif
{
X   register CONST char *s1 =  str1, *s2 = str2;
X
X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  CHARNULL;
X
X   for ( ; *s1 ; s1++ )  {
X      if ( strchr(s2, *s1) )  return (char *)s1;
X   }
X
X   return  CHARNULL;
}
X
X
/***************************************************************************
** ^FUNCTION: strspn, strcspn - identify leading runs of characters
**
** ^SYNOPSIS:
**    char *strspn( str1, str2 )
**    char *strcspn( str1, str2 )
**
** ^PARAMETERS:
**    char *str1;
**    -- the string to be searched
**
**    char *str2;
**    -- the string to be searched
**
** ^DESCRIPTION:
**    Strspn (strcspn) attempts to determine the length of the longest
**    leading prefix of str1 that consists entirely of character from
**    (not from) str2.
**
** ^REQUIREMENTS:
**    Both str1 and str2 should be non-null and non-empty.
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
**    The length of the initial prefix in str1 consisting entirely
**    of characters from (not from) str2.
**
** ^ALGORITHM:
**    - length = 0
**    - for each char in str1
**       - if char is in str2 (for strcspn) or not in str2 (for strcspn)
**            then return length
**       - else
**            add 1 to length
**         end-if
**      end-for
**    - if end-of-string then return length
**
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int strspn( const char *str1, const char *str2 )
#else
X   int strspn( str1, str2 )  char *str1, *str2;
#endif
{
X   register CONST char  *s1 = str1, *s2 = str2;
X   int len = 0;
X
X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
X   while ( *s1  &&  strchr(s2, *s1++) )  ++len;
X   return  len;
}
X
X
#ifdef __ANSI_C__
X   int strcspn( const char *str1, const char *str2 )
#else
X   int strcspn( str1, str2 )  char *str1, *str2;
#endif
{
X   register CONST char  *s1 = str1, *s2 = str2;
X   int len = 0;
X
X   if ( !s1 || !*s1 || !s2 || !*s2 )  return  0;
X   while ( *s1  &&  !strchr(s2, *s1++) )  ++len;
X   return  len;
}
X
#endif  /* BSD */
X
X
/***************************************************************************
** ^FUNCTION: strltrim, strrtrim, strtrim - trim leading/trailing characters
**
** ^SYNOPSIS:
**    char *strltrim( str, charset )
**    char *strrtrim( str, charset )
**    char *strtrim( str, charset )
**
** ^PARAMETERS:
**    char *str;
**    -- the string to be trimmed
**
**    char *charset;
**    -- the set of characters to be trimmed
**
** ^DESCRIPTION:
**    Strltrim removes from str, all leftmost (leading) characters occurring
**    in charset.
**
**    Strrtrim removes from str, all rightmost (trailing) characters occurring
**    in charset.
**
**    Strtrim removes from str, all leading and trailing characters occurring
**    in charset.
**
**    For each of these functions, if charset is NULL or empty, then the set
**    of whitespace characters (space, tab, newline, carriage-return, form-feed
**    and vertical-tab) is assumed.
**
** ^REQUIREMENTS:
**    str should be non-null and non-empty.
**
** ^SIDE-EFECTS:
**    characters may be removed from the beginning and/or end of str.
**
** ^RETURN-VALUE:
**    Address of str.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *strltrim( char *str, const char *charset )
#else
X   char *strltrim( str, charset )  char *str, *charset;
#endif
{
X   register   int   i;
X
X   if ( !str  ||  !*str )   return   str;
X      /* if delim-string is NULL, whitespace is used */
X   if ( !charset )   charset = WhiteSpace;
X
X   i = strspn( str, charset );
X   if ( i > 0 )  strcpy( str, &(str[i]) );
X
X   return   str;
}
X
X
#ifdef __ANSI_C__
X   char *strrtrim( char *str, const char *charset )
#else
X   char *strrtrim( str, charset )  char *str, *charset;
#endif
{
X   register   int   i;
X
X   if ( !str  ||  !*str )   return   str;
X   if ( !charset )   charset = WhiteSpace;
X   for ( i = strlen(str) - 1 ;
X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
X            i--
X         ) ;
X
X   str[i+1] = '\0';
X
X   return   str;
}
X
X
#ifdef __ANSI_C__
X   char *strtrim( char *str, const char *charset )
#else
X   char *strtrim( str, charset )  char *str, *charset;
#endif
{
X   register   int   i;
X
X   if ( !str  ||  !*str )   return   str;
X   if ( !charset )   charset = WhiteSpace;
X   i = strspn( str, charset );
X   if ( i > 0 )  strcpy( str, &(str[i]) );
X
X   for ( i = strlen(str) - 1 ;
X            ( i >= 0 ) && (strchr( charset, str[i] )) ;
X            i--
X         ) ;
X
X   str[i+1] = '\0';
X
X   return   str;
}
X
X
/***************************************************************************
** ^FUNCTION: strsplit - split a string into tokens
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   int  strsplit( vec, token_str, separators )
/*
** ^PARAMETERS:
*/
X   char **vec[];
/*    -- pointer to the string vector to be allocated
*/
X   char token_str[];
/*    -- the string to be split up
*/
X   char separators[];
/*    -- the delimiters that separate tokens
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Strsplit will split token_str up into  a vector of tokens that are
**    separated by one or more characters from <separators>. The number
**    of tokens found is returned and storage is allocated for the given
**    vector (which may later be deallocated using free()).
**
**    If <separators> is NULL or empty, then the set of whitespace characters
**    is used as the token delimiters.
**
** ^REQUIREMENTS:
**    vec must be non-NULL (it must be a valid address).
**    token_str should be non-null and non-empty
**
** ^SIDE-EFECTS:
**    All leading and trailing characters from <separators> are removed
**    from token_str. Furthermore, all remaining sequences in token_str
**    of characters from <separators> are replaced with a single NUL-byte.
**
**    Token_str holds the actual storage for all the strings in the newly
**    created vector.
**
** ^RETURN-VALUE:
**    The number of tokens parsed.
**
** ^ALGORITHM:
**    - count the number of tokens present while at the same time removing
**      all leading and trailing delimiters, and replacing all other sequences
**      of delimiters with the NUL character.
**    - allocate a vector large enough to point to all the token strings.
**    - for i in 0 .. (numtokens - 1) do
**         - vector[i] = token_str
**         - advance token_str to point at the next character past the
**           righmost NUL-byte (which should be the start of the next token).
**      end-for
**    - return the number of tokens parsed.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   int strsplit( char **vec[], char token_str[], const char separators[] )
#endif
{
X   register   char c, *pread, *pwrite;
X   int   i, count = 0;
X
X   if ( !token_str )    return   0;
X      /* if delim-string is NULL, whitespace is used */
X   if ( !separators )   separators = WhiteSpace;
X
X      /* trim leading separators */
X   pread = token_str;
X   while ( strchr(separators, *pread) )   ++pread;
X   token_str = pwrite = pread;
X
X      /*
X      ** make first pass through string, counting # of tokens and
X      ** separating all tokens by a single '\0'
X      */
X   while ( c = *pread++ ) {
X      if ( !strchr(separators, c) )   {
X         *pwrite++ = c;
X      }
X      else {
X         *pwrite++ = '\0';   /* null terminate this token */
X         ++count;                /* update token count */
X         while ( strchr(separators, *pread) )   ++pread;
X      }
X   }/*while*/
X   if ( *(pwrite - 1) )  {
X      ++count;         /* dont forget last token */
X      *pwrite = '\0';   /* null-terminate */
X   }
X
X      /* allocate space for the caller's vector (remember NULL at the end) */
X   (*vec) = (char **)malloc( (1 + count) * sizeof( char * ) );
X   if ( !*vec ) {
X      fprintf( stderr, "out of memory in strsplit() - aborting\n" );
X      exit( -1 );
X   }
X
X      /* now go thru token-string again assigning pointers from vector */
X   pread = token_str;
X   for ( i = 0 ; i < count ; i++ ) {
X      (*vec)[i] = pread;   /* assign pointer */
X      pread += strlen( pread ) + 1;
X   }/* end-for */
X
X      /* set up the trailing pointer to NULL at the end */
X   (*vec)[ count ] = CHARNULL;
X   return   count;
}
X
X
/***************************************************************************
** ^FUNCTION: strjoin - join a vector of tokens together
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   char  *strjoin( argv, separator )
/*
** ^PARAMETERS:
*/
X   char *argv[];
/*    -- pointer to the string vector to join together
*/
X   char separator[];
/*    -- the the string to use to separate tokens (if NULL, " " is used)
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Strjoin will make a single string out of the given vector by copying
**    all the tokens from the given vector (in order) toa newly allocated
**    string. Each token will be separated by an occurence of <separator>.
**
**    If <separator> is NULL then a single space is used as the separator.
**    If <separator> is empty, then no separator is used and the tokens are
**    simply concatenated together.
**
** ^REQUIREMENTS:
**    argv must be non-NULL (it must be a valid address), and must be terminated
**    by a pointer to NULL (argv[last+1] == NULL).
**
** ^SIDE-EFECTS:
**    Storage is allocated.
**
** ^RETURN-VALUE:
**    The addres of the newly-joined results (which should be deallocated
**    using free()). Returns NULL if nothing was joined.
**
** ^ALGORITHM:
**    - count the number of characters to place in the joined-result.
**    - allocate a string large-enough to copy the joined-result into.
**    - copy each string into the string (with <separator> between tokens).
**    - 0 return the result.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *strjoin( const char *argv[], const char separator[] )
#endif
{
X   size_t  sz = 0;
X   register char *p;
X   register CONST char *a, **av;
X   register int  seplen;
X   char *result;
X
X      /* if argv is NULL, nothing to do */
X   if ( !argv )  return  CHARNULL;
X   if ( !separator )  separator = " ";
X   seplen = strlen( separator );
X
X      /* figure out how much space we need */
X   for ( av = argv ; *av ; av++ ) {
X      if ( !**av )  continue;
X      sz += strlen( *av );
X      if ( seplen  &&  *(av + 1) )  sz += seplen;
X   }
X
X      /* allocate space */
X   result = (char *)malloc( (sz + 1) * sizeof(char) );
X   if ( !result )  syserr( "malloc failed in strjoin()" );
X
X      /* join the strings together */
X   *result = '\0';
X   for ( av = argv, p = result ; (a = *av) ; av++ ) {
X      if ( !*a )  continue;
X      while ( (*p = *a++) ) ++p;  /* copy token */
X      if ( seplen  &&  *(av + 1) ) {
X         a = separator;
X         while ( (*p = *a++) ) ++p;  /* copy separator */
X      }/*end-if*/
X   }/*end-for*/
X
X   return  result;
}
X
X
/***************************************************************************
** ^FUNCTION: get_name - return the aname (argument-name) of an argument
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   char  *get_name( s, buf )
/*
** ^PARAMETERS:
*/
X   char *s;
/*    -- the ad_prompt field of an ARGDESC struct
*/
X   char *buf;
/*    -- address to which the aname should be copied
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Get_name will get the full argument name of the given argument
**    (not just the keyword name) and copy it to buf.
**
** ^REQUIREMENTS:
**    Both s and buf must be non-null and non-empty.
**    buf must be large enough to hold the result.
**
** ^SIDE-EFECTS:
**    buf is overwritten.
**
** ^RETURN-VALUE:
**    Address of the buffer containing the name.
**
** ^ALGORITHM:
**    determine the name of an argument from its prompt
**    and copy the result in the given buffer
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *get_name( const char *s, char *buf )
#endif
{
X      /* <buf> must be large enough to hold the result! */
X   strlcpy(buf, s);
X   return   buf;
}
X
X
/***************************************************************************
** ^FUNCTION: get_keyword - get the sname (keyword name) of an argument
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   char  *get_keyword( s, buf )
/*
** ^PARAMETERS:
*/
X   char *s;
/*    -- the ad_prompt field of an ARGDESC struct
*/
X   char *buf;
/*    -- address to which the sname should be copied
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Get_name will get the keyword name of the given argument
**    (not the entire argument name) and copy it to buf.
**
**    The sname (keyword-name) consists only of all uppercase characters
**    from the ad_prompt field (in the order they occur). If the ad_prompt
**    field contains NO uppercase characters, than the aname and the sname
**    are equivalent (the entire string).
**
** ^REQUIREMENTS:
**    Both s and buf must be non-null and non-empty.
**    buf must be large enough to hold the result.
**
** ^SIDE-EFECTS:
**    buf is overwritten.
*
** ^RETURN-VALUE:
**    Address of the buffer containing the keyword.
**
** ^ALGORITHM:
**    determine the keyword of an argument from its prompt
**    and copy the result in the given buffer
***^^**********************************************************************/
#ifdef __ANSI_C__
X   char *get_keyword( const char *s, char *buf )
#endif
{
X   register char *p1 = (char *)s, *p2;
X   register int   i, len = 0;
X   char *caps = CHARNULL;
X
X   if ( !p1 )  return  CHARNULL;
X
X      /* find size to copy (use all caps if possible) */
X   for ( p1 = (char *)s ; *p1 ; p1++ )   {
X     if ( !caps  &&  isupper( *p1 ) )  caps = p1;
X         if ( caps   &&   isupper( *p1 ) )   ++len;
X   }
X   if ( !caps )   len = (int) (p1 - (char *)s);
X
X      /* copy string into buffer and convert it to desired case */
X      /* <buf> must be large enough to hold the result! */
X   p1 = buf;
X   if ( len )   {
X     if ( !caps ) {
X        for ( p1 = buf, p2 = (char *)s, i = 0 ; i < len ; p1++, p2++, i++ ) {
X            *p1 = TO_KWDCASE(*p2);
X        }
X     }/*if*/
X
X     else {
X        for ( p2 = caps, i = 0 ; i < len ; p2++ ) {
X           if ( isupper( *p2 ) )   {
X              *(p1++) = TO_KWDCASE(*p2);
X              ++i;
X           }
X        }/*for*/
X     }/*else*/
X   }/*if*/
X   *p1 = '\0';
X
X   return   buf;   /* return buffer address */
}
#ifndef amiga_style
X
/***************************************************************************
** ^FUNCTION: match - match a keyword against a prospective argument
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   int match( candidate, target )
/*
** ^PARAMETERS:
*/
X   char *candidate;
/*    -- the possible keyword argument
*/
X   char *target;
/*    -- the keyword to be matched
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Match will attempt to see if the candidate string matches the
**    target string (case insensitive). First a match is tried on the
**    sname of the keyword, then on the aname.  Candidate may be only
**    a partial leading portion of the target as long as it is at least
**    two characters long (unless the keyword is 1 character long).
**
**    No "partial" matching is accepted for AmigaDOS command-lines.
**
** ^REQUIREMENTS:
**    Both candidate and target should be non-null and non-empty.
**    target should be the ad_prompt field of an ARGDESC structure.
**
** ^SIDE-EFECTS:
**    None.
**
** ^RETURN-VALUE:
*     < 0  if candidate < target
**    = 0  if candidate matches target
**    > 0  if candidate > target
**
** ^ALGORITHM:
**    - attempt a partial match against the sname and return 0 if we succeed
**    - attempt a partial match against the aname and return 0 if we succeed
**    - if both the above fail return non-zero (no match).
**    
***^^**********************************************************************/
X
/* rewritten 8/20/90 --BDA */
#define MINLEN  2     /* minimum # of characters to match */
X
#ifdef __ANSI_C__
X   int match ( const char *candidate, const char *target )
#endif
{
X   int  i, clen, tlen, too_short=0;
X   CONST char *full_targ;
X   char *up_targ;
X
X
X   full_targ = target;
X
X      /* make up_targ the uppercase portion of target */
X   up_targ = strdup( full_targ );
X   (VOID) get_keyword( full_targ, up_targ );
X
X      /* match at least MINLEN characters if possible */
X   tlen = strlen( up_targ );
X   clen = strlen( candidate );
X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
X      ++too_short;      /* not long enough -- no match */
X   }
X
#ifdef vms_style
X      /* if first two chars are NO then match at least MINLEN+2 chars */
X   if ( !strnicmp(up_targ, "NO", 2) ) {
X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
X         ++too_short;      /* not long enough -- no match */
X      }
X   }
#endif
X
X      /* first try to match prefix of the uppercase portion */
X   i = (too_short) ? -1 : strnicmp(up_targ, candidate, clen);
X
X   free( up_targ );
X
X      /* did we match? */
X   if ( !i )  return  0;   /* yes! */
X
X   /* no! : compare the whole target
X   **       match at least MINLEN characters if possible
X   */
X   tlen = strlen(full_targ);
X   if ( (tlen >= MINLEN)   &&   (clen < MINLEN) ) {
X      return   -1;      /* not long enough -- no match */
X   }
X
#ifdef vms_style
X   /* if first two chars are NO then match at least MINLEN+2 chars */
X   if ( !strnicmp(full_targ, "no", 2) ) {
X      if ( (tlen >= (MINLEN + 2))   &&   (clen < (MINLEN + 2)) ) {
X         return   -1;      /* not long enough -- no match */
X      }
X   }
#endif
X
X   return   strnicmp(full_targ, candidate, clen);
}
X
X
/* here is the AmigaDOS version of match() */
#else
X
# ifdef __ANSI_C__
X   int match( const char *candidate, const char *target )
# else
X   int match( candidate, target) char *candidate, *target;
# endif
{
X   int i, j;
X   char c;
X
X   i = j = 0;
X
X   while ( isgraph(target[i]) || isgraph(candidate[i]) ) {
X      while ( islower(target[i]) ) i++;
X      if ( !isgraph(target[i]) ) {
X         if ( !isgraph(candidate[j]) )  return 0;
X         return  stricmp(target, candidate);
X      }
X      c = islower( candidate[j] ) ? toupper(candidate[j]) : candidate[j];
X      if (target[i] != c)  return  stricmp(target, candidate);
X      i++;
X      j++;
X   }
X   return 0;
}
X
#endif
X
X
/***************************************************************************
** ^FUNCTION: basename - return the last component of a pathname
**
** ^SYNOPSIS:
**    char *basename( path )
**
** ^PARAMETERS:
**    path;
**    -- the pathname to be truncated.
**
** ^DESCRIPTION:
**    Basename takes a pathname and strips of all leading components
**    (except for the very last one) which refer to directories or
**    disk-drives.
**
** ^REQUIREMENTS:
**    path should be non-null, non-empty, and should correspond to a valid
**    pathname (absolute or relative).
**
** ^SIDE-EFECTS:
**    None under Unix and AmigaDOS.
**
**    Under VMS, the file version is removed and any .COM or .EXE extension
**    is also removed.
**
**    Under MS-DOS, any .EXE, .COM, or .BAT extension is removed.
**
**    Under OS/2, any .EXE, .COM, or .CMD extension is removed.
**    
** ^RETURN-VALUE:
**    The address of the basename of the path.
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
X   /* should use '\\' for MS-DOS & OS/2 and use ']' for VMS */
#ifdef vms
#define PATH_SEP ']'
X
X      /* VAX/VMS version of basename */
# ifdef __ANSI_C__
X   char *basename( char  path[] )
# else
X   char *basename( path ) char  path[];
# endif
X   {
X      char *base = strrchr( path, PATH_SEP );
X      char *vers = strrchr( path, ';' );
X      char *ext  = strrchr( path, '.' );
X
X      if ( !base ) {
X         if ( !(base = strrchr( path, ':' )) ) {
X            base = path;
X         }
X         else {
X            ++base;
X         }
X      }
X      else {
X         ++base;
X      }
X
X      if ( vers )  *vers ='\0';
X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
X          ext = '\0';
X      }
X
X      return  base;
X   }
X
#else
#ifdef AmigaDOS
X      /* amiga version of basename() */
# ifdef __ANSI_C__
X   char *basename( char  path[] )
# else
X   char *basename( path ) char  path[];
# endif
X   {
X      return   path;
X   }
#else
#define PATH_SEP  '/'     /* default path-separator character */
X
X      /* default version of basename() */
# ifdef __ANSI_C__
X   char *basename( char  path[] )
# else
X   char *basename( path ) char  path[];
# endif
X   {
X      char *base = strrchr( path, PATH_SEP );
X
#if ( defined(MSDOS) || defined(OS2) )
X      /* remove the extension from .EXE, .COM, .BAT, and .CMD files */
# ifdef OS2
X      if ( ext  &&  (!stricmp(ext, ".CMD") )  *ext = '\0';
# else
X      if ( ext  &&  (!stricmp(ext, ".BAT") )  *ext = '\0';
# endif
X
X      if ( ext  &&  (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
X          ext = '\0';
X      }
#endif
X
X      if ( !base ) {
#if ( defined(MSDOS) || defined(OS2) )
X         base = strrchr( path, '\\' );
X         if ( base )  return  (base + 1);
X         if ( path[ 1 ] == ':' )  return  (path + 2);  /* just remove drive */
X         return  (base + 1);
#endif
X         return  path;
X      }
X      else {
X         return  (base + 1);
X      }
X   }
#endif
#endif
X
X
/***************************************************************************
** ^FUNCTION: indent_para - print a hanging indented paragraph
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   VOID indent_para(fp, maxcols, margin, title, indent, text)
/*
** ^PARAMETERS:
*/
X   FILE *fp;
/*    -- the stream to which output is sent
*/
X   int maxcols;
/*    -- the maximum width (in characters) of the output
*/
X   int margin;
/*    -- the number of spaces to use as the left margin
*/
X   char *title;
/*    -- the paragraph title
*/
X   int indent;
/*    -- the distance between the title and the paragraph body
*/
X   char *text;
/*    -- the body of the paragraph
*/
#endif  /* !__ANSI_C__ */
X
/* ^DESCRIPTION:
**    Indent_para will print on fp, a titled, indented paragraph as follows:
**
**    <----------------------- maxcols --------------------------->
**    <--- margin -->     <-- indent -->
**                   title              This is the first sentence
**                                      of the paragraph. Etc ...
**
** ^REQUIREMENTS:
**    maxcols and indent must be positive numbers with maxcols > indent
**
** ^SIDE-EFECTS:
**    Output is printed to fp.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    Print the paragraph title and then print the text.
**    Lines are automatically adjusted so that each one starts in the
**    appropriate column.
***^^**********************************************************************/
#ifdef __ANSI_C__
X   void indent_para( FILE *fp, int maxcols, int margin,
X                     const char *title, int indent, const char *text )
#endif
{
X   register int idx = 0;
X   BOOL first_line = TRUE;
X   int  text_len = strlen(text);
X   char ch;
X
X   /* print the title */
X      fprintf( fp, "%*s%-*s", margin, "", indent, title );
X
X   idx = maxcols - margin - indent;
X
X   if ( text_len <= idx )
X      fprintf(fp, "%s\n", text);
X   else
X      do {
X               /* backup to end of previous word */
X         while (idx  &&  !isspace(text[idx]))  --idx;
X         while (idx  &&  isspace(text[idx]))   --idx;
X
X            /* print leading whitespace */
X         if (!first_line)
X            fprintf(fp, "%*s%-*s", margin, "", indent, "");
X
X         ch = text[ ++idx ];
X         *((char *)text + idx) = '\0';
X         fprintf(fp, "%s\n", text);
X         *((char *)text + idx) = ch;
X         first_line = FALSE;
X         text = &(text[idx+1]);
X         text_len -= (idx+1);
X
X         while (isspace(*text)) {  /* goto next word */
X            ++text;
X            --text_len;
X         }
X
X         idx = maxcols - margin - indent;
X
X         if ( text_len <= idx )  /* print-last line */
X            fprintf(fp, "%*s%-*s%s\n", margin, "", indent, "", text);
X      } while ( text_len > idx );
}
X
X
#ifdef STRTEST
X
#define WS " \t\n\v\r\f\"'"
X
static char string2[] =  "	  oh what  	a beautiful -	morning!    	";
X
static char string[] =  "\n\
\t' ',  ARGREQ,          argStr,   Name,     'Name',\n\
\t'n',  ARGOPT|ARGLIST,  listStr,  Groups,   'newsGROUP (newsgroups test)',\n\
\t'c',  ARGOPT,          argInt,   RepCount, 'REPcount (number of reps)',\n\
\t'd',  ARGOPT,          argStr,   DirName,  'DIRname',\n\
\t'x',  ARGOPT,          argBool,  XFlag,    'Xflag (expand in X direction)',\n\
\t' ',  ARGOPT|ARGLIST,  listStr,  Argv,     'File',\n\
\tENDOFARGS\n\
";
X
static char word_str[] = "HELP (print help and quit)";
X
main()
#ifdef __ANSI_C__
#endif
{
X   char **vector;
X   unsigned i, numtoks;
X
X   printf( "test of strtrim() and strsplit():\n\n" );
X
X   printf( "unparsed string='%s'\n", string2 );
X   printf( "ltrimmed string='%s'\n", strltrim( string2, WS ) );
X   printf( "rtrimmed string='%s'\n", strrtrim( string2, WS ) );
X
X   numtoks = strsplit( &vector, string, "," );
X   printf( "number of tokens=%d\n", numtoks );
X   for ( i = 0 ; i < numtoks ; i++ ) {
X      printf( "trimmed token[%d] = '%s'\n", i, strtrim( vector[i], WS ) );
X   }
X
X   exit( 0 );
}
X
#endif
SHAR_EOF
chmod 0664 parseargs/strfuncs.c ||
echo 'restore of parseargs/strfuncs.c failed'
Wc_c="`wc -c < 'parseargs/strfuncs.c'`"
test 34399 -eq "$Wc_c" ||
	echo 'parseargs/strfuncs.c: original size 34399, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/strfuncs.h ==============
if test -f 'parseargs/strfuncs.h' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/strfuncs.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/strfuncs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/strfuncs.h' &&
/***************************************************************************
** ^FILE: strfuncs.h - string functions
**
** ^DESCRIPTION:
**    External declarations for the functions implemented in strfuncs.c
**
** ^HISTORY:
**    01/07/91	Brad Appleton	<brad at ssd.csd.harris.com>	Created
***^^**********************************************************************/
X
#ifndef STRFUNCS_H
#define STRFUNCS_H
X
#include <useful.h>
X
EXTERN  char  *strucpy      ARGS(( char *, const char * ));
EXTERN  char  *strlcpy      ARGS(( char *, const char * ));
EXTERN  char  *strupr       ARGS(( char * ));
EXTERN  char  *strlwr       ARGS(( char * ));
EXTERN  int    stricmp      ARGS(( const char *, const char * ));
EXTERN  int    strnicmp     ARGS(( const char *, const char *, size_t ));
X
#ifdef BSD
X   EXTERN  char  *strdup    ARGS(( const char * ));
X   EXTERN  char  *strpbrk   ARGS(( const char *, const char * ));
X   EXTERN  int    strspn    ARGS(( const char *, const char * ));
X   EXTERN  int    strcspn   ARGS(( const char *, const char * ));
#endif
X
EXTERN  char  *strltrim     ARGS(( char *, const char * ));
EXTERN  char  *strrtrim     ARGS(( char *, const char * ));
EXTERN  char  *strtrim      ARGS(( char *, const char * ));
EXTERN  int    strsplit     ARGS(( char ***, char *, const char * ));
EXTERN  char  *strjoin      ARGS(( const char **, const char * ));
EXTERN  char  *get_name     ARGS(( const char *, char * ));
EXTERN  char  *get_keyword  ARGS(( const char *, char * ));
EXTERN  int    match        ARGS(( const char *, const char * ));
EXTERN  char  *basename     ARGS(( char * ));
EXTERN  VOID   indent_para  ARGS(( FILE *, int, int,
X                                   const char *, int, const char * ));
X
#endif
SHAR_EOF
chmod 0664 parseargs/strfuncs.h ||
echo 'restore of parseargs/strfuncs.h failed'
Wc_c="`wc -c < 'parseargs/strfuncs.h'`"
test 1729 -eq "$Wc_c" ||
	echo 'parseargs/strfuncs.h: original size 1729, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= parseargs/syserr.c ==============
if test -f 'parseargs/syserr.c' -a X"$1" != X"-c"; then
	echo 'x - skipping parseargs/syserr.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting parseargs/syserr.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'parseargs/syserr.c' &&
/*************************************************************************
** ^FILE: syserr.c - error-message printing routines
**
** ^DESCRIPTION:
**    This fill implements various routines for printing diagnostic
**    messages on standard diagnostic output (stderr). The routines are:
**
**       usrerr()  --  print message and any system message(s) and return
**       syserr()  --  print message and any system message(s) and exit
**       eprintf() --  print to stderr and return
**
** ^HISTORY:
**    01/02/91	Brad Appleton	<brad at ssd.csd.harris.com>
**       - Changed to use varargs/stdargs
**       - Added structured comment blocks
**       - Added eprintf()
**
**    --/--/--	Peter da Silva	<peter at ferranti.com>
**
**    --/--/--	Eric P. Allman	<eric at Berkeley.EDU> 	Created
***^^**********************************************************************/
X
#include <stdio.h>
#include <useful.h>
/* #include <funclist.h> */
X
VERSIONID("$Header: syserr.c,v 2.0 89/12/24 00:56:31 eric Exp $");
X
extern  char *ProgName;
extern  int   errno;
EXTERN  int   vfprintf  ARGS((FILE *, const char *, va_list));
X
X
/***************************************************************************
** ^FUNCTION: _error_message - generic message printing routine.
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
X   static VOID _error_message( format, ap )
/*
** ^PARAMETERS:
*/
X   char *format;
SHAR_EOF
true || echo 'restore of parseargs/syserr.c failed'
fi
echo 'End of  part 9'
echo 'File parseargs/syserr.c is continued in part 10'
echo 10 > _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