[net.sources] Body - That which goes between head and tail

fouts@AMES-NAS.ARPA (Marty) (08/18/85)

     I was reading a copy of "The Unix Programming Environment" and
discovered the remark about never feeling the need to write head(1) because
it was covered by using sed(1).

     Well, this got me thinking about head and tail and replacing both. . .

     So, without further ado, here is  a version of body(1) which I wrote
one rainy Saturday afternoon.  It seems to work under both 4.2BSD and SVR2.

     I have included Spencer Thompson's version of scanargs, since it is
used by body, so the posting isn't a total loss.

     Problems, or suggestions to fouts@ames-nas, Flames to /dev/null.

Marty
fouts@ames-nas
...!ames!amelia!fouts

------ Cut, rip, or otherwise abuse here -----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	body.1
#	body.c
#	body.h
#	cout.c
#	lout.c
#	pfile.c
#	scanargs.3
#	scanargs.c
#	wout.c
# This archive created: Sat Aug 17 18:09:28 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(407 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Makefile for body
X#
XSRCS	= scanargs.c body.c pfile.c lout.c wout.c cout.c
XOBJS	= scanargs.o body.o pfile.o lout.o wout.o cout.o
XEXES	= body
XLIBS	=
XCFLAGS	= -g
X
Xall:		body
X
Xbody:		$(OBJS)
X		cc $(CFLAGS) -o body $(OBJS) $(LIBS)
X
Xbody.o:		body.h body.c
X
Xpfile.o:	body.h pfile.c
X
Xlout.o:		body.h lout.c
X
Xcout.o:		body.h cout.c
X
Xwout.o:		body.h wout.c
X
Xclean:
X		rm $(OBJS) $(EXES)
X
Xlint:
X		lint -lc $(SRCS)
X
SHAR_EOF
if test 407 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 407 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'body.1'" '(1321 characters)'
if test -f 'body.1'
then
	echo shar: will not over-write existing file "'body.1'"
else
sed 's/^X//' << \SHAR_EOF > 'body.1'
X.TH BODY NPSN "17 August 1985"
X.UC 4
X.SH NAME
Xbody \- display the body of a file
X.SH SYNOPSIS
X.B body
X[
X.B \-s n
X] [
X.B \-n n
X] [
X.B \-e n
X] [
X.B \-d n
X] [
X.B \-{lwc}
X]
Xfile ...
X.br
X.SH DESCRIPTION
X.I Body
Xreads each
X.I file
Xin sequence and displays it on the standard output.  Thus
X.PP
X.ti+15n
Xbody file
X.PP
Xdisplays the file on the standard output, and
X.PP
X.ti+15n
Xbody file1 file2 >file3
X.PP
Xconcatenates the first two files and places the result on the third.
X.PP
XIf no input file is given
X.I body
Xreads from the standard input file.
X.PP
XThe
X.B \-f
Xoption specifies the
X.I unit
Xto start output at. If no starting unit is specified, 1 is used.
X.PP
XThe
X.B \-e
Xoption specifies the
X.I unit
Xto end output at. The default is to output until end of file.
X.PP
XThe
X.B \-n
Xoption specifies the number of
X.I units
Xto output. The default is 10.
X.PP
XThe
X.B \-{lwc}
Xoption specifies the
X.I unit
Xto use for
X.B \-e, \-s,
Xand
X.B \-f.
XThe
X.I units
Xare
X.I line,
X.I word,
Xor
X.I character.
X.SH "EXAMPLES"
XTo copy lines 5 through 10 of the file myfile to the file junk, use
X.ti+15n
Xbody -s 5 -e 10 myfile > junk
X.PP
Xor
X.ti+15n
Xbody -s 5 -n 5 myfile > junk
X.SH "SEE ALSO"
Xcp(1), more(1), pr(1), tail(1), head(1)
X.SH BUGS
XBound to be plenty.
X.PP
XThere is an arbitray limit of 1024 characters per line.
X.SH DIAGNOSTICS
XAre Self-explanatory.
SHAR_EOF
if test 1321 -ne "`wc -c < 'body.1'`"
then
	echo shar: error transmitting "'body.1'" '(should have been 1321 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'body.c'" '(3080 characters)'
if test -f 'body.c'
then
	echo shar: will not over-write existing file "'body.c'"
else
sed 's/^X//' << \SHAR_EOF > 'body.c'
X/*
X * body [-s number] [-e number] [-n number] [-{lwc}] [-d n] file . . .
X *
X * -s number		starting unit for printout default = 1
X * -e number		ending unit for printout default = end of file
X * -n number		number of units to print default = 10 units
X * -l			units = line (\n)
X * -w			units = word (nonwhite space)
X * -c			units = characters
X *
X * Can specify only one of -e or -n.
X * If file is not specified, standard input is used.
X * Author: Martin Fouts (fouts@ames-nas)
X */
X
X#include <stdio.h>
X#include "body.h"
X
Xextern int errno;
Xint debug;
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    int sflag,		/* -s present (start) */
X        eflag,		/* -e present (end) */
X	nflag,		/* -n present (number) */
X	dflag,		/* -d present (debug) */
X	lwcflag,	/* -l, -w, or -c present (units) */
X	start,		/* Place to start output */
X	end,		/* Place to end output */
X	number,		/* number of units to output */
X	nfiles;		/* Number of file entries */
X    int i;		/* Good ole' I */
X    char **files;	/* Array of file entries */
X
X/*
X * Set the defaults and scan the argument list
X * Then check for errors not noticed by scanargs:
X *   -e and -n both specified
X *   start < 0
X *   end < start
X */
X    start = DE_FIRST;
X    number = DE_NUMB;
X    end = DE_LAST;
X
X    if (scanargs(argc,argv,
X        "% s%-start!n e%-end!n n%-number!n lwc%- d%-debug!n filename%*s",
X    		&sflag, &start, &eflag, &end, &nflag, &number,
X		&lwcflag, &dflag, &debug, &nfiles, &files) == 0) {
X        exit(1);
X	/* NOT REACHED */
X		}
X
X    IFDEBUG(D_ARGS) {
X    (void) fprintf(stderr,"sflag = %d, start = %d\n", sflag, start);
X    (void) fprintf(stderr,"eflag = %d, end = %d\n", eflag, end);
X    (void) fprintf(stderr,"nflag = %d, number = %d\n", nflag, number);
X    (void) fprintf(stderr,"dflag = %d, debug = %d\n", dflag, debug);
X    (void) fprintf(stderr,"lwcflag = %d\n",lwcflag);
X    (void) fprintf(stderr,"nfiles = %d\n", nfiles);
X    for (i = 0; i < nfiles; i++)
X        (void) fprintf(stderr,"File(%d) = %s\n", i, files[i]);
X    }
X
X    if (eflag & nflag) {
X	(void) fprintf(stderr,"Only one of -e or -n.\n");
X	exit(1);
X	/* NOT REACHED */
X    }
X
X    if ((eflag != 1) && (nflag == 1))	/* If -n and -s, calculate end */
X           end = start + number - 1;
X
X    if (start < 1) {
X	(void) fprintf(stderr,"Starting point outside of file.\n");
X	exit(1);
X	/* NOT REACHED */
X    }
X
X    if ((end != DE_LAST) && (start > end)) {
X	(void) fprintf(stderr,"Start after end.\n");
X	exit(1);
X	/* NOT REACHED */
X    }
X
X    if (end == DE_LAST)
X        number = DE_LAST;
X    else
X        number = end - start + 1;
X
X/*
X * Print each of the files specified, using pfile
X */
X    if (nfiles == 0) {		/* no files, use stdin */
X        IFDEBUG(D_LIST)
X	    (void) fprintf(stderr,"%s %d %d %d\n", "stdin",
X	            start, number, lwcflag);
X	(void) pfile(DE_FILE, start, number, lwcflag);
X    } else {
X        for (i = 0; i < nfiles; i++) { /* Once for each file */
X	    IFDEBUG(D_LIST)
X                (void) fprintf(stderr,"%s %d %d %d\n",
X		       files[i], start, number, lwcflag);
X	    pfile(files[i], start, number, lwcflag);
X	}
X    }
X}
SHAR_EOF
if test 3080 -ne "`wc -c < 'body.c'`"
then
	echo shar: error transmitting "'body.c'" '(should have been 3080 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'body.h'" '(371 characters)'
