v19i086: parseargs - functions to parse command line argument, Patch05e/5
Brad Appleton
brad at hcx1.ssd.csd.harris.com
Sat May 18 04:18:00 AEST 1991
Submitted-by: Brad Appleton <brad at hcx1.ssd.csd.harris.com>
Posting-number: Volume 19, Issue 86
Archive-name: parseargs/patch05e
Patch-To: parseargs: Volume 17, Issue 45-57
#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file PATCH05 continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 5; 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 PATCH05'
else
echo 'x - continuing file PATCH05'
sed 's/^X//' << 'SHAR_EOF' >> 'PATCH05' &&
- ment should be the object itself.
-
- If mode is pc_READ, then the desired attributes are copied
- into the object pointed to by the last parameter. If the
- mode is pc_WRITE, then the attributes from the last parame-
- ter are copied to the command- object. If mode is pc_RDWR,
- then the attributes pointed to by the last parameter are
- copied to the command-object, and then the previous value of
- these attributes (before they were overwritten) is copied
- into the object pointed to by the last parameter.
-
- If cntl is pc_ARGFLAGS, then the only valid mode is pc_READ.
- All other attributes may be written or read by parsecntl.
-
- FUNCTION CODES
- Each of the following function codes specifies an attribute
- that is to be manipulated by parsecntl. The function code
- is the second parameter to parsecntl. With the exception of
- pc_ARGFLAGS, each of the function codes corresponds to a
- call to parsecntl using four parameters ( pc_ARGFLAGS uses 5
- parameters). In each case, the last parameter is either the
- address of a buffer to write the attribute to, or the actual
- buffer to read the attribute from (depending upon the mode -
- the third parameter to parsecntl).
-
- pc_PARSEFLAGS
- This function code is used to read and/or modify the
- existing parsing parsing behavior. The fourth parameter
- to parsecntl should be a combination of pc_XXXX
-
-
-
- Page 1
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- bitmasks if the parse-flags are only being written,
- otherwise it should be a pointer to an argMask_t vari-
- able.
-
- pc_ARGFLAGS
- This function code may only be used to read the
- argument-flags of a named argument. It is an error to
- specify a mode that attempts to write the argument-
- flags with this function code. The fourth parameter to
- parsecntl should be the keyword name of the argument
- whose flags are to be read. The fifth (and final) argu-
- ment should be a pointer to the argMask_t variable
- which will receive the resulting argument-flags.
-
- pc_DEFARGS
- This function code is used to query or modify the
- current default argument-descriptor list for the given
- command. The fourth parameter to parsecntl should be
- the argument-descriptor array to assign as the new
- default-list (or the address of an argdesc-array if the
- default list is being retrieved).
-
- If a given option/qualifier does not appear to match
- any items in the argdesc-array, a default argdesc-
- array is then searched to match the option. If it is
- STILL unmatched then it is flagged as such. The
- default-argdesc array is automatically used by all
- programmer-defined argdesc-array but may be unset or
- reset using the pc_DEFARGS function of parsecntl. In
- such a manner, a programmer could specify a different
- set of default-arguments to search for. Furthermore,
- default argdesc-arrays may also be assigned default
- argdesc-arrays, thus allowing the programmer to define
- a whole search-list of default argdesc-arrays for a
- given command.
-
- This could prove useful in a situation where a set of
- commands have a few common-options and differ in their
- remaining ones. If the same main() were used for each
- command, then main could define one common argdesc-
- array and then a set of argdesc-arrays for each com-
- mand. Main could then figure out which argdesc-array to
- used based on the name in argv[0], and set its default
- argdesc-array to be the common argdesc-array, as in the
- following:
-
- #include <parseargs.h>
- .
- . variable declarations
- .
-
- static ARGDESC common_args[] = {
-
-
-
- Page 2
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- STARTOFARGS,
- { 'L', ARGOPT, argBool, __ &lflag, "list (list the items)" },
- { 'I', ARGOPT, argStr, __ &item, "item (item to use)" },
- ENDOFARGS
- };
-
- static ARGDESC cmd1_args[] = {
- STARTOFARGS,
- { 's', ARGOPT, argBool, __ &sflag, "S (set S)" },
- { 't', ARGOPT, argBool, __ &tflag, "T (set T)" },
- ENDOFARGS
- };
-
- static ARGDESC cmd2_args[] = {
- STARTOFARGS,
- { 'x', ARGOPT, argBool, __ &xflag, "X (set X)" },
- { 'y', ARGOPT, argBool, __ &yflag, "Y (set Y)" },
- ENDOFARGS
- };
-
- main( int argc, char *argv[] )
- {
- ARGDESC *cmd = cmd1_args;
- int rc;
-
- if ( strcmp(*argv, "cmd2") == 0 )
- cmd = cmd2_args;
-
- rc = parsecntl( cmd, pc_DEFARGS, pc_WRITE, common_args );
- if ( rc != pe_SUCCESS )
- syserr( "unable to set default args" );
-
- rc = parseargs( argv, cmd );
- .
- .
- .
- }
-
- Note that in the above call to parsecntl(3), that zero
- will be returned upon success and non-zero upon
- failure. If pe_DEFARGS is returned, then cmd is already
- on common_args's list of defaults (and would result in
- an infinite loop while parsing).
-
- pc_NAME
-
- pc_PURPOSE
-
- pc_DESCRIPTION
- Each of these last three function codes are used to
- modify or query the name, purpose, or description asso-
- ciated with a command. The fourth parameter to
-
-
-
- Page 3
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- parsecntl should be the new string to use (or the
- address of the string, a char** variable, to recieve
- the current value).
-
- PARSE MODES
- Parsecntl may be used to read current command attributes,
- write (assign) new command attributes, or both. The mode
- argument to parsecntl determines which of these three alter-
- natives are desired. If the programmer merely wishes to
- assign new attributes, then invoking parsecntl in pc_WRITE
- mode and passing the new attributes will do the job. If the
- programmer wishes simply to query attributes, then invoking
- parsecntl in pc_READ mode and passing a pointer to the
- desired object in which to write the attribute settings will
- suffice.
-
- If the programmer wishes to assign new attributes and at the
- same time find out what the attributes were before making
- the assignment, then programmer must invoke parsecntl for
- pc_RDWR mode and pass a pointer to the object containing the
- new attribute settings; When parsecntl returns, then (assum-
- ing it returns 0) the desired attributes will have been
- assigned and the object that contained the new attribute
- settings will now contain the attribute settings that were
- in effect immediately before parsecntl was invoked.
-
- PARSE FLAGS
- The following bitmasks may be combined in order to modify
- the behavior of the parseargs library. The parse flags for a
- given may be set through the use of the parsecntl(3) func-
- tion.
-
- pa_PROMPT
- Prompt the user for any missing arguments that are
- required on the command-line. No special escaping or
- quoting is performed on the user input. Required argu-
- ments that expect a list of values will be repeatedly
- prompted for (one item per line) until a blank line
- (followed by a carriage return) is entered.
-
- pa_IGNORE
- Ignore any unrecognized or improperly specified
- command-line arguments and continue execution of the
- program. Normally, if a required argument is unmatched
- (or an argument is improperly specified), a usage mes-
- sage is printed program execution is terminated.
-
- pa_OPTSONLY
- Under UNIX, setting this flag will disable the parsing
- of long-option syntax. This will cause all arguments
- starting with `+' to always be treated as a positional
- parameter (instead of a long-option).
-
-
-
- Page 4
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- pa_KWDSONLY
- Under UNIX, setting this flag disables the parsing of
- single-character options. This will cause all argu-
- ments starting with `-' to always be treated as a posi-
- tional parameter (instead of an option).
-
- pa_FLAGS1ST
- Setting this flag causes the parseargs library to force
- any and all non-positional arguments to be specified
- before any positional ones. As an example, under UNIX,
- if this flag is SET then parseargs will consider the
- command line "cmd -x arg" to consist of one option and
- one positional argument; however the command line "cmd
- arg -x" would be considered to consist of two posi-
- tional arguments (the -x option will be unmatched).
-
- If this flag is UNSET, then both of the previous exam-
- ples are considered to consist of one option and one
- positional argument.
-
- pa_ANYCASE
- Setting this flag will cause character-case to be
- ignored when attempting to match single-character argu-
- ment names (i.e. causes "-i" and "-I" to be considered
- equivalent).
-
- pa_ARGV0
- Normally, the parseargs library will assume that the
- first argument on the command-line is the name of the
- command. Setting this flag tells parseargs that this is
- NOT the case and that the very first argument on the
- command-line is a bona-fide argument to the command.
-
- pa_NOCHECK
- Setting this flag will prevent parseargs from checking
- for any required arguments that were not given on the
- command-line. This is useful when more than one call to
- the parseargs library is needed to parse all the
- command-line arguments (which could occur if the
- command-line argument came from a file or from two
- argv-vectors).
-
- Keeping this flag on until the final set of arguments
- is parsed will cause parseargs to not check for missing
- arguments until the last set of arguments has been
- parsed (by the final call to one of the functions in
- the parseargs library).
-
- pa_CONTINUE
- Setting this flag will cause subsequent calls to the
- parseargs library to NOT reset the current command-
- state. Hence, all arguments will not be initially set
-
-
-
- Page 5
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- to "NOT GIVEN" and other (normal) initializations are
- not be performed. This is useful in conjunction with
- the pa_NOCHECK flag when more than one call to par-
- seargs is required to parse all the command arguments.
- In this scenario, pa_CONTINUE should be unset (the
- default setting) for the very first call to parseargs,
- but should then be set before any subsequent calls to
- parseargs are made.
-
- pa_NOCMDENV
- Setting this flag prevents parseargs from checking the
- CMD-NAME_ARGS environment variable (or symbol) for any
- user-defined default command arguments.
-
- pa_COPYF
- When this flag is OFF (the default), a value of FALSE
- is provided as the copyf argument to all the arg-type
- (argXxxxx) functions when an argument is matched. Set-
- ting this flag will cause a value of TRUE to be pro-
- vided as the copyf argument to all the arg-type
- (argXxxxx) functions when an argument is matched.
-
- ARGUMENT FLAGS
- These are the possible bitmasks that may be turned ON or OFF
- in the ad_flags field of an ARGDESC structure.
-
- ARGOPT
- This flag is actually a dummy flag (i.e. it is the
- default). This flag specifies that the command-line
- argument is optional (need not appear on the command-
- line). It is only needed if no other flags are used to
- define the given argument. If other flags are given
- and ARGREQ is NOT one of them, then ARGOPT is always
- assumed.
-
- ARGREQ
- The associated command argument is required on the
- command-line.
-
- ARGPOS
- The associated command argument is positonal. The
- difference between using this flag to indicate a posi-
- tional argument and between using a blank in the
- ad_name field to indicate a positional arguments is the
- following: If this flag is set but the ad_name of the
- argument is non-blank, then this argument may be
- matched either positionally or by keyword. If the
- ad_name field is blank, then this argument may only be
- matched positionally.
-
- ARGNOVAL
- The associated command argument takes no value (as in
-
-
-
- Page 6
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- "-x value"); Its mere presence (or lack thereof) on the
- command-line is sufficient to determine the necessary
- action(s) to take (as in "-x"). Boolean argument types
- and Pseudo-argument types automatically default to ARG-
- NOVAL.
-
- ARGVALOPT
- This flag is used to indicate that the command-line
- argument takes a value (as in "-s string" or
- "/str=string") but that the value to this command-line
- argument is NOT required (hence simply "-s" or "/str"
- is also permissable).
-
- ARGVALREQ
- Another "dummy" flag. Unless ARGNOVAL or ARGVALOPT is
- specified, ARGVALREQ is always assumed. This flag indi-
- cates that the value to a command-line argument is
- required (hence "-s string" is okay but just "-s" is
- not).
-
- ARGHIDDEN
- Don't display this argument in usage messages but still
- attempt to match it against strings given on the
- command-line.
-
- ARGLIST
- A variable number of values are used for this argument
- (and hence may use more than one or two argv elements
- from the command-line as in "-l val1 val2 ..."). The
- list of values must be stored in an ArgList structure
- (NOT a vector structure), an the corresponding
- argument-type function should be one of the listXxxx
- functions.
-
- ARGVEC
- A variable number of values are used for this argument
- (and hence may use more than one or two argv elements
- from the command-line as in in "-v val1 val2 ..."). The
- list of values must be stored in a vector structure
- (NOT an ArgList structure).
-
- The following bitmasks may also be present, but, unlike the
- above masks which must be specified by the programmer at
- initialization time, the following masks must only be read
- (never set) by the programmer. They may be queried by using
- the pc_ARGFLAGS function code and the mode pc_READ with par-
- secntl(3).
-
- ARGGIVEN
- The argument WAS given on the command-line.
-
- ARGVALGIVEN
-
-
-
- Page 7
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- The value for this argument was given on the command-
- line.
-
- ARGVALSEP
- The value to this argument was supplied in a separate
- argv element from the argument itself (as in "-x value"
- as opposed to "-xvalue").
-
- ARGKEYWORD
- This argument was matched as a keyword (long-form) on
- the command-line and not as a single character.
-
- ARGDESCRIBED
- This argument was given a description by the programmer
- at initialization.
-
- ARGCOPYF
- This flag is only used for lists and vectors (mul-
- tivalued arguments) and is used on a per-item basis. If
- it is set, it means that the corresponding value in the
- vector/list required space to be allocated (such as the
- duplication of a temporary string).
-
- RETURN VALUE
- The functions in the parseargs library will return a value
- of zero upon succesful completion. They may however, return
- any of the following status codes (which are defined in
- <parseargs.h>):
-
- pe_SYSTEM
- A system error occurred. The global variable errno may
- indicate the problem (then again, it may not).
-
- pe_SUCCESS
- Success, no errors encountered (zero is returned).
-
- pe_SYNTAX
- A command-line syntax error was encountered
-
- pe_DEFARGS
- An attempt (using parsecntl) was made to change the
- default arg-search list of a command to point to an
- argdesc-array which already has the given command on
- its default arg-search list (which would cause an
- infinite loop when attempting to match an unknown
- command-line argument).
-
- pe_NOMATCH
- Unable to match the named argument. This occurs when
- the argument keyword name passed to parsecntl (using
- the pc_ARGFLAGS functions code) was found in the given
- argdesc-array or in its default-list.
-
-
-
- Page 8
-
-
-
-
-
-
- PARSECNTL(3) PARSECNTL(3)
-
-
-
- pe_BADMODE
- Bad mode for given command in parsecntl. This occurs
- when pc_WRITE or pc_RDWR mode is passed to parsecntl in
- conjunction with the pc_ARGFLAGS functions code. Par-
- secntl will not modify existing arguments.
-
- pe_BADCNTL
- Bad command for parsecntl. This occurs if an unknown
- function-code was passed to parsecntl.
-
- SIDE EFFECTS
- Each of the functions in the parseargs library will set the
- external character string ProgName to be the name of the
- last command that was operated upon by any of the library
- routines.
-
- When an argument-descriptor array is first encountered by
- any of the parseargs library routines, it is initially com-
- piled into an intermediate form that is more convenient to
- manipulate. As a direct result, it is not advisable to
- attempt to index directly into the array to manipulate one
- of the argument descriptors (because the argdesc that you
- thought was there may actually be somewhere else). After the
- array has been given its initial value(s), only parsecntl(3)
- should be used to manipulate or query the attributes of an
- argument descriptor.
-
- SEE ALSO
- argtype(3), parseargs(3), parseargs(1)
-
- AUTHOR
- Brad Appleton (brad at ssd.csd.harris.com)
- Harris Computer Systems, Fort Lauderdale, FL USA
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 9
-
-
-
--- 0 ----
diff -cNr ../patchlevel4/patchlevel.h ./patchlevel.h
*** ../patchlevel4/patchlevel.h Thu May 2 11:05:47 1991
--- ./patchlevel.h Thu May 2 14:36:20 1991
***************
*** 2,22 ****
X ** ^FILE: patchlevel.h - current patchlevel for parseargs
X **
X ** ^HISTORY:
X ** 04/10/91 Brad Appleton <brad at ssd.csd.harris.com>
X ** Patch04
X ** - fixed problem with prompting in xparse.c:prompt_user()
! ** - under vms, getenv was defined to be 'getsymbol', it should be
! ** 'get_symbol' (note the underscore).
! ** - now uses <errno.h>
! ** - parseargs no longer included <fcntl.h>
X ** - fix bug in vms_args.c printing '[]' for required args and vis-a-vis
! ** - fixed bug in argInput and argOutput in argtype.c
X ** - fixed bug in <os>_args.c where ARGVALGIVEN was improperly being
X ** cleared if the argument was a list or a vector. This was causing
X ** parseargs(1) to screw up on optional lists.
! ** - fixed bug in strfuncs.c:strnicmp()
X ** - changed strfuncs.[ch] so that my version of strdup is always used
! ** (my version dies if malloc failed, others return NULL).
X ** - Added some changes for SUN and VAX
X ** - Added -1 option to parseargs(1)
X ** - Unhid the -# option to parseargs(1)
--- 2,36 ----
X ** ^FILE: patchlevel.h - current patchlevel for parseargs
X **
X ** ^HISTORY:
+ ** 04/25/91 Brad Appleton <brad at ssd.csd.harris.com>
+ ** Patch05
+ ** - documented support for zsh in parseargs(1)
+ ** - added missing call to pclose() in pgopen.c:pgclose()
+ ** - added zsh to the list of shells supported by parseargs(1)
+ ** (I have yet to document this in the man-pages)
+ ** - changed the shell_info structure used by parseargs(1) to
+ ** represent different shells. It should now be much simpler
+ ** to add new shells to parseargs.c
+ ** - fixed a bug in strfuncs.c:basename() for VMS systems
+ ** - added more comments to explain whats going on in each <os>_args.c
+ ** - updated the README file to correspond with the patchlevel(s)
+ ** - updated dependencies in doc/Makefile
+ **
X ** 04/10/91 Brad Appleton <brad at ssd.csd.harris.com>
X ** Patch04
X ** - fixed problem with prompting in xparse.c:prompt_user()
! ** - under VMS, getenv was defined to be 'getsymbol', it should
! ** be 'get_symbol' (note the underscore).
! ** - now includes <errno.h> to declare errno
! ** - parseargs no longer includes <fcntl.h>
X ** - fix bug in vms_args.c printing '[]' for required args and vis-a-vis
! ** - fixed bug in argInput and argOutput in argtype.c for VMS
X ** - fixed bug in <os>_args.c where ARGVALGIVEN was improperly being
X ** cleared if the argument was a list or a vector. This was causing
X ** parseargs(1) to screw up on optional lists.
! ** - fixed bug in strfuncs.c:strnicmp() (it was ignoring the length)
X ** - changed strfuncs.[ch] so that my version of strdup is always used
! ** (my version exits if malloc failed, others return NULL).
X ** - Added some changes for SUN and VAX
X ** - Added -1 option to parseargs(1)
X ** - Unhid the -# option to parseargs(1)
***************
*** 25,31 ****
X ** 04/04/91 Brad Appleton <brad at ssd.csd.harris.com>
X ** Patch04 (continued)
X ** - fixed bug in xparse.c with PARSECNTL='Prompt' being ignored.
- ** - added test.pl to test.all and added options to test.all
X ** - fixed newline printing error in perl-scripts for parseargs(1)
X ** - added -C option to parseargs(1) and to the docs
X ** - added "patchlevel.h" to distribution
--- 39,44 ----
***************
*** 53,59 ****
X
X #define VERSION 2
X #define REVISION 0
! #define PATCHLEVEL 4
X
X #ifdef __STDC__
X static const char
--- 66,72 ----
X
X #define VERSION 2
X #define REVISION 0
! #define PATCHLEVEL 5
X
X #ifdef __STDC__
X static const char
***************
*** 60,63 ****
X #else
X static char
X #endif
! _Ident[] = "@(#)parseargs 2.0 patchlevel 4";
--- 73,76 ----
X #else
X static char
X #endif
! _Ident[] = "@(#)parseargs 2.0 patchlevel 5";
diff -cNr ../patchlevel4/pgopen.c ./pgopen.c
*** ../patchlevel4/pgopen.c Thu May 2 11:06:13 1991
--- ./pgopen.c Thu May 2 14:36:23 1991
***************
*** 71,77 ****
X extern int strcmp();
X extern int access();
X extern int isatty();
- extern int wait();
X extern unsigned sleep();
X
X static void pg_error(); /* broken-pipe exception handler */
--- 71,76 ----
***************
*** 157,163 ****
X ** - if we used popen() to open this pager then
X ** - call pclose to close the pager-program
X ** - unset the SIGPIPE signal-handler
- ** - wait for the pager-process to die
X ** end-if
X ** - reset the pager-file-pointer to NULL
X ** - set the pager-state to closed
--- 156,161 ----
***************
*** 172,179 ****
X fflush( Pager_FP );
X
X if ( Pager_Type == PG_ENV || Pager_Type == PG_DFLT ) {
! signal( SIGPIPE, (void (*)())SIG_IGN );
! wait( (int *) 0 );
X }
X
X Pager_FP = (FILE *)NULL;
--- 170,177 ----
X fflush( Pager_FP );
X
X if ( Pager_Type == PG_ENV || Pager_Type == PG_DFLT ) {
! (VOID) pclose( Pager_FP );
! (VOID) signal( SIGPIPE, (void (*)())SIG_IGN );
X }
X
X Pager_FP = (FILE *)NULL;
diff -cNr ../patchlevel4/strfuncs.c ./strfuncs.c
*** ../patchlevel4/strfuncs.c Thu May 2 11:06:14 1991
--- ./strfuncs.c Thu May 2 14:36:35 1991
***************
*** 12,17 ****
--- 12,19 ----
X ** strlcpy() -- copy a string and map to lowercase
X ** strupr() -- convert a string to uppercase
X ** strlwr() -- convert a string to lowercase
+ ** stricmp() -- case insensitive comparison of strings
+ ** strnicmp() -- case insensitive length-limited comparison of strings
X ** strdup() -- return a (newly allocated) copy of a string
X ** strpbrk() -- return first occurrence of character in a set
X ** strspn() -- return length of initial prefix of a character set
***************
*** 20,31 ****
X ** strrtrim() -- trim rightmost (trailing) characters in a string
X ** strtrim() -- trim leading and trailing characters in a string
X ** strsplit() -- split a string up into a vector of tokens
! ** strjoin() -- join a vector of token into a single string
X ** get_name() -- return the aname (argument-name) of an argument
X ** get_keyword() -- return the sname (keyword-name) of an argument
X ** match() -- match two keywords (case insensitive) upto a unique prefix
- ** stricmp() -- case insensitive comparison of strings
- ** strnicmp() -- case insensitive length-limited comparison of strings
X ** basename() -- remove the leading directories (and disks) from a path
X ** indent_para() -- print an indented hanging paragraph
X **
--- 22,31 ----
X ** strrtrim() -- trim rightmost (trailing) characters in a string
X ** strtrim() -- trim leading and trailing characters in a string
X ** strsplit() -- split a string up into a vector of tokens
! ** strjoin() -- join a vector of tokens into a single string
X ** get_name() -- return the aname (argument-name) of an argument
X ** get_keyword() -- return the sname (keyword-name) of an argument
X ** match() -- match two keywords (case insensitive) upto a unique prefix
X ** basename() -- remove the leading directories (and disks) from a path
X ** indent_para() -- print an indented hanging paragraph
X **
***************
*** 601,607 ****
X ** - for i in 0 .. (numtokens - 1) do
X ** - vector[i] = token_str
X ** - advance token_str to point at the next character past the
! ** righmost NUL-byte (which should be the start of the next token).
X ** end-for
X ** - return the number of tokens parsed.
X ***^^**********************************************************************/
--- 601,607 ----
X ** - for i in 0 .. (numtokens - 1) do
X ** - vector[i] = token_str
X ** - advance token_str to point at the next character past the
! ** rightmost NUL-byte (which should be the start of the next token).
X ** end-for
X ** - return the number of tokens parsed.
X ***^^**********************************************************************/
***************
*** 680,687 ****
X
X /* ^DESCRIPTION:
X ** 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>.
X **
X ** If <separator> is NULL then a single space is used as the separator.
X ** If <separator> is empty, then no separator is used and the tokens are
--- 680,687 ----
X
X /* ^DESCRIPTION:
X ** Strjoin will make a single string out of the given vector by copying
! ** all the tokens from the given vector (in order) to a newly allocated
! ** string. Tokens will be separated by a single occurence of <separator>.
X **
X ** If <separator> is NULL then a single space is used as the separator.
X ** If <separator> is empty, then no separator is used and the tokens are
***************
*** 688,701 ****
X ** simply concatenated together.
X **
X ** ^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).
X **
X ** ^SIDE-EFECTS:
X ** Storage is allocated.
X **
X ** ^RETURN-VALUE:
! ** The addres of the newly-joined results (which should be deallocated
X ** using free()). Returns NULL if nothing was joined.
X **
X ** ^ALGORITHM:
--- 688,701 ----
X ** simply concatenated together.
X **
X ** ^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).
X **
X ** ^SIDE-EFECTS:
X ** Storage is allocated.
X **
X ** ^RETURN-VALUE:
! ** The address of the newly-joined result (which should be deallocated
X ** using free()). Returns NULL if nothing was joined.
X **
X ** ^ALGORITHM:
***************
*** 1078,1084 ****
X
X if ( vers ) *vers ='\0';
X if ( ext && (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
! ext = '\0';
X }
X
X return base;
--- 1078,1084 ----
X
X if ( vers ) *vers ='\0';
X if ( ext && (!stricmp(ext, ".COM") || !stricmp(ext, ".EXE")) ) {
! *ext = '\0';
X }
X
X return base;
***************
*** 1200,1206 ****
X char ch;
X
X /* print the title */
! fprintf( fp, "%*s%-*s", margin, "", indent, title );
X
X idx = maxcols - margin - indent;
X
--- 1200,1206 ----
X char ch;
X
X /* print the title */
! fprintf( fp, "%*s%-*s", margin, "", indent, title );
X
X idx = maxcols - margin - indent;
X
diff -cNr ../patchlevel4/strfuncs.h ./strfuncs.h
*** ../patchlevel4/strfuncs.h Thu May 2 11:06:15 1991
--- ./strfuncs.h Thu May 2 14:36:38 1991
***************
*** 32,37 ****
--- 32,38 ----
X EXTERN char *strtrim ARGS(( char *, const char * ));
X EXTERN int strsplit ARGS(( char ***, char *, const char * ));
X EXTERN char *strjoin ARGS(( const char **, const char * ));
+
X EXTERN char *get_name ARGS(( const char *, char * ));
X EXTERN char *get_keyword ARGS(( const char *, char * ));
X EXTERN int match ARGS(( const char *, const char * ));
diff -cNr ../patchlevel4/test.ksh ./test.ksh
*** ../patchlevel4/test.ksh Thu May 2 10:57:08 1991
--- ./test.ksh Thu May 2 14:36:50 1991
***************
*** 22,33 ****
X export ARGUMENTS
X
X ## set defaults ##
- typeset groups[] ## default group used by everyone
X typeset count='1' ## only do once unless otherwise specified
X typeset dirname='.' ## default to current directory
X typeset xflag='' ## default xflag is false
X typeset yflag='TRUE' ## default yflag is true
X typeset sepch=',' ## default separator is a comma
X typeset files[]
X
X ## parse command-line ##
--- 22,33 ----
X export ARGUMENTS
X
X ## set defaults ##
X typeset count='1' ## only do once unless otherwise specified
X typeset dirname='.' ## default to current directory
X typeset xflag='' ## default xflag is false
X typeset yflag='TRUE' ## default yflag is true
X typeset sepch=',' ## default separator is a comma
+ typeset groups[]
X typeset files[]
X
X ## parse command-line ##
diff -cNr ../patchlevel4/test.zsh ./test.zsh
*** ../patchlevel4/test.zsh Wed Dec 31 18:00:00 1969
--- ./test.zsh Thu May 2 14:36:59 1991
***************
*** 0 ****
--- 1,65 ----
+ #!/bin/zsh
+ #
+ # test.zsh - Z shell script to test out the parseargs command!
+ #
+
+ NAME="`basename $0`"
+
+ ARGUMENTS="
+ '?', ARGHIDDEN, argUsage, NULL, 'Help -- print usage and exit',
+ 'S', ARGVALOPT, argStr, string, 'STRing -- optional string arg',
+ 'g', ARGLIST, argStr, groups, 'newsGROUPS -- groups to test',
+ 'r', ARGOPT, argInt, count, 'REPcount -- number to repeat each group',
+ 'd', ARGOPT, argStr, dirname, 'DIRectory -- working directory',
+ 'x', ARGOPT, argBool, xflag, 'Xflag -- turn on X-mode',
+ 'y', ARGOPT, argUBool, yflag, 'Yflag -- turn off Y-mode',
+ 's', ARGOPT, argChar, sepch, 'SEPchar -- field separator',
+ 'f', ARGLIST, argStr, files, 'files -- files to process',
+ 'n', ARGREQ|ARGPOS, argStr, name, 'name -- name to use',
+ ' ', ARGLIST, argStr, argv, 'argv -- any remaining arguments',
+ ENDOFARGS
+ "
+ export ARGUMENTS
+
+ ## set defaults ##
+ typeset count='1' ## only do once unless otherwise specified
+ typeset dirname='.' ## default to current directory
+ typeset xflag='' ## default xflag is false
+ typeset yflag='TRUE' ## default yflag is true
+ typeset sepch=',' ## default separator is a comma
+ typeset groups
+ typeset files
+
+ ## parse command-line ##
+ parseargs -s zsh -e ARGUMENTS -u -- "$NAME" "$@" >/tmp/tmp$$
+ if [ $? -ne 0 ] ; then
+ rm -f /tmp/tmp$$
+ exit 2 ## improper syntax (or just wanted usage)
+ fi
+
+ ## evaluate results from parseargs and remove temporary file ##
+ INTERPRET="."
+ $INTERPRET /tmp/tmp$$
+ rm -f /tmp/tmp$$
+
+ ## print arguments ##
+ print "ARGUMENTS:"
+ print "=========="
+ print "Groups='${groups[@]}'"
+ print "Count='$count'"
+ print "Directory='$dirname'"
+ print "XFlag='$xflag'"
+ print "YFlag='$yflag'"
+ print "SepChar='$sepch'"
+ print "Name='$name'"
+ print "Files='${files[@]}'"
+ if [ "$string_flag" ] ; then
+ string=${string:-"!string arg ommitted on cmd-line!"}
+ else
+ string="default string"
+ fi
+ print "String='$string'"
+ print "New Positional Parameters='$*'"
+
+ ## print usage ##
+ parseargs -a "$ARGUMENTS" -U "$NAME"
diff -cNr ../patchlevel4/unix_args.c ./unix_args.c
*** ../patchlevel4/unix_args.c Thu May 2 11:06:16 1991
--- ./unix_args.c Thu May 2 14:37:02 1991
***************
*** 128,134 ****
X cmd = argd;
X
X while ( av && (p = *av++) ) {
! if ( isKWD(p) ) {
X char *s, c = '\0';
X
X /* check for `++' to end flags */
--- 128,134 ----
X cmd = argd;
X
X while ( av && (p = *av++) ) {
! if ( isKWD(p) ) { /* we have a keyword here */
X char *s, c = '\0';
X
X /* check for `++' to end flags */
***************
*** 166,171 ****
--- 166,176 ----
X continue;
X }
X
+ /* reset the argument flags - if this arg was already given, some
+ ** of its flags may be set to indicate how it was given before.
+ ** we need to know how it was given now (but save the old ones
+ ** just in case the new one fails).
+ */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
***************
*** 174,180 ****
X
X BSET( arg_flags(ad), ARGKEYWORD );
X
! if( ARG_isMULTIVAL(ad) ) {
X cmd_list(cmd) = ad;
X }
X else {
--- 179,185 ----
X
X BSET( arg_flags(ad), ARGKEYWORD );
X
! if( ARG_isMULTIVAL(ad) ) { /* we matched a list (or a vector) */
X cmd_list(cmd) = ad;
X }
X else {
***************
*** 245,251 ****
X continue;
X }
X
! /* flag argument */
X while (*p) {
X
X /* find the flag in the list */
--- 250,261 ----
X continue;
X }
X
! /* We have a flag argument;
! ** remember that in the case of single character keywords,
! ** the conversion function (ad_type) tells us how many characters
! ** were used. We need that information to decide how many
! ** characters to skip before the next iteration of the while loop.
! */
X while (*p) {
X
X /* find the flag in the list */
***************
*** 276,281 ****
--- 286,296 ----
X continue;
X }/* if unknown-option */
X
+ /* reset the argument flags - if this arg was already given, some
+ ** of its flags may be set to indicate how it was given before.
+ ** we need to know how it was given now (but save the old ones
+ ** just in case the new one fails).
+ */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
***************
*** 283,289 ****
X }
X
X if( ARG_isMULTIVAL(ad) ) {
! cmd_list(cmd) = ad;
X }
X else {
X cmd_list(cmd) = ARGDESCNULL;
--- 298,304 ----
X }
X
X if( ARG_isMULTIVAL(ad) ) {
! cmd_list(cmd) = ad; /* we matched a list (or a vector) */
X }
X else {
X cmd_list(cmd) = ARGDESCNULL;
***************
*** 358,365 ****
X }/*elif option*/
X else {
X /* parsing a list of arguments */
! if ( cmd_list(cmd) ) {
X ad = cmd_list(cmd);
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
--- 373,386 ----
X }/*elif option*/
X else {
X /* parsing a list of arguments */
! if ( cmd_list(cmd) ) { /* we're in the middle of a list */
X ad = cmd_list(cmd);
+
+ /* reset the argument flags - if this arg was already given, some
+ ** of its flags may be set to indicate how it was given before.
+ ** we need to know how it was given now (but save the old ones
+ ** just in case the new one fails).
+ */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
***************
*** 395,400 ****
--- 416,426 ----
X continue;
X }
X
+ /* reset the argument flags - if this arg was already given, some
+ ** of its flags may be set to indicate how it was given before.
+ ** we need to know how it was given now (but save the old ones
+ ** just in case the new one fails).
+ */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP | ARGKEYWORD );
***************
*** 401,410 ****
X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
X }
X
! if ( ARG_isMULTIVAL(ad) ) {
X cmd_list(cmd) = ad;
X }
X
X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
X BSET( cmd_state(cmd), ps_NOFLAGS );
X }
--- 427,437 ----
X if ( !ARG_isMULTIVAL(ad) ) BCLEAR( arg_flags(ad), ARGVALGIVEN );
X }
X
! if ( ARG_isMULTIVAL(ad) ) { /* we positionally matched a list */
X cmd_list(cmd) = ad;
X }
X
+ /* if FLAGS1ST is set then first positional marks end-of-flags */
X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
X BSET( cmd_state(cmd), ps_NOFLAGS );
X }
diff -cNr ../patchlevel4/useful.h ./useful.h
*** ../patchlevel4/useful.h Thu May 2 11:06:17 1991
--- ./useful.h Thu May 2 14:37:07 1991
***************
*** 25,31 ****
X #ifndef _USEFUL_H_
X #define _USEFUL_H_
X
! #if ( defined(_unix) || defined(UNIX) || defined(__UNIX) )
X # ifndef unix
X # define unix
X # endif
--- 25,31 ----
X #ifndef _USEFUL_H_
X #define _USEFUL_H_
X
! #if (defined(_unix) || defined(__unix) || defined(_unix_) || defined(__unix__))
X # ifndef unix
X # define unix
X # endif
***************
*** 44,50 ****
X # ifdef sun
X # define BSD
X # endif
! # ifdef apollo
X # define BSD
X # endif
X # if ( defined(_CX_UX) && defined(ucb_universe) )
--- 44,50 ----
X # ifdef sun
X # define BSD
X # endif
! # if ( defined(apollo) || defined(aegis) )
X # define BSD
X # endif
X # if ( defined(_CX_UX) && defined(ucb_universe) )
***************
*** 203,209 ****
X # define FILENULL ((FILE *) NULL)
X #endif
X
! #ifdef __ANSI_C__
X typedef void *ARBPTR;
X #else
X typedef char *ARBPTR;
--- 203,209 ----
X # define FILENULL ((FILE *) NULL)
X #endif
X
! #if ( defined(__ANSI_C__) || defined(vms) )
X typedef void *ARBPTR;
X #else
X typedef char *ARBPTR;
diff -cNr ../patchlevel4/vms_args.c ./vms_args.c
*** ../patchlevel4/vms_args.c Thu May 2 11:06:18 1991
--- ./vms_args.c Thu May 2 14:37:09 1991
***************
*** 653,659 ****
X cmd_flags(cmd) = saveflags;
X exit(1);
X }
! /* have we seen this one before */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP );
--- 653,663 ----
X cmd_flags(cmd) = saveflags;
X exit(1);
X }
! /* reset the argument flags - if this arg was already given, some
! ** of its flags may be set to indicate how it was given before.
! ** we need to know how it was given now (but save the old ones
! ** just in case the new one fails).
! */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP );
***************
*** 752,760 ****
--- 756,771 ----
X continue;
X }
X
+ /* if FLAGS1ST is set then first positional marks end-of-flags */
X if ( BTEST(cmd_flags(cmd), pa_FLAGS1ST) ) {
X BSET( cmd_state(cmd), ps_NOFLAGS );
X }
+
+ /* reset the argument flags - if this arg was already given, some
+ ** of its flags may be set to indicate how it was given before.
+ ** we need to know how it was given now (but save the old ones
+ ** just in case the new one fails).
+ */
X flags = arg_flags(ad);
X if ( ARG_isGIVEN(ad) ) {
X BCLEAR( arg_flags(ad), ARGVALSEP );
diff -cNr ../patchlevel4/winsize.c ./winsize.c
*** ../patchlevel4/winsize.c Thu May 2 10:57:14 1991
--- ./winsize.c Thu May 2 14:37:13 1991
***************
*** 46,52 ****
X ** System dependent.
X ***^^**********************************************************************/
X
! #if ( defined(__STDC__) || defined(c_plusplus) || defined(__cplusplus) )
X # define GET_WINSIZE(fd,nrows,ncols) \
X void get_winsize( int fd, int *nrows, int *ncols )
X #else
--- 46,54 ----
X ** System dependent.
X ***^^**********************************************************************/
X
! #include <stdio.h>
!
! #ifdef __ANSI_C__
X # define GET_WINSIZE(fd,nrows,ncols) \
X void get_winsize( int fd, int *nrows, int *ncols )
X #else
***************
*** 55,63 ****
X int fd, *nrows, *ncols; /* nrows and ncols are passed by reference */
X #endif
X
- #include <stdio.h>
- #include <useful.h>
-
X #define DEFAULT_ROWS 24
X #define DEFAULT_COLS 80
X
--- 57,62 ----
***************
*** 67,72 ****
--- 66,72 ----
X #include <iodef.h>
X #include <ssdef.h>
X #include <descrip.h>
+ #include <useful.h>
X
X /* structure to contain terminal characteristics */
X typedef struct {
***************
*** 127,132 ****
--- 127,134 ----
X #if ( !defined(TIOCGWINSZ) && !defined(TIOCGSIZE) && !defined(WIOCGETD) )
X #include <sgtty.h>
X #endif
+
+ #include <useful.h>
X
X /*
X ** get_winsize() -- determine # of rows/columns that will fit on the screen.
diff -cNr ../patchlevel4/xparse.c ./xparse.c
*** ../patchlevel4/xparse.c Thu May 2 11:06:20 1991
--- ./xparse.c Thu May 2 14:37:17 1991
***************
*** 139,145 ****
X #endif
X
X
! #if vms
X # define USER_VARIABLE "symbol"
X #else
X # define USER_VARIABLE "environment variable"
--- 139,145 ----
X #endif
X
X
! #ifdef vms
X # define USER_VARIABLE "symbol"
X #else
X # define USER_VARIABLE "environment variable"
***************
*** 180,186 ****
X ** command-name (specified on the command-line) of the command that
X ** has most recently invoked a function in the parseargs library.
X ***^^**********************************************************************/
! CONST char *ProgName = (char *)NULL;
X
X EXTERN VOID syserr ARGS((const char *, ...));
X EXTERN VOID usrerr ARGS((const char *, ...));
--- 180,186 ----
X ** command-name (specified on the command-line) of the command that
X ** has most recently invoked a function in the parseargs library.
X ***^^**********************************************************************/
! CONST char *ProgName = CHARNULL;
X
X EXTERN VOID syserr ARGS((const char *, ...));
X EXTERN VOID usrerr ARGS((const char *, ...));
***************
*** 521,527 ****
X register ARGDESC *ad, *anchor;
X int ad_count = 0;
X BOOL old_style = FALSE;
! char *description = (char *)NULL, *purpose = (char *)NULL;
X
X if ( !argd ) return;
X
--- 521,527 ----
X register ARGDESC *ad, *anchor;
X int ad_count = 0;
X BOOL old_style = FALSE;
! char *description = CHARNULL, *purpose = CHARNULL;
X
X if ( !argd ) return;
X
***************
*** 1382,1388 ****
X BSET( cmd_state(cmd), ps_NOCMDENV );
X
X /* split line up into whitespace separated tokens */
! if ( !strsplit( &argv, env_val, (char *)NULL ) ) {
X free( argv );
X return;
X }
--- 1382,1388 ----
X BSET( cmd_state(cmd), ps_NOCMDENV );
X
X /* split line up into whitespace separated tokens */
! if ( !strsplit( &argv, env_val, CHARNULL ) ) {
X free( argv );
X return;
X }
***************
*** 1874,1880 ****
X BSET(cmd_flags(argd), pa_ARGV0);
X
X /* split line up into whitespace separated tokens */
! if ( !strsplit( &argv, str, (char *)NULL ) ) {
X free( argv );
X return rc;
X }
--- 1874,1880 ----
X BSET(cmd_flags(argd), pa_ARGV0);
X
X /* split line up into whitespace separated tokens */
! if ( !strsplit( &argv, str, CHARNULL ) ) {
X free( argv );
X return rc;
X }
***************
*** 1972,1977 ****
--- 1972,1997 ----
X
X if ( !CMD_isINIT(argd) ) init_args(argd);
X
+ /* We want the following scenario for the various calls to sparseargs():
+ ** assume there are N lines in the input file. Then there will be N
+ ** calls to sparseargs(). For all calls, we want pa_ARGV0 and pa_COPYF
+ ** to be ON. Then for the ALL but the very last call, we want pa_NOCHECK
+ ** to be off. For all but the very first call - we want pa_CONTINUE to
+ ** be turned ON. So we have the following table:
+ **
+ ** Parse || invocation of sparseargs
+ ** Flag || 0 | 1 | 2 .. N-1 | N
+ ** ============++========+===========+=================+===============
+ ** ARGV0 || on | on | on | on
+ ** ------------++--------+-----------+-----------------+---------------
+ ** COPYF || on | on | on | on
+ ** ------------++--------+-----------+-----------------+---------------
+ ** NOCHECK || on | on | on | OFF
+ ** ------------++--------+-----------+-----------------+---------------
+ ** CONTINUE || OFF | on | on | on
+ ** ============++========+===========+=================+===============
+ */
+
X /* save old flags & initialize parse flags for first call */
X saveflags = cmd_flags(argd);
X BSET(cmd_flags(argd), pa_ARGV0 | pa_NOCHECK | pa_COPYF);
***************
*** 1985,1997 ****
X }/*if*/
X
X /* trim leading and trailing whitespace and check for comments */
! (VOID) strtrim( text, (char *)NULL );
X if ( !text || !(*text) || *text == c_COMMENT ) continue;
X
X rc = sparseargs( text, argd );
X
X /* set up parseflags for next call */
! BSET(cmd_flags(argd), pa_CONTINUE);
X }/*while !EOF*/
X
X if ( !BTEST(saveflags, pa_NOCHECK) ) BCLEAR(cmd_flags(argd), pa_NOCHECK);
--- 2005,2019 ----
X }/*if*/
X
X /* trim leading and trailing whitespace and check for comments */
! (VOID) strtrim( text, CHARNULL );
X if ( !text || !(*text) || *text == c_COMMENT ) continue;
X
X rc = sparseargs( text, argd );
X
X /* set up parseflags for next call */
! if ( !BTEST(cmd_flags(argd), pa_CONTINUE) ) {
! BSET(cmd_flags(argd), pa_CONTINUE);
! }
X }/*while !EOF*/
X
X if ( !BTEST(saveflags, pa_NOCHECK) ) BCLEAR(cmd_flags(argd), pa_NOCHECK);
***************
*** 2079,2085 ****
X /* allocate a NULL terminated arg-vector */
X argv = (char **)malloc( (argc + 1) * sizeof(char *) );
X if ( !argv ) return pe_SYSTEM;
! argv[ argc ] = (char *)NULL;
X
X /* make 2nd pass to assign the elements of the vector */
X for ( ls = argls, i = 0 ; ls ; ls = L_NEXT(ls), i++ ) {
--- 2101,2107 ----
X /* allocate a NULL terminated arg-vector */
X argv = (char **)malloc( (argc + 1) * sizeof(char *) );
X if ( !argv ) return pe_SYSTEM;
! argv[ argc ] = CHARNULL;
X
X /* make 2nd pass to assign the elements of the vector */
X for ( ls = argls, i = 0 ; ls ; ls = L_NEXT(ls), i++ ) {
***************
*** 2183,2189 ****
X /* allocate a NULL terminated arg-vector */
X argv = (char **) malloc( (argc + 1) * sizeof(char *) );
X if ( !argv ) return pe_SYSTEM;
! argv[ argc ] = (char *)NULL;
X
X VA_START(ap, argc);
X for ( i = 0; i < argc && (arg = VA_ARG(ap, char *)) ; i++ ) {
--- 2205,2211 ----
X /* allocate a NULL terminated arg-vector */
X argv = (char **) malloc( (argc + 1) * sizeof(char *) );
X if ( !argv ) return pe_SYSTEM;
! argv[ argc ] = CHARNULL;
X
X VA_START(ap, argc);
X for ( i = 0; i < argc && (arg = VA_ARG(ap, char *)) ; i++ ) {
SHAR_EOF
echo 'File PATCH05 is complete' &&
chmod 0664 PATCH05 ||
echo 'restore of PATCH05 failed'
Wc_c="`wc -c < 'PATCH05'`"
test 268263 -eq "$Wc_c" ||
echo 'PATCH05: original size 268263, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo You have unpacked the last part
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