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