if test -f 'body.h'
then
	echo shar: will not over-write existing file "'body.h'"
else
sed 's/^X//' << \SHAR_EOF > 'body.h'
X/*
X * Global definitions for body
X */
X
X#define IFDEBUG(x) if ((debug&(x)) == x)
X#define D_ARGS	0x01
X#define D_LIST  0x02
X#define D_PFILE 0x04
X
X#define L_FLAG  0x04
X#define W_FLAG  0x02
X#define C_FLAG  0x01
X
X#define DE_FIRST  1
X#define DE_LAST  -1
X#define DE_NUMB  10
X#define DE_FILE  (char *) 0
X
X#define LINMAX 1024
X
X#define IN_WHIT 0
X#define IN_WORD 1
X#define IN_FIRS 2
SHAR_EOF
if test 371 -ne "`wc -c < 'body.h'`"
then
	echo shar: error transmitting "'body.h'" '(should have been 371 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'cout.c'" '(492 characters)'
if test -f 'cout.c'
then
	echo shar: will not over-write existing file "'cout.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cout.c'
X#include <stdio.h>
X#include "body.h"
X
Xcskip(start,fd)
Xint start;
XFILE * fd;
X{
X    return (fseek(fd,(long) (start-1), 0) == 0 ? 1 : 0);
X}
X
Xcprint(number,fd)
Xint number;
XFILE * fd;
X{
X    int i;
X    int c;
X    if (number == DE_LAST) {	/* Print to end of file */
X	while ((c = getc(fd)) != EOF)
X	    (void) fputc(c,stdout);
X    } else {
X    for (i = 0; i < number; i++) { /* Print n characters */
X        if ((c = getc(fd)) == EOF) return(1);
X	(void) fputc(c,stdout);
X    }
X    }
X    return(1);
X}
SHAR_EOF
if test 492 -ne "`wc -c < 'cout.c'`"
then
	echo shar: error transmitting "'cout.c'" '(should have been 492 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'lout.c'" '(628 characters)'
if test -f 'lout.c'
then
	echo shar: will not over-write existing file "'lout.c'"
else
sed 's/^X//' << \SHAR_EOF > 'lout.c'
X#include <stdio.h>
X#include "body.h"
X
Xchar *fgets();
X
Xlskip(start,fd)
Xint start;
XFILE * fd;
X{
X    char s[LINMAX];
X    int i;
X    (void) fseek(fd, 0L, 0);
X    i = 0;
X    while (i < start - 1) {
X        if(fgets(s,LINMAX,fd) == NULL) return(0);
X	i++;
X    }
X    return(1);
X}
X
Xlprint(number,fd)
Xint number;
XFILE * fd;
X{
X    int i;
X    char s[LINMAX];
X    if (number == DE_LAST) {	/* Print to end of file */
X        while (fgets(s,LINMAX,fd) != NULL)
X	    (void) fputs(s,stdout);
X    } else {
X	for (i = 0; i < number; i++) { /* Print n lines */
X	    if (fgets(s,LINMAX,fd) == NULL) return(1);
X	    (void) fputs(s,stdout);
X	}
X    }
X}
SHAR_EOF
if test 628 -ne "`wc -c < 'lout.c'`"
then
	echo shar: error transmitting "'lout.c'" '(should have been 628 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'pfile.c'" '(998 characters)'
if test -f 'pfile.c'
then
	echo shar: will not over-write existing file "'pfile.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pfile.c'
X#include <stdio.h>
X#include "body.h"
X
Xextern int debug;
XFILE *fopen();
X
Xpfile(fname,start,number,lwcflag)
Xchar * fname;
Xint start;
Xint number;
Xint lwcflag;
X{
X    FILE *fd;
X    IFDEBUG(D_PFILE)
X        (void) fprintf(stderr,
X	"pfile: fname = %s, start = %d, number = %d, lwcflag = %d\n",
X	fname == DE_FILE ? "stdin" : fname, start, number, lwcflag);
X    /*
X     * open the file or set the descriptor to standard input
X     */
X    if (fname == DE_FILE) {
X	fd = stdin;
X    } else {
X	if ((fd = fopen(fname,"r")) == NULL)
X	   return(-1);
X    }
X    switch (lwcflag) {
X	case L_FLAG:
X	    if (lskip(start,fd) == 1)
X	        (void) lprint(number,fd);
X	    break;
X	case W_FLAG:
X	    if (wskip(start,fd) == 1)
X	        (void) wprint(number,fd);
X	    break;
X        case C_FLAG:
X	    if (cskip(start,fd) == 1)
X	        (void) cprint(number,fd);
X	    break;
X	default:
X	    if (lskip(start,fd) == 1)
X	    	(void) lprint(number,fd);
X	    break;
X    }
X    if (fname != DE_FILE) (void) fclose(fd);
X    return(0);
X}
SHAR_EOF
if test 998 -ne "`wc -c < 'pfile.c'`"
then
	echo shar: error transmitting "'pfile.c'" '(should have been 998 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scanargs.3'" '(12928 characters)'
