More changes for parseargs

Peter da Silva peter at ficc.uu.net
Tue Feb 6 09:02:52 AEST 1990


This second set of patches is close enough to the first that it's also
based on the original parseargs distribution. If you have changed things
from my changes and can't back them out, let me know and I'll attempt to
build an incremental patch.

I'm considering adding options of the form "+LongName=value" (or simply
"+LongName" for booleans). Anyone interested in a more verbose parsing
scheme like this? Or should I just go straight to the Amiga version?

Since comp.sources.unix seems to be dead, I have been thinking of posting
my enhanced parseargs to comp.sources.misc, with full credit to Eric Allman
as the original author of course.

:
#! /bin/sh
# This is a shell archive, created at Ferranti International Controls Corp.
# by peter at ficc.uu.net (Peter da Silva) on Mon Feb  5 15:55:51 1990
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file".  If you do not have sh, you need 
# unshar, a dearchiving program which is widely available.  In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'README.PDS'
# 'patches.2'
# 'strtol.c'
# To extract them, run the following through /bin/sh
echo x - README.PDS
sed 's/^X//' > README.PDS << '//END_OF_FILE'
XUpdate to parseargs by Peter da Silva (peter at ficc.uu.net).
X(second update: more improvements to error messages, argChar type)
X
XParseargs is a really nifty set of routines, but it doesn't fit too
Xwell with standard UNIX semantics. In particular, you can get into a
Xlot of trouble using it in a script. To make it work better, I've made
Xa couple of changes.
X
XIt compiled straight out of the box on System III once I'd provided
Xbcopy, bcmp, and strtol. The strtol I've provided is almost totally
Xuntested, but hopefully you won't need to use it. It's only for folks with
Xold UNIX systems.
X
XFirst change was to disable the interactive prompting for arguments.
XI think that's inconsistent with usual UNIX semantics. You can undo
Xthis change by #defining INTERACTIVE when compiling parseargs.c.
X
XThe second change was to allow for a trailing list of arguments. There's
Xan extra argument, name, that's used by the usage routine and also flags
Xthat trailing arguments are acceptable. parseargs now returns a new argc
Xand edits argv to match.
X
XThe final change is the addition of a 'argChar' type. This parses character
Xarguments (such as the '-T' option to 'awk'), accepting single characters,
X'\nnn' octal escapes, and '^X' for control characters.
X
XAlso, the error messages have been made a bit more descriptive. Instead
Xof saying "stest: value required for -c flag", it prints "stest: RepCount
Xrequired for -c flag". The ad_prompt element should relly be a descriptive
Xword that can be used in a sentence... or for non_UNIX systems a multi-
Xcharacter or keyword based flag. I plan on doing an Amiga version, for
Xexample, that uses keyword syntax. In that version, the usage message would
Xread:
X
XUsage: stest [Name] <Name> [RepCount <RepCount>] [DirName <DirName>] \
X	[XFlag] [YFlag] [ZFlag] [<File>]...
X
XInstead of:
X
XUsage: stest <Name> [-c <RepCount>] [-d <DirName>] [-x] [-y] [-z] \
X	 [<File>]...
X
XThis would solve the old problem of UNIX programs sticking out like a
Xsore thumb in other operating systems.
//END_OF_FILE
echo x - patches.2
sed 's/^X//' > patches.2 << '//END_OF_FILE'
XMakefile orig/Makefile differ: char 70, line 3
X*** orig/Makefile
X--- Makefile
X***************
X*** 1,6 ****
X  # $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $
X  
X! TARGET=		/usr/local
X  INCLUDES=	-I.
X  O=		-O
X  
X--- 1,6 ----
X  # $Header: Makefile,v 2.1 89/12/30 20:59:01 eric Exp $
X  
X! TARGET=		/usr1/local
X  INCLUDES=	-I.
X  O=		-O
X  
X***************
X*** 12,18 ****
X  		openpath.o \
X  		parseargs.o \
X  		syserr.o \
X! 		traceset.o
X  HFILES=		funclist.h \
X  		parseargs.h \
X  		useful.h
X--- 12,19 ----
X  		openpath.o \
X  		parseargs.o \
X  		syserr.o \
X! 		traceset.o \
X! 		strtol.o
X  HFILES=		funclist.h \
X  		parseargs.h \
X  		useful.h
X***************
X*** 35,41 ****
X  
X  OBJS=		${OFILES}
X  SRCFILES=	${XXFILES} ${HFILES} ${CFILES} ${MANFILES}
X! LIBNAME=	libgoodies.a
X  LOCLIBS=	${LIBNAME}
X  SYSLIBS=	-lm
X  LIBS=		${LOCLIBS} ${SYSLIBS}
X--- 36,42 ----
X  
X  OBJS=		${OFILES}
X  SRCFILES=	${XXFILES} ${HFILES} ${CFILES} ${MANFILES}
X! LIBNAME=	libparseargs.a
X  LOCLIBS=	${LIBNAME}
X  SYSLIBS=	-lm
X  LIBS=		${LOCLIBS} ${SYSLIBS}
Xparseargs.c orig/parseargs.c differ: char 317, line 13
X*** orig/parseargs.c
X--- parseargs.c
X***************
X*** 10,19 ****
X  **	Parameters:
X  **		argv -- the argument vector as passed to main().
X  **		argd -- the argument descriptor array.
X  **
X  **	Returns:
X! **		none.  Terminates the process if parameters cannot be
X! **			properly matched up.
X  **
X  **	Side Effects:
X  **		Converts and stores arguments into variables as
X--- 10,21 ----
X  **	Parameters:
X  **		argv -- the argument vector as passed to main().
X  **		argd -- the argument descriptor array.
X+ **		name -- name of extra arguments for usage message,
X+ **			or NULL if none allowed.
X  **
X  **	Returns:
X! **		Modifies argv to eat arguments, returns new argc.
X! **			Exits with return code 2 if error in args.
X  **
X  **	Side Effects:
X  **		Converts and stores arguments into variables as
X***************
X*** 42,48 ****
X  STATIC ARGDESC	_DefaultArgs[] =
X  {
X       /* name	flags	type		valp		prompt		*/
X! 	'T',	ARGOPT,	argTrace,	ARBNULL,	"trace flags",
X  	ENDOFARGS
X  };
X  
X--- 44,50 ----
X  STATIC ARGDESC	_DefaultArgs[] =
X  {
X       /* name	flags	type		valp		prompt		*/
X! 	'T',	ARGOPT,	argTrace,	ARBNULL,	"TRACE",
X  	ENDOFARGS
X  };
X  
X***************
X*** 52,76 ****
X  	ENDOFARGS
X  };
X  
X  VOID
X! parseargs(argv, argd)
X  	char **argv;
X  	ARGDESC argd[];
X  {
X  	register ARGDESC *ad;
X! 	register char **av = argv;
X  	register char *p;
X  	BOOL noflags;
X  	BOOL error;
X  	BOOL shouldprompt;
X  	extern char *getenv ARGS((char *));
X  	extern int isatty ARGS((int));
X  
X  	/* save the name of this program (for error messages) */
X  	ProgName = *av;
X  
X  	/* test to see if we are interactive */
X  	shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
X  
X  	/* allow null argument descriptor */
X  	if (argd == (ARGDESC *) NULL)
X--- 54,90 ----
X  	ENDOFARGS
X  };
X  
X+ static char *Extra;
X+ 
X  VOID
X! parseargs(argv, argd, extra)
X  	char **argv;
X  	ARGDESC argd[];
X+ 	char *extra;
X  {
X  	register ARGDESC *ad;
X! 	register char **av;
X  	register char *p;
X+ 	int argc;
X  	BOOL noflags;
X  	BOOL error;
X+ #ifdef INTERACTIVE
X  	BOOL shouldprompt;
X+ #endif
X  	extern char *getenv ARGS((char *));
X+ #ifdef INTERACTIVE
X  	extern int isatty ARGS((int));
X+ #endif
X  
X+ 	av = argv++; argc = 1;
X  	/* save the name of this program (for error messages) */
X  	ProgName = *av;
X+ 	Extra = extra;
X  
X+ #ifdef INTERACTIVE
X  	/* test to see if we are interactive */
X  	shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
X+ #endif
X  
X  	/* allow null argument descriptor */
X  	if (argd == (ARGDESC *) NULL)
X***************
X*** 147,154 ****
X  					if (p == CHARNULL || *p == '-')
X  					{
X  						av--;
X! 						usrerr("value required for -%c flag",
X! 							ad->ad_name);
X  						error = TRUE;
X  						break;
X  					}
X--- 161,168 ----
X  					if (p == CHARNULL || *p == '-')
X  					{
X  						av--;
X! 						usrerr("%s required for -%c flag",
X! 							ad->ad_prompt, ad->ad_name);
X  						error = TRUE;
X  						break;
X  					}
X***************
X*** 173,180 ****
X  			}
X  			if (ad->ad_name == '\0')
X  			{
X! 				usrerr("too many positional parameters");
X! 				error = TRUE;
X  				continue;
X  			}
X  
X--- 187,202 ----
X  			}
X  			if (ad->ad_name == '\0')
X  			{
X! 				if(extra==NULL) {
X! 					usrerr("too any arguments");
X! 					error = 1;
X! 					continue;
X! 				}
X! 				/* Compress extra parms back into av */
X! 				if(argv != av)
X! 					*argv = *av;
X! 				argv++;
X! 				argc++;
X  				continue;
X  			}
X  
X***************
X*** 186,191 ****
X--- 208,215 ----
X  		}
X  	}
X  
X+ 	*argv = NULL;
X+ 
X  	/* now rescan for missing required arguments */
X  	for (ALL_AD)
X  	{
X***************
X*** 191,196 ****
X--- 215,221 ----
X  	{
X  		if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
X  		{
X+ #ifdef INTERACTIVE
X  			/* can we prompt? */
X  			while (shouldprompt && !error)
X  			{
X***************
X*** 214,219 ****
X--- 239,246 ----
X  					break;
X  				}
X  			}
X+ #endif
X+ 
X  			if (!BITSET(ARGGIVEN, ad->ad_flags))
X  			{
X  				/* still didn't get a value... sigh */
X***************
X*** 219,231 ****
X  				/* still didn't get a value... sigh */
X  				if (ad->ad_name == ' ')
X  				{
X! 					usrerr("value required for <%s> parameter",
X  						ad->ad_prompt);
X  				}
X  				else
X  				{
X! 					usrerr("value required for -%c flag",
X! 						ad->ad_name);
X  				}
X  				error = TRUE;
X  			}
X--- 246,258 ----
X  				/* still didn't get a value... sigh */
X  				if (ad->ad_name == ' ')
X  				{
X! 					usrerr("%s required",
X  						ad->ad_prompt);
X  				}
X  				else
X  				{
X! 					usrerr("%s required for -%c flag",
X! 						ad->ad_prompt, ad->ad_name);
X  				}
X  				error = TRUE;
X  			}
X***************
X*** 235,242 ****
X  	if (error)
X  	{
X  		usage(argd);
X! 		exit(1);
X  	}
X  }
X  /*
X  **  USAGE -- print a usage message
X--- 262,271 ----
X  	if (error)
X  	{
X  		usage(argd);
X! 		exit(2);
X  	}
X+ 
X+ 	return argc;
X  }
X  /*
X  **  USAGE -- print a usage message
X***************
X*** 319,325 ****
X  		if (!BITSET(ARGREQ, ad->ad_flags))
X  			fprintf(stderr, "]");
X  	}
X! 	fprintf(stderr, "\n");
X  }
X  /*
X  **  ARGtype -- argument translation routines.
X--- 348,362 ----
X  		if (!BITSET(ARGREQ, ad->ad_flags))
X  			fprintf(stderr, "]");
X  	}
X! 	if(Extra) {
X! 		pl = 8 + strlen(Extra);
X! 		if (ll + pl > MaxOutputLine) {
X! 			fprintf(stderr, " \\\n\t");
X! 			ll = 7;
X! 		}
X! 		fprintf(stderr, " [<%s>]...\n", Extra);
X! 	} else
X! 		fprintf(stderr, "\n");
X  }
X  /*
X  **  ARGtype -- argument translation routines.
X***************
X*** 370,377 ****
X  	return (TRUE);
X  }
X  
X- /*ARGSUSED*/
X  BOOL
X  argInt(ad, vp, copyf)
X  	register ARGDESC *ad;
X  	register char *vp;
X--- 407,452 ----
X  	return (TRUE);
X  }
X  
X  BOOL
X+ argChar(ad, vp, copyf)
X+ 	register ARGDESC *ad;
X+ 	register char *vp;
X+ 	BOOL copyf;
X+ {
X+ 	auto char *vpp;
X+ 	extern long strtol ARGS((char *, char **, int));
X+ 	int status = FALSE;
X+ 	char c;
X+ 
X+ 	if (strlen(vp) == 2 && vp[0]=='^')
X+ 	{
X+ 		c = vp[1] ^ '@';
X+ 		status = TRUE;
X+ 	}
X+ 	else if(strlen(vp) > 1 && vp[0]=='\\')
X+ 	{
X+ 		c = (int) strtol(&vp[1], &vpp, 8);
X+ 		if (*vpp == '\0')
X+ 			status = TRUE;
X+ 	}
X+ 	else if(strlen(vp) == 1)
X+ 	{
X+ 		c = *vp;
X+ 		status = TRUE;
X+ 	}
X+ 
X+ 	if(status == TRUE)
X+ 		*(char *) ad->ad_valp = c;
X+ 	else
X+ 	{
X+ 		usrerr("invalid character argument '%s' for %s",
X+ 			vp, ad->ad_prompt);
X+ 	}
X+ 	return status;
X+ }
X+ 
X+ /*ARGSUSED*/
X+ BOOL
X  argInt(ad, vp, copyf)
X  	register ARGDESC *ad;
X  	register char *vp;
X***************
X*** 383,389 ****
X  	*(int *) ad->ad_valp = (int) strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s'", vp);
X  		return (FALSE);
X  	}
X  	else
X--- 458,465 ----
X  	*(int *) ad->ad_valp = (int) strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s' for %s",
X! 			vp, ad->ad_prompt);
X  		return (FALSE);
X  	}
X  	else
X***************
X*** 405,411 ****
X  	*(short *) ad->ad_valp = (short) strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s'", vp);
X  		return (FALSE);
X  	}
X  	else
X--- 481,488 ----
X  	*(short *) ad->ad_valp = (short) strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s' for %s",
X! 			vp, ad->ad_prompt);
X  		return (FALSE);
X  	}
X  	else
X***************
X*** 427,433 ****
X  	*(long *) ad->ad_valp = strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s'", vp);
X  		return (FALSE);
X  	}
X  	else
X--- 504,511 ----
X  	*(long *) ad->ad_valp = strtol(vp, &vpp, 0);
X  	if (*vpp != '\0')
X  	{
X! 		usrerr("invalid integer argument '%s' for %s",
X! 			vp, ad->ad_prompt);
X  		return (FALSE);
X  	}
X  	else
X***************
X*** 487,493 ****
X  		}
X  	}
X  
X! 	usrerr("invalid Boolean argument '%s'", vp);
X  	return (FALSE);
X  }
X  
X--- 565,571 ----
X  		}
X  	}
X  
X! 	usrerr("invalid Boolean argument '%s' for %s", vp, ad->ad_prompt);
X  	return (FALSE);
X  }
X  
Xparseargs.h orig/parseargs.h differ: char 900, line 37
X*** orig/parseargs.h
X--- parseargs.h
X***************
X*** 34,39 ****
X--- 34,40 ----
X  
X  /* types available for ad_type */
X  extern BOOL	argBool ARGS((ARGDESC *, char *, BOOL));
X+ extern BOOL	argChar ARGS((ARGDESC *, char *, BOOL));
X  extern BOOL	argStr ARGS((ARGDESC *, char *, BOOL));
X  extern BOOL	argInt ARGS((ARGDESC *, char *, BOOL));
X  extern BOOL	argShort ARGS((ARGDESC *, char *, BOOL));
Xstest.c orig/stest.c differ: char 267, line 15
X*** orig/stest.c
X--- stest.c
X***************
X*** 12,27 ****
X  */
X  
X  int	RepCount;
X! char	*XFlag;
X! char	*FirstArg;
X! BOOL	FFlag =		FALSE;
X  
X  ARGDESC	Args[] =
X  {
X! 	' ',	ARGREQ,		argStr,		__ &FirstArg,	"First Argument",
X! 	'c',	ARGREQ,		argInt,		__ &RepCount,	"Repetition Count",
X! 	'f',	ARGREQ,		argBool,	__ &FFlag,	"F Flag",
X! 	' ',	ARGOPT,		argStr,		__ &XFlag,	"This is a long string, to force wrap",
X  	ENDOFARGS
X  };
X  
X--- 12,33 ----
X  */
X  
X  int	RepCount;
X! char	*Name;
X! char	*DirName =	".";
X! BOOL	XFlag =		FALSE;
X! BOOL	YFlag =		FALSE;
X! BOOL	ZFlag =		FALSE;
X! char	TabChar =	':';
X  
X  ARGDESC	Args[] =
X  {
X! 	' ',	ARGREQ,		argStr,		__ &Name,	"Name",
X! 	'c',	ARGOPT,		argInt,		__ &RepCount,	"RepCount",
X! 	'd',	ARGOPT,		argStr,		__ &DirName,	"DirName",
X! 	'x',	ARGOPT,		argBool,	__ &XFlag,	"XFlag",
X! 	'y',	ARGOPT,		argBool,	__ &YFlag,	"YFlag",
X! 	'z',	ARGOPT,		argBool,	__ &ZFlag,	"ZFlag",
X! 	't',	ARGOPT,		argChar,	__ &TabChar,	"TabChar",
X  	ENDOFARGS
X  };
X  
X***************
X*** 29,37 ****
X  	int argc;
X  	char **argv;
X  {
X! 	parseargs(argv, Args);
X! 	printf("FirstArg = '%s', RepCount = %d, FFlag = %d\n",
X! 		FirstArg, RepCount, FFlag);
X  	TRACE(1, 2, ("hello world\n"));
X  	exit(0);
X  }
X--- 35,58 ----
X  	int argc;
X  	char **argv;
X  {
X! 	int newargc;
X! 
X! 	newargc = parseargs(argv, Args, "File");
X! 	printf("Name = \"%s\", DirName = \"%s\", RepCount = %d,\n",
X! 		Name, DirName, RepCount);
X! 	printf("XFlag = %d, YFlag = %d, ZFlag = %d, TabChar=%03o;\n",
X! 		XFlag, YFlag, ZFlag, TabChar);
X! 	if(newargc > 1) {
X! 		printf("%d remaining args: ", newargc-1);
X! 		argv++;
X! 		while(*argv) {
X! 			printf("%s", *argv++);
X! 			if(*argv)
X! 				putchar(' ');
X! 			else
X! 				putchar('\n');
X! 		}
X! 	}
X  	TRACE(1, 2, ("hello world\n"));
X  	exit(0);
X  }
Xuseful.h orig/useful.h differ: char 1894, line 117
X*** orig/useful.h
X--- useful.h
X***************
X*** 114,117 ****
X--- 114,122 ----
X  #define MAXINPUTLINE	200		/* maximum string input line */
X  #define MAXWORDLEN	100		/* maximum word (token) length */
X  
X+ #ifndef BSD
X+ #define bcopy(f,t,l) memcpy(t,f,l)
X+ #define bcmp(s,t,l) memcmp(s,t,l)
X+ #endif
X+ 
X  #endif /* _USEFUL_H_ */
//END_OF_FILE
echo x - strtol.c
sed 's/^X//' > strtol.c << '//END_OF_FILE'
X#ifndef BSD
X#include <ctype.h>
X
X#define XX 36
Xstatic char valof[128] = {
X	XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
X	XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
X	XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
X	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, XX, XX, XX, XX, XX, XX,
X	XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
X	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX,
X	XX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
X	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, XX, XX, XX, XX, XX
X};
X
Xlong strtol(str, ptr, base)
Xchar *str;
Xchar **ptr;
Xint base;
X{
X	long digit;
X	char *s;
X	char *p;
X	long val, sign;
X
X	s = str;
X	while(isspace(*s))
X		s++;
X
X	if(*s=='-') {
X		sign = -1L;
X		s++;
X	} else
X		sign = 1L;
X
X	if(base <= 0 || base > 36) {
X		if(s[0]=='0') {
X			if(s[1]=='x' || s[1]=='X')
X				base = 16;
X			else
X				base = 8;
X		} else
X			base = 10;
X	}
X
X	if(base==16 && s[0]=='0' && (s[1] == 'X' || s[1] == 'x'))
X		s += 2;
X
X	val = 0L;
X
X	if(*s > 0 && *s < 128) {
X		digit = valof[*s];
X		if(digit >= base) {
X			if(ptr) *ptr = str;
X			return 0L;
X		}
X	} else {
X		if(ptr) *ptr = str;
X		return 0L;
X	}
X
X	do {
X		val = val * base + digit;
X		s++;
X		digit = valof[*s];
X		if(digit >= base)
X			break;
X	} while(*s > 0 && *s < 128);
X
X	if(ptr) *ptr = s;
X	return val * sign;
X}
X#endif
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0
-- 
 _--_|\  Peter da Silva. +1 713 274 5180. <peter at ficc.uu.net>.
/      \
\_.--._/ Xenix Support -- it's not just a job, it's an adventure!
      v  "Have you hugged your wolf today?" `-_-'



More information about the Alt.sources mailing list