if test -f 'scanargs.3'
then
	echo shar: will not over-write existing file "'scanargs.3'"
else
sed 's/^X//' << \SHAR_EOF > 'scanargs.3'
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
XNAME
X     scanargs, qscanargs - formatted conversion from command
X     argument list
X
XSYNOPSIS
X     #include <stdio.h>
X
X     scanargs(argc, argv, format [, pointer]...  )
X     int argc;
X     char *argv[];
X     char *format;
X
XDESCRIPTION
X     Scanargs reads argc arguments from an argument list pointed
X     to by argv. It converts the argument list according to the
X     format string, and stores the results of the conversions in
X     its parameters.  Qscanargs is a smaller and less powerful
X     version which does not understand floating point.
X
X     Scanargs expects as its parameters an argument count argc, a
X     pointer to an argument list argv (see exec(2)), a control
X     string format, described below, and a set of pointer argu-
X     ments indicating where the converted output should be
X     stored.
X
X     The control string contains specifications, which are used
X     to direct interpretation of argument sequences.  It contains
X     the necessary information to describe an acceptable syntax
X     for the argument list, and the expected meaning of each
X     argument.
X
X     If the scanning fails it will print a cryptic message tel-
X     ling why it failed, and generate a usage message from the
X     control string.
X
X     The control string is composed of two parts:
X
X     Name:   The first characters in the string are assumed to be
X     the calling name of the program being executed. This is used
X     for generation of usage messages, but is otherwise ignored.
X     If this field is a % sign, it is replaced with the contents
X     of argv[0] in the message.
X
X     Conversions:   Following the name, an optional list of
X     conversion specifications is given, with separating spaces.
X     The structure of a conversion specification:
X
X          label_key_conversion
X
X     consists of a label which is a string of non-space charac-
X     ters describing the acceptable argument, a key which may be
X     either of
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          1
X
X
X
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
X     %   The argument is optional. Its absence is ignored.
X
X     !   A required argument. If absent, an error return ensues.
X
X     and a conversion character which indicates the interpreta-
X     tion of the argument; the corresponding pointer parameter
X     must be of a restricted type.
X
X     The following conversion characters are supported:
X
X     d D a decimal integer is expected; the corresponding parame-
X         ter should be an int or a long (if D is specified)
X         pointer.
X
X     o O an octal integer is expected; the corresponding parame-
X         ter should be an int or a long pointer.
X
X     x X a hexadecimal integer is expected; the corresponding
X         parameter should be an int or a long pointer.
X
X     n N an integer numeric conversion using C language syntax.
X         Numbers beginning 0x are hexadecimal, numbers beginning
X         0 are octal, and other numbers are decimal.  Negative
X         hex numbers must have the minus sign following the 0x,
X         i.e. negative 0xa would be given as 0x-a.  The
X         corresponding pointer should point to an int or a long.
X
X     f F a floating point number is expected; the corresponding
X         parameter should be a pointer to a float or a double.
X         Not available in qscanargs.
X
X     x X d D o O f F
X         all numeric types supported by scanf(3S) are legal in
X         scanargs; qscanargs supports all but f and F formats,
X         and avoids including the large size of the scanf rou-
X         tine.
X
X     s   a character string is expected; the corresponding param-
X         eter should be the address of a pointer to char.
X
X     -   a single character flag is expected; the corresponding
X         parameter should be an int pointer.  The occurrence of a
X         - followed by the character specified in the label will
X         cause the setting of the least significant bit of the
X         integer pointed to by the corresponding parameter.  The
X         label may consist of up to sixteen (32 on a VAX) option
X         characters, in which case one of the bits of the integer
X         is independantly set to reflect which one of the flags
X         was present. (The right most character corresponds to
X         the LSB of the integer)  Only one option may be chosen
X         from each conversion specification.  The bits which are
X         not set will remain in their previous state.  For
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          2
X
X
X
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
X         example, a specification of abc%- would match one of -a
X         -b or -c in the argument list. -c would cause the
X         corresponding variable to be set to 1, -b to 2, and -a
X         to 4.  (Actually, these bits would be ored in, but
X         assuming an intial value of 0, this is true).
X
X         The - may be followed immediately by more
X         label_key_conversion specifications.  These should not
X         be separated by blanks and should not contain any -
X         specifications.  They will be processed only if the flag
X         argument is scanned.  This allows optional specification
X         of parameters corresponding to a flag (e.g.  -f file ).
X         Corresponding arguments on the command line must appear
X         between the flag which introduces them and the next flag
X         in the command line.
X
X     $   This may appear only as the last specifier in the format
X         string, and is used to "eat up" the rest of the command
X         arguments.  The corresponding function argument is an
X         int pointer.  An index into argv to the dividing point
X         between the arguments which have been used, and those
X         which have not is returned.  This index points to the
X         first unused command argument.  If there is no such
X         dividing point, an error will be generated.
X
X     A string or numeric conversion character may be preceded by
X     a * or a , to indicate that a list of such arguments is
X     expected.  If , is used, then the AT&T proposed argument
X     standard is followed, and a single string is expected, with
X     the individual list elements separated by commas or spaces.
X     Two commas in a row will produce a null entry (0 if numeric,
X     zero-length string if string conversion), but multiple
X     spaces, and spaces following a comma, are taken as a single
X     separator.  If * is specified, then multiple arguments are
X     parsed to produce the list.  A format specifier with a * or
X     a , takes two arguments.  The first is an int pointer, the
X     number of items in the list is returned here.  The second is
X     a pointer to pointer to the correct data type for the format
X     specifier.  A pointer to the list of arguments is returned
X     here.
X
X     The scanner will process the control string from left to
X     right, and where there are multiple conversions of the same
X     type, they will be assigned one to one with their order of
X     occurrence in the argument list.  Where the order of the
X     arguments is not ambiguous in the control string, they may
X     occur in any order in the argument list. (ie. A decimal
X     number will not be confused with a flag, but may be confused
X     with an octal number or another decimal number. So if an
X     octal and a decimal number are to be arguments, their order
X     will determine their conversion, while a decimal number and
X     a flag as arguments may occur in any order and still be
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          3
X
X
X
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
X     converted correctly.)
X
X     An argument list that does not match the requirements of the
X     control string will cause the printing of a short message
X     telling why, and a message telling what the correct usage
X     is.  This usage is gleaned from the control string, and the
X     labels are used directly.  The labels should be both terse
X     and descriptive!  Spaces, tabs, and newlines in the format
X     string will be reproduced in the usage message, and can be
X     used for effective prettyprinting.  A single tab (following
X     a newline) will indent the line directly under the command
X     name in the usage message.
X
X     The scanargs function returns 1 when the argument list
X     matched the requirements of the control string, and returns
X     0 if there was a failure.  Parameters for any conversions
X     not matched are left untouched.
X     For example, the call
X
X          int i; double x; char *name;
X          scanargs(argc, argv, "program decimal%d floating%F
X          file%s"
X               , &i, &x, &name );
X
X     in a C program executed by the shell command
X
X          % program 10 3.5397 inputfile
X
X     will assign to i the value 10, x the value 3.5397, and name
X     will point to the string "inputfile".
X
X     If the program was executed by the shell command
X
X          % program  3.4 .7 inputfile
X
X     the following would be printed on the standard error:
X
X          extra arguments not processed
X          usage : program [decimal] [floating] [file]
X
X     because 3.4 matches the type of 'floating' and inputfile
X     matches the type of 'file', leaving .7 unmatched (it is con-
X     sidered a string by scanargs, to be considered a number, it
X     must begin with a digit).
X
X     Finally, executing the command
X          % program 10
X     would assign 10 to i, leaving x and name unaffected.
X
X     This call could be used for the diff(1) command
X
X
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          4
X
X
X
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
X          int blanks; int flags; char *file1; char *file2;
X          scanargs(argc, argv, "diff b%- efh%- file1!s file2!s"
X               , &blanks, &flags, &file1, &file2 );
X
X     and would only allow one of either -e -f or -h to be chosen
X     optionally, with -b as an independent option.  File1 and
X     file2 are both required.  The usage message for this version
X     of diff would be
X
X          usage : diff [-b] -{efh} file1 file2
X
X     This call could be used for a simplified version of the
X     sed(1) command
X
X          int efile; int noprint; char *script; char *file1; char
X          *file2;
X          scanargs(argc, argv, "sed n%- script%s f%-editfile!s
X          file%s"
X               , &noprint, &script, &efile, &file1, &file2 );
X
X     If the -f option is specified, then a file name must be
X     given as the next string argument.  The usage message for
X     this version of sed would be
X
X          usage : sed [-n] [script] [-f editfile] file
X
X
X     Further notes on putting together a format string:
X
X     It is still possible for conditional arguments to be con-
X     fused with arguments which stand alone.  For this reason, it
X     is recommended that all flags (and associated conditional
X     arguments) be specified first in the scanargs format string.
X     This ordering is not necessary for the command line argu-
X     ments, however.  The only case which could still cause con-
X     fusion if these rules are followed is illustrated below:
X          format string: "prog d%-num%d othernum%d"
X          command line:  prog -d 9
X     It is unclear whether the number 9 should be associated with
X     the num parameter or the othernum parameter. Scanargs
X     assigns it to the num parameter.  To force it to be associ-
X     ated with othernum the command could be invoked as either
X                    prog 9 -d
X          or        prog -d -- 9
X     The -- in the second example is interpreted as a flag,
X     thereby terminating the scan for arguments introduced by the
X     -d.  According to the proposed standard, an argument of --
X     is to be interpreted as terminating the optional arguments
X     on a flag.
X
X     Note that if the format string in the above example were
X                    "prog othernum%d d%-num%d"
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          5
X
X
X
X
X
X
XSCANARGS(3)         UNIX Programmer's Manual          SCANARGS(3)
X
X
X
X     it would be impossible to assign a value to num without also
X     assigning a value to othernum.
X
X
XSEE ALSO
X     exec(2), scanf(3S)
X
XDIAGNOSTICS
X     Returns 0 on error, 1 on success.
X
XAUTHOR
X     Gary Newman - Ampex Corporation
X     Spencer W. Thomas - University of Utah
X
XBUGS
X     By its nature a call to scanargs defines a syntax which may
X     be ambiguous, and although the results may be surprising,
X     they are quite predictable.  The heuristic used to tell
X     string arguments from numeric arguments is just that.  In
X     fact, that you can't give a number as a string argument is
X     sort of bogus.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XPrinted 10/6/84            AMPEX CORP.                          6
X
X
X
SHAR_EOF
if test 12928 -ne "`wc -c < 'scanargs.3'`"
then
	echo shar: error transmitting "'scanargs.3'" '(should have been 12928 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scanargs.c'" '(19707 characters)'
if test -f 'scanargs.c'
then
	echo shar: will not over-write existing file "'scanargs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'scanargs.c'
X/* 
X * $Header: scanargs.c,v 1.3 83/05/22 02:21:32 thomas Exp $
X * 		Version 7 compatible
X * 	Argument scanner, scans argv style argument list.
X * 
X * 	Some stuff is a kludge because sscanf screws up
X * 
X * 	Gary Newman - 10/4/1979 - Ampex Corp. 
X * 
X * 	Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
X * 	add args introduced by 	a flag, add qscanargs call,
X * 	allow empty flags.
X * 
X * 	Compiling with QUICK defined generates 'qscanargs' ==
X * 	scanargs w/o floating point support; avoids huge size
X * 	of scanf.
X * 
X * 	If you make improvements we'd like to get them too.
X * 	Jay Lepreau	lepreau@utah-20, decvax!harpo!utah-cs!lepreau
X * 	Spencer Thomas	thomas@utah-20, decvax!harpo!utah-cs!thomas 
X * 
X *	(I know the code is ugly, but it just grew, you see ...)
X * 
X * Modified by:	Spencer W. Thomas
X * 	Date:	Feb 25 1983
X * 1. Fixed scanning of optional args.  Now args introduced by a flag
X *    must follow the flag which introduces them and precede any other
X *    flag argument.  It is still possible for a flag introduced
X *    argument to be mistaken for a "bare" argument which occurs
X *    earlier in the format string.  This implies that flags may not
X *    be conditional upon other flags, and a message will be generated
X *    if this is attempted.
X * 
X * 2. Usage message can be formatted by inserting newlines, tabs and
X *    spaces into the format string.  This is especially useful for
X *    long argument lists.
X * 
X * 3. Added n/N types for "numeric" args.  These args are scanned
X *    using the C language conventions - a number starting 0x is
X *    hexadecimal, a number starting with 0 is octal, otherwise it is
X *    decimal.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <varargs.h>
X
Xtypedef char bool;
X/* 
X * An explicit assumption is made in this code that all pointers look
X * alike, except possible char * pointers.
X */
Xtypedef int *ptr;
X
X#define YES 1
X#define NO 0
X#define ERROR(msg)  {fprintf(stderr, "msg\n"); goto error; }
X
X/* 
X * Storage allocation macros
X */
X#define NEW( type, cnt )	(type *) malloc( (cnt) * sizeof( type ) )
X#define RENEW( type, ptr, cnt )	(type *) realloc( ptr, (cnt) * sizeof( type ) )
X
Xstatic char * prformat();
Xstatic bool isnum();
X
X/* 
X * Argument list is (argc, argv, format, ... )
X */
X#ifndef	QUICK
Xscanargs ( va_alist )
X#else
Xqscanargs ( va_alist )
X#endif
Xva_dcl
X{
X    int     argc;			/* Actual arguments */
X    char  **argv;
X    char   *format;
X    va_list argl;
X
X    register    check;			/* check counter to be sure all argvs
X					   are processed */
X    register char  *cp;
X    register    cnt;
X    int	    optarg = 0;			/* where optional args start */
X    int	    nopt;
X    char    tmpflg,			/* temp flag */
X	    typchr;			/* type char from format string */
X    char    c;
X    bool  * arg_used;			/* array of flags */
X    char  * malloc();
X    ptr	    aptr;			/* pointer to return loc */
X
X    bool    required;
X    int	    excnt;			/* which flag is set */
X    bool    exflag;			/* when set, one of a set of exclusive
X					   flags is set */
X
X    bool    list_of;			/* set if parsing off a list of args */
X    bool    comma_list;			/* set if AT&T style multiple args */
X    int	  * cnt_arg;			/* where to stuff list count */
X    int	    list_cnt;			/* how many in list */
X    /* These are used to build return lists */
X    char ** strlist;
X    int   * intlist;
X    long  * longlist;
X    float * fltlist;
X    double *dbllist;
X
X    char   *ncp;			/* remember cp during flag scanning */
X#ifndef	QUICK
X    char   *cntrl;			/* control string for scanf's */
X    char    junk[2];			/* junk buffer for scanf's */
X
X    cntrl = "% %1s";			/* control string initialization for
X					   scanf's */
X#endif
X
X    va_start( argl );
X    argc = va_arg( argl, int );
X    argv = va_arg( argl, char ** );
X    format = va_arg( argl, char * );
X
X    arg_used = NEW( bool, argc );
X    if (arg_used == NULL)
X    {
X	fprintf(stderr, "malloc failed in scanargs, exiting\n");
X	exit(-1);
X    }
X    else
X    {
X	for (cnt=0; cnt<argc; cnt++)
X	    arg_used[cnt] = NO;
X    }
X
X    check = 0;
X    cp = format;
X    /* 
X     * Skip program name
X     */
X    while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
X	cp++;
X
X    while (*cp)
X    {
X	required = NO;			/* reset per-arg flags */
X	list_of = NO;
X	comma_list = NO;
X	list_cnt = 0;
X	switch (*(cp++))
X	{
X	    default: 			/* all other chars */
X		break;
X	    case ' ':			/* separators */
X	    case '\t':
X	    case '\n':
X		optarg = 0;		/* end of optional arg string */
X		break;
X
X	    case '!': 			/* required argument */
X		required = YES;
X	    case '%': 			/* not required argument */
Xreswitch:				/* after finding '*' or ',' */
X		switch (typchr = *(cp++))
X		{
X		    case ',':		/* argument is AT&T list of things */
X			comma_list = YES;
X		    case '*':		/* argument is list of things */
X			list_of = YES;
X			list_cnt = 0;	/* none yet */
X			cnt_arg = va_arg( argl, int *);	/* item count * here */
X			goto reswitch;	/* try again */
X
X		    case '$':		/* "rest" of argument list */
X			while ( argc > 1 && !arg_used[argc-1] )
X			    argc--;	/* find last used argument */
X			*va_arg( argl, int * ) = argc;
X			break;
X
X		    case '-': 		/* argument is flag */
X			if (optarg > 0)
X			    ERROR(Format error: flag conditional on flag not allowed);
X
X		    /* go back to label */
X			ncp = cp-1;	/* remember */
X			cp -= 3;
X			for (excnt = exflag = 0
X				; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
X				(--cp, excnt++))
X			{
X			    for (cnt = optarg+1; cnt < argc; cnt++)
X			    {
X			    /* flags all start with - */
X				if (*argv[cnt] == '-' && !arg_used[cnt] &&
X					!isdigit(argv[cnt][1]))
X				    if (*(argv[cnt] + 1) == *cp)
X				    {
X					if (*(argv[cnt] + 2) != 0)
X					    ERROR (extra flags ignored);
X					if (exflag)
X					    ERROR (more than one exclusive flag chosen);
X					exflag++;
X					required = NO;
X					check += cnt;
X					arg_used[cnt] = 1;
X					nopt = cnt;
X					*va_arg( argl, int *) |= (1 << excnt);
X					break;
X				    }
X			    }
X			}
X			if (required)
X			    ERROR (flag argument missing);
X			cp = ncp;
X			/* 
X			 * If none of these flags were found, skip any
X			 * optional arguments (in the varargs list, too).
X			 */
X			if (!exflag)
X			{
X			    va_arg( argl, int * );	/* skip the arg, too */
X			    while (*++cp && ! isspace(*cp))
X				if (*cp == '!' || *cp == '%')
X				{
X				    if ( *++cp == '*' || *cp == ',' )
X				    {
X					cp++;
X					va_arg( argl, int * );
X				    }
X				    /* 
X				     * Assume that char * might be a
X				     * different size, but that all
X				     * other pointers are same size.
X				     */
X				    if ( *cp == 's' )
X					va_arg( argl, char * );
X				    else
X					va_arg( argl, ptr );
X				}
X			}
X			else
X			{
X			    optarg = nopt;
X			    cp++;	/* skip over - */
X			}
X
X			break;
X
X		    case 's': 		/* char string */
X		    case 'd': 		/* decimal # */
X		    case 'o': 		/* octal # */
X		    case 'x': 		/* hexadecimal # */
X		    case 'n':		/* "number" in C syntax */
X#ifndef	QUICK
X		    case 'f': 		/* floating # */
X#endif
X		    case 'D': 		/* long decimal # */
X		    case 'O': 		/* long octal # */
X		    case 'X': 		/* long hexadecimal # */
X		    case 'N':		/* long number in C syntax */
X#ifndef	QUICK
X		    case 'F': 		/* double precision floating # */
X#endif
X			for (cnt = optarg+1; cnt < argc; cnt++)
X			{
X			    ncp = argv[cnt];
X
X			    if ( isnum( ncp, typchr, comma_list ) )
X			    {
X				if ( typchr == 's' )	/* string? */
X				    continue;	/* don't want numbers, then */
X			    }
X			    else if ( *ncp == '-' )
X				if ( optarg > 0 ) /* end optional args? */
X				{
X				    /* Eat the arg, too, if necessary */
X				    if ( list_cnt == 0 )
X					if ( typchr == 's' )
X					    va_arg( argl, char * );
X					else
X					    va_arg( argl, ptr );
X				    break;
X				}
X				else
X				    continue;
X			    else if ( typchr != 's' )
X				continue;	/* not number, keep looking */
X			    
X			    /* 
X			     * Otherwise usable argument may already
X			     * be used.  (Must check this after
X			     * checking for flag, though.)
X			     */
X			    if (arg_used[cnt]) continue;
X
X			    /* 
X			     * If it's a comma-and-or-space-separated
X			     * list then count how many, and separate
X			     * the list into an array of strings.
X			     */
X			    if ( comma_list )
X			    {
X				register char * s;
X				int pass;
X
X				/* 
X				 * On pass 0, just count them.  On
X				 * pass 1, null terminate each string 
X				 */
X				for ( pass = 0; pass <= 1; pass++ )
X				{
X				    for ( s = ncp; *s != '\0'; )
X				    {
X					if ( pass )
X					    strlist[list_cnt] = s;
X					while ( (c = *s) != '\0' && c != ' ' &&
X						c != '\t' && c != ',' )
X					    s++;
X					if ( pass )
X					    *s = '\0';
X
X					list_cnt++;	/* count separators */
X					/* 
X					 * Two commas in a row give a null
X					 * string, but two spaces
X					 * don't.  Also skip spaces
X					 * after a comma.
X					 */
X					if ( c != '\0' )
X					    while ( *++s == ' ' || *s == '\t' )
X						;
X				    }
X				    if ( pass == 0 )
X				    {
X					strlist = NEW( char *, list_cnt );
X					list_cnt = 0;
X				    }
X				}
X			    }
X			    else if ( list_of )
X				list_cnt++;   /* getting them one at a time */
X			    /* 
X			     * If it's either type of list, then alloc
X			     * storage space for the returned values
X			     * (except that comma-separated string
X			     * lists already are done).
X			     */
X			    if ( list_of )
X			    {
X				if ( list_cnt == 1 || comma_list )
X				    switch( typchr )
X				    {
X					case 's':
X					    if ( !comma_list )
X						strlist = NEW( char *, 1 );
X					    aptr = (ptr) &strlist[0];
X					    break;
X					case 'n':
X					case 'd':
X					case 'o':
X					case 'x':
X					    intlist = NEW( int, list_cnt );
X					    aptr = (ptr) &intlist[0];
X					    break;
X					case 'N':
X					case 'D':
X					case 'O':
X					case 'X':
X					    longlist = NEW( long, list_cnt );
X					    aptr = (ptr) &longlist[0];
X					    break;
X					case 'f':
X					    fltlist = NEW( float, list_cnt );
X					    aptr = (ptr) &fltlist[0];
X					    break;
X					case 'F':
X					    dbllist = NEW( double, list_cnt );
X					    aptr = (ptr) &dbllist[0];
X					    break;
X				    }
X				else
X				    switch( typchr )
X				    {
X					case 's':
X					    strlist = RENEW( char *, strlist,
X							     list_cnt );
X					    aptr = (ptr) &strlist[list_cnt-1];
X					    break;
X					case 'n':
X					case 'd':
X					case 'o':
X					case 'x':
X					    intlist = RENEW( int, intlist,
X							     list_cnt );
X					    aptr = (ptr) &intlist[list_cnt-1];
X					    break;
X					case 'N':
X					case 'D':
X					case 'O':
X					case 'X':
X					    longlist = RENEW( long, longlist,
X							      list_cnt );
X					    aptr = (ptr) &longlist[list_cnt-1];
X					    break;
X					case 'f':
X					    fltlist = RENEW( float, fltlist,
X							     list_cnt );
X					    aptr = (ptr) &fltlist[list_cnt-1];
X					    break;
X					case 'F':
X					    dbllist = RENEW( double, dbllist,
X							     list_cnt );
X					    aptr = (ptr) &dbllist[list_cnt-1];
X					    break;
X				    }
X			    }
X			    else
X				aptr = va_arg( argl, ptr );
X
X			    if ( typchr == 's' )
X			    {
X				if ( ! comma_list )
X				    *(char **)aptr = ncp;
X			    }
X			    else
X			    {
X				nopt = 0;
X				do {
X				    /* 
X				     * Need to update aptr if parsing
X				     * a comma list
X				     */
X				    if ( comma_list && nopt > 0 )
X				    {
X					ncp = strlist[nopt];
X					switch( typchr )
X					{
X					    case 'n':
X					    case 'd':
X					    case 'o':
X					    case 'x':
X						aptr = (ptr) &intlist[nopt];
X						break;
X					    case 'N':
X					    case 'D':
X					    case 'O':
X					    case 'X':
X						aptr = (ptr) &longlist[nopt];
X						break;
X					    case 'f':
X						aptr = (ptr) &fltlist[nopt];
X						break;
X					    case 'F':
X						aptr = (ptr) &dbllist[nopt];
X						break;
X					}
X				    }
X				    /* 
X				     * Do conversion for n and N types
X				     */
X				    tmpflg = typchr;
X				    if (typchr == 'n' || typchr == 'N' )
X					if (*ncp != '0')
X					    tmpflg = 'd';
X					else if (*(ncp+1) == 'x' ||
X						 *(ncp+1) == 'X')
X					{
X					    tmpflg = 'x';
X					    ncp += 2;
X					}
X					else
X					    tmpflg = 'o';
X				    if (typchr == 'N')
X					toupper( tmpflg );
X
X
X#ifndef	QUICK
X				    cntrl[1] = tmpflg;/* put in conversion */
X				    if (sscanf (ncp, cntrl, aptr, junk) != 1)
X					ERROR (Bad numeric argument);
X#else
X				    if (numcvt(ncp, tmpflg, aptr) != 1)
X					ERROR (Bad numeric argument);
X#endif
X				} while ( comma_list && ++nopt < list_cnt );
X			    }
X			    check += cnt;
X			    arg_used[cnt] = 1;
X			    required = NO;
X			    /*
X			     * If not looking for multiple args,
X			     * then done, otherwise, keep looking.
X			     */
X			    if ( !( list_of && !comma_list ) )
X				break;
X			    else
X				continue;
X			}
X			if (required)
X			    switch (typchr)
X			    {
X				case 'x': 
X				case 'X': 
X				    ERROR (missing hexadecimal argument);
X				case 's': 
X				    ERROR (missing string argument);
X				case 'o': 
X				case 'O': 
X				    ERROR (missing octal argument);
X				case 'd': 
X				case 'D': 
X				    ERROR (missing decimal argument);
X				case 'f': 
X				case 'F': 
X				    ERROR (missing floating argument);
X				case 'n':
X				case 'N':
X				    ERROR (missing numeric argument);
X			    }
X			if ( list_cnt > 0 )
X			{
X			    *cnt_arg = list_cnt;
X			    switch ( typchr )
X			    {
X				case 's':
X				    *va_arg( argl, char *** ) = strlist;
X				    break;
X				case 'n':
X				case 'd':
X				case 'o':
X				case 'x':
X				    *va_arg( argl, int ** ) = intlist;
X				    break;
X				case 'N':
X				case 'D':
X				case 'O':
X				case 'X':
X				    *va_arg( argl, long ** ) = longlist;
X				    break;
X				case 'f':
X				    *va_arg( argl, float ** ) = fltlist;
X				    break;
X				case 'F':
X				    *va_arg( argl, double **) = dbllist;
X				    break;
X			    }
X			    if ( typchr != 's' )
X				free( (char *) strlist );
X			}
X			else if ( cnt >= argc )
X			{
X			    /* Fell off end looking, so must eat the arg */
X			    if ( typchr == 's' )
X				va_arg( argl, char * );
X			    else
X				va_arg( argl, ptr );
X			}
X			break;
X		    default: 		/* error */
X			fprintf (stderr, "error in call to scanargs\n");
X			return (0);
X		}
X	}
X    }
X
X    /*  Count up empty flags */
X    for (cnt=1; cnt<argc; cnt++)
X	if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
X	    && !arg_used[cnt] )
X	    check += cnt;
X
X    /* sum from 1 to N = n*(n+1)/2 used to count up checks */
X    if (check != (((argc - 1) * argc) / 2))
X	ERROR (extra arguments not processed);
X
X    free(arg_used);
X    return (1);
X
Xerror: 
X    fprintf (stderr, "usage : ");
X    if (*(cp = format) != ' ')
X    {
X	if ( *cp == '%' )
X	{
X	    /* 
X	     * This is bogus, but until everyone can agree on a name
X	     * for (rindex/strrchr) ....
X	     */
X	    for ( cp = argv[0]; *cp != '\0'; cp++ )
X		;			/* find the end of the string */
X	    for ( ; cp > argv[0] && *cp != '/'; cp-- )
X		;			/* find the last / */
X	    if ( *cp == '/' )
X		cp++;
X	    fprintf( stderr, "%s", cp );
X
X	    cp = format + 1;		/* reset to where it should be */
X	}
X	while (putc (*cp++, stderr) != ' ');
X    }
X    else
X	fprintf (stderr, "?? ");
X    while (*cp == ' ')
X	cp++;
X    prformat (cp, NO);
X    free(arg_used);
X    return 0;
X}
X
Xstatic char *
Xprformat (format, recurse)
Xchar   *format;
X{
X    register char  *cp;
X    bool    required, comma_list;
X    int    list_of;
X
X    cp = format;
X    if (recurse)
X	putc (' ', stderr);
X
X    required = NO;
X    list_of = 0;
X    comma_list = NO;
X    while (*cp)
X    {
X	switch (*cp)
X	{
X	    default: 
X		cp++;
X		break;
X	    case ' ':
X	    case '\t':
X	    case '\n':
X		putc(*cp, stderr);
X		format = ++cp;
X		break;
X	    case '!': 
X		required = YES;
X	    case '%': 
Xreswitch:
X		switch (*++cp)
X		{
X		    case ',':
X			comma_list++;
X		    case '*':
X			list_of++;
X			goto reswitch;
X
X		    case '$':		/* "rest" of argument list */
X			if (!required)
X			    putc ('[', stderr);
X			for (; format < cp - 1 - list_of; format++)
X			    putc (*format, stderr);
X			fputs( " ...", stderr );
X			if ( !required )
X			    putc( ']', stderr );
X			break;
X
X		    case '-': 		/* flags */
X			if (!required)
X			    putc ('[', stderr);
X			putc ('-', stderr);
X
X			if (cp - format > 2 + list_of)
X			    putc ('{', stderr);
X			cp = format;
X			while (*cp != '%' && *cp != '!')
X			    putc (*cp++, stderr);
X			if (cp - format > 1 + list_of)
X			    putc ('}', stderr);
X			cp += 2;	/* skip !- or %- */
X			if (*cp && !isspace(*cp))
X			    cp = prformat (cp, YES);
X					/* this is a recursive call */
X			if (!required)
X			    putc (']', stderr);
X			break;
X		    case 's': 		/* char string */
X		    case 'd': 		/* decimal # */
X		    case 'o': 		/* octal # */
X		    case 'x': 		/* hexadecimal # */
X		    case 'f': 		/* floating # */
X		    case 'D': 		/* long decimal # */
X		    case 'O': 		/* long octal # */
X		    case 'X': 		/* long hexadecimal # */
X		    case 'F': 		/* double precision floating # */
X		    case 'n':		/* numeric arg (C format) */
X		    case 'N':		/* long numeric arg */
X			if (!required)
X			    putc ('[', stderr);
X			for (; format < cp - 1 - list_of; format++)
X			    putc (*format, stderr);
X			if ( list_of != 0 )
X			{
X			    if ( comma_list )
X				putc( ',', stderr );
X			    else
X				putc( ' ', stderr );
X			    fputs( "...", stderr );
X			}
X			if (!required)
X			    putc (']', stderr);
X			break;
X		    default: 
X			break;
X		}
X		required = NO;
X		list_of = NO;
X		comma_list = NO;
X		if (*cp)		/* check for end of string */
X		    format = ++cp;
X		if (*cp && !isspace(*cp))
X		    putc (' ', stderr);
X	}
X	if (recurse && isspace(*cp))
X	    break;
X    }
X    if (!recurse)
X	putc ('\n', stderr);
X    return (cp);
X}
X
X/* 
X * isnum - determine whether a string MIGHT represent a number.
X * typchr indicates the type of argument we are looking for, and
X * determines the legal character set.  If comma_list is YES, then
X * space and comma are also legal characters.
X */
Xstatic bool
Xisnum( str, typchr, comma_list )
Xregister char * str;
Xchar typchr;
Xbool comma_list;
X{
X    register char * allowed, * digits, * cp;
X    bool hasdigit = NO;
X
X    switch( typchr )
X    {
X	case 'n':
X	case 'N':
X	    allowed = " \t,+-x0123456789abcdefABCDEF";
X	    break;
X	case 'd':
X	case 'D':
X	    allowed = " \t,+-0123456789";
X	    break;
X	case 'o':
X	case 'O':
X	    allowed = " \t,01234567";
X	    break;
X	case 'x':
X	case 'X':
X	    allowed = " \t,0123456789abcdefABCDEF";
X	    break;
X	case 'f':
X	case 'F':
X	    allowed = " \t,+-eE.0123456789";
X	    break;
X	case 's':			/* only throw out decimal numbers */
X	default:
X	    allowed = " \t,+-.0123456789";
X	    break;
X    }
X    digits = allowed;
X    while ( *digits != '0' )
X	digits++;
X    if ( ! comma_list )
X	allowed += 3;		      /* then don't allow space, tab, comma */
X
X    while ( *str != '\0' )
X    {
X    	for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
X    	    ;
X    	if ( *cp == '\0' )
X	    return NO;		     /* if not in allowed chars, not number */
X	if ( cp - digits >= 0 )
X	    hasdigit = YES;
X	str++;
X    }
X    return hasdigit;
X}
X
X#ifdef	QUICK
Xnumcvt(str, conv, val)
Xregister char *str;
Xchar conv;
Xint *val;
X{
X    int base, neg = 0;
X    register unsigned int d;
X    long retval = 0;
X    register char *digits;
X    extern char *index();
X    if (conv == 'o' || conv == 'O')
X	base = 8;
X    else if (conv == 'd' || conv == 'D')
X	base = 10;
X    else if (conv == 'x' || conv == 'X')
X	base = 16;
X    else
X	return 0;
X
X    if (*str == '-')
X    {
X	neg = 1;
X	str++;
X    }
X    while (*str)
X    {
X	if (*str >= '0' && *str < '0'+base)
X	    d = *str - '0';
X	else if (base == 16 && *str >= 'a' && *str <= 'f')
X	    d = 10 + *str - 'a';
X	else if (base == 16 && *str >= 'A' && *str <= 'F')
X	    d = 10 + *str - 'A';
X	else
X	    return 0;
X	retval = retval*base + d;
X	str++;
X    }
X    if (neg)
X	retval = -retval;
X    if (conv == 'D' || conv == 'O' || conv == 'X')
X	*(long *) val = retval;
X    else
X	*val = (int) retval;
X    return 1;
X}
X#endif	QUICK
SHAR_EOF
if test 19707 -ne "`wc -c < 'scanargs.c'`"
then
	echo shar: error transmitting "'scanargs.c'" '(should have been 19707 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'wout.c'" '(1325 characters)'
if test -f 'wout.c'
then
	echo shar: will not over-write existing file "'wout.c'"
else
sed 's/^X//' << \SHAR_EOF > 'wout.c'
X#include <stdio.h>
X#include <ctype.h>
X#include "body.h"
X
Xwskip(start,fd)
Xint start;
XFILE * fd;
X{
X    int i;
X    int flag;
X    int c;
X    flag = IN_FIRS;	/* In 'white space' to begin with */
X    i = 0;
X    (void) fseek(fd, 0L, 0);
X    if (start == 1) return(1);	/* Already at begining */
X    while ((c = getc(fd)) != EOF) {
X	switch (flag) {
X	    case IN_FIRS:
X	        if (isspace(c))
X		    flag = IN_WHIT;
X		else {
X		    flag = IN_WORD;
X		}
X		break;
X	    case IN_WHIT:
X	         if (!isspace(c)) {
X		     flag = IN_WORD;
X		 }
X		 break;
X	    case IN_WORD:
X	        if (isspace(c)) {
X		    flag = IN_WHIT;
X		    if (++i == (start - 1)) return(1);
X		}
X		break;
X	}
X    }
X    return ((c == EOF) ? 0 : 1);
X}
X
Xwprint(number,fd)
Xint number;
XFILE * fd;
X{
X    int i;
X    int c;
X    int flag;
X    if (number == DE_LAST) {	/* Print to end of file */
X	while ((c = getc(fd)) != EOF)
X	    (void) fputc(c,stdout);
X    } else {
X	i = 0;
X	flag = IN_FIRS;
X    while ((c = getc(fd)) != EOF) {
X	if (c != EOF) (void) fputc(c,stdout);
X	switch (flag) {
X	    case IN_FIRS:
X	        flag = isspace(c) ? IN_WHIT : IN_WORD;
X		break;
X	    case IN_WHIT:
X	         if (!isspace(c)) flag = IN_WORD;
X		 break;
X	    case IN_WORD:
X	        if (isspace(c)) {
X		    flag = IN_WHIT;
X		    if (++i == number) return(1);
X		}
X		break;
X	}
X    }
X    }
X    return(1);
X}
SHAR_EOF
if test 1325 -ne "`wc -c < 'wout.c'`"
then
	echo shar: error transmitting "'wout.c'" '(should have been 1325 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0