ff: fast text formatter (part 1 of 2)
sources-request at panda.UUCP
sources-request at panda.UUCP
Fri Nov 29 02:32:36 AEST 1985
Mod.sources: Volume 3, Issue 51
Submitted by: decvax!wanginst!perlman
ff: A Fast Text Formatter
Here is ff, a fast text formatter. It fills a gap between
the fmt program in Berkeley UNIX and systems like nroff. ff
is sort of an inside-out nroff. There are no commands
inside a file, but the common options like line width, line
spacing, indentation, pagination, etc., are command line
options. ff is a general utility that lets you throw away
most uses of programs like pr, expand, and especially fmt.
There are a lot of options for ff--some would argue too
many--but they are necessary to provide the functionality.
I make shell scripts that encode most of my needs. Here is
the shell script I am using to format these paragraphs (I
have the filter bound to a function key; I go to the top of
the paragraph and type PF1).
exec ff -w 60 -j -B " '*.@|" $*
I have scripts for centering regions and for indented
paragraphs. These and a nice one for making program
listings are listed in the manual entry. emacs users might
find the centering option useful, even though many of the
other functions are built in to emacs. vi users will find
ff and option-variants on it much more useful.
ff really is fast--roughly twice the speed as fmt for the
formats fmt supports. For paginating text, ff is about
twice as fast as pr. The tab expansion options on ff are
comparable to those of the expand program, but ff is a
little slower than expand on expanding tabs--it simply has
too many concerns that expand can ignore. Still, ff is fast
enough to bind to keys in emacs or vi to filter regions,
making vi a passable wysiwyg editor. One reason for this is
extensive profiling and optimization, some by my students
for a programming efficiency assignment.
#! /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:
# ff.1
# ff.test
# makefile
# number.c
# filter.c
# getopt.c
# This archive created: Wed Nov 13 19:27:58 1985
# By: Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'ff.1'" '(6812 characters)'
if test -f 'ff.1'
then
echo shar: "will not over-write existing file 'ff.1'"
else
sed 's/^ X//' << \SHAR_EOF > 'ff.1'
X.TH FF 1 "August 10, 1985" "Wang Institute" "UNIX User's Manual"
X.\" $Compile: iroff -man.new %f
X.SH NAME
Xff \- fast text formatter
X.SH USAGE
X.B ff
X[options] [-] [files]
X.SH DESCRIPTION
X.I ff
Xis a simple text formatter for flexible uniform formatting of
Xinput files.
XProgram options are used to control formatting.
XThis is in contrast to text formatters like
X.I nroff (1)
Xthat require special format requests to be part of their input files.
XBesides avoiding cryptic format requests in text,
X.I ff
Xis considerably faster than traditional formatters like
X.I nroff (1)
Xand even simple formatters like
X.I fmt (1).
X.PP
XThe most complicated concept with
X.I ff
Xis that of a line break.
XA line break causes an interruption in the filling
X(evening out of the text lines).
XLine breaks occur when special characters are seen at the beginnings
Xof lines, or when all lines are broken.
XBy default, any non-alphanumeric character will cause a break,
Xbut this can be controlled with the
X.B -B
Xoption.
XA blank line always causes a break.
X.SH OPTIONS
XThere are many, many options to allow control of
Xindentation, line width, line spacing, filling,
Xpagination with headers and footers,
Xline numbering, right justification,
Xand perhaps some other things.
XThey have extensive type and range checking
Xthat produces diagnostic error messages,
Xso warnings of obviously wrong options will not be discussed here.
XIn general, options that imply the use of others
Xwork the way they should; if the page size is set,
Xthen pagination is automatically assumed.
XSome combinations of options give impressive, even artistic, effects.
XMaking a small text file and playing with it is the easiest
Xway to learn how the options interact.
X.de OP
X.TP
X.B -\\$1 \\$2
X..
X.OP b
XBreak all lines of text.
XThat is, don't even-out lines by filling.
XBy default, text lines are filled.
X.OP B breakchars
XChange the set of characters that cause line breaks at the start of lines to
X.I breakchars.
XBy default, any characters but letters and numbers cause a break.
XA good choice for break characters might be "*-+" and TABS
Xthat might be used for lists.
X.OP c
XCenter all lines of text.
XThis option stops all filling of text.
X.OP d
XDelete white space at the beginning and end of lines.
XThis option is useful to help un-format text to be re-formatted.
X.OP D
XDelete empty input lines.
XAn input line is empty if it has no characters,
Xnot even invisible character like tabs or spaces.
XThis option can be combined with the option to remove white space
Xto delete visibly blank lines.
X.OP f footer
XSet the page footer to the string
X.I footer.
XThis can be any string,
Xbut if the first character is not a letter or a digit,
Xbut a punctuation character like /,
Xthen that character separates the left,
Xcenter, and right fields of a title.
XFor example, the title
X.ce
X"/ff: fast formatter//1985/"
Xwould have "ff: fast formatter" as a left justified field
Xand 1985 as a right justified field on each page.
XNote that there is no middle field in this example,
Xbut there could have been, between the two consecutive /'s.
XThere are two special characters, % and *,
Xthat respectively are variables for the page number
Xand the input file name.
XThe default page footer is blank.
X.OP F footersize
XSet the number of blank lines at the bottom of the page.
XThe footer, if any, is placed in the middle of the space,
Xwhich by default, is five lines.
XIf
X.I footersize
Xis 0, no footer will be printed.
X.OP h header
XSet the page header.
XSee the description of three-part titles for the
X.B -f footer
Xoption.
XThe default page header is
X.ce
X"|File: *||Page: %|".
X.OP H headersize
XSee the description of the footer size.
X.OP i indent
XSet the indentation of the text to
X.I indent
Xspaces.
XNote that this effectively reduces the usable width of the page.
X.OP I tempindent
XSet the temporary indent.
XThis causes filled text found immediately after a break to
Xbe indented for one line.
XIt is useful for indenting the first lines of paragraphs.
XIf
X.I tempindent
Xis negative,
Xthe the temporary indent will be relative to the current
X.I indent
Xvalue.
XIf the
X.I tempindent
Xvalue is more negative than the
X.I indent
Xvalue is positive,
X.I ff
Xwill automatically increase
X.I indent.
X.OP j
XJustify the text.
XThat is, even the right margin by inserting spaces in the line.
XOnly filled text can be justified.
X.OP n
XNumber all output lines produced by the input text.
XLines from multiple line spacing or pagination will not
Xbe numbered.
X.OP N numberwidth
XSet the width of the line numbers.
XThe default is to take up 4 spaces.
XNote that this effectively reduces the usable part of the page.
X.OP p
XPaginate the output.
XSee the options for page header and footer control.
X.OP P pagesize
XSet the number of lines in a page to
X.I pagesize.
XBy default, the standard 66 line page is assumed.
X.OP s spacing
XSet the line spacing.
XBy default, text is single spaced (\fIspacing\fR equals 1).
X.OP t tab
XSet individual absolute and relative tab stops.
XThese values tell the formatter
Xwhere to put the text (from an unfilled line)
Xthat follows a tab character.
XEach tab stop is supplied with its own
X.B -t
Xoption; there is no way to bundle them.
X.I tab
Xvalues can be integers without a plus sign.
XThese are \fIabsolute\fR tab settings;
Xthe tabs go to that position.
XThe values must increase monotonically.
XIf a
X.I tab
Xvalue is preceded by a plus sign,
Xthen it is interpreted \fIrelative\fR to the previous tab setting.
XFor example, a tab setting of 40 followed by one of +20
Xwill set the second tab stop to 60.
X.OP T tabs
XSet tab stops to every
X.I tabs
Xspaces.
XIt is useful to get equally spaced tabs.
XThis option cannot be used with the other tab setting option.
X.OP u
XPrint All Input Text As Initial Upper-Case Titles,
XLike This Sentence.
XThis option goes well with the one for centering lines.
X.OP U
XPrint a usage summary of all the options and stop.
X.OP w width
XSet the page width.
XBy default, the page width is 72 characters.
XNote that the usable line length is sometimes less
Xthan the page width.
XIf line numbering or indentation is requested,
Xthese subtract from the line length.
X.SH EXAMPLES
XSome of these examples can make shell scripts or aliases.
X.nf
X.ta .5i
X.sp
XCentered Titles: title
X ff -dcu $*
XDouble Spaced Unfilled Paginated indented (for editing): draft
X ff -s 2 -b -p -f "`date`" -i 8 $*
XProgram Listing: cpr
X H="@ Dir: `pwd`@@File: *@"
X F="@ $NAME@`date`@Page %@"
X ff -b -N 8 -H 3 -h "$H" -F 3 -f "$F" -T 4 -w 79 -i 2 $*
XReformat Paragraphed Text: nr
X ff -jd -I 5 -i 10 -w 65 -B "TAB SP'*.@" $*
X.fi
X.SH DIAGNOSTICS
XSome options are incompatible with others.
XFor example, centered text cannot be right-justified.
X.I ff
Xwill not allow inconsistent combinations of options.
X.SH "SEE ALSO"
Xfmt(1), nroff(1), scribe(1w)
X.SH AUTHOR
XGary Perlman (with help from many students)
X.SH STATUS
XPretty well tested.
SHAR_EOF
if test 6812 -ne "`wc -c < 'ff.1'`"
then
echo shar: "error transmitting 'ff.1'" '(should have been 6812 characters)'
fi
fi
echo shar: "extracting 'ff.test'" '(7703 characters)'
if test -f 'ff.test'
then
echo shar: "will not over-write existing file 'ff.test'"
else
sed 's/^ X//' << \SHAR_EOF > 'ff.test'
X#! /usr/local/bin/ksh
X# test script for ff fast text formatter
X
XPATH=$PATH:/tmp
Xdelim="-------------- "
Xtrap "rm -f /tmp/linelength fourcol ff.in; exit 1" 2
X
X# Define utility functions
Xfunction runcom
X {
X echo "$delim($1):" "$2"
X shift
X echo $* | sh
X }
Xfunction newtest
X {
X echo
X echo $1
X echo ===============================================
X }
X# the following must be available to the Bourne shell
Xecho "dm '#INPUT'" > /tmp/linelength
Xchmod +x /tmp/linelength
X
X# create utility files
Xcat << \EOF > fourcol
Xa b c d
X w x y z
XEOF
Xcat << \EOF > ff.in
XThe rain in Spain falls mainly in the plains.
XShe sells sea shells on the sea shore.
XPeter piper picked a peck of pickled peppers.
XThe quick red fox jumped over the lazy brown dog.
XA stitch in time saves nine.
XNow is the time for all good men to come to the aid of the party.
XAnd now a word from our sponsor...
X
XThe rain in Spain falls mainly in the plains. She sells sea
Xshells on the sea shore. Peter piper picked a peck of
Xpickled peppers. The quick red fox jumped over the lazy
Xbrown dog. A stitch in time saves nine. Now is the time
Xfor all good men to come to the aid of the party. And now a
Xword from our sponsor...
XEOF
X
Xnewtest "WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH"
Xruncom "width of 1" "ff -w 1 ff.in | linelength"
Xruncom "width of 20" "ff -w 20 ff.in | linelength"
Xruncom "width of 60" "ff -w 60 ff.in | linelength"
X
Xnewtest "JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY"
Xruncom "justify text" "ff -j ff.in"
Xruncom "justify with width = 30" "ff -w 30 -j ff.in | linelength"
Xruncom "justify with indent and temp indent" "ff -j -i 20 -I 5 ff.in | linelength"
X
Xnewtest "ALLTABS ALLTABS ALLTABS ALLTABS ALLTABS ALLTABS"
Xruncom "tabs set at 1" "ff -T 1 -b fourcol"
Xruncom "tabs set at 10" "ff -T 10 -b fourcol"
Xruncom "tabs set at 100" "ff -T 100 -b fourcol"
X
Xnewtest "TABS TABS TABS TABS TABS TABS TABS TABS TABS TABS"
Xruncom "decreasing values" "ff -t 10 -t 11 -t 10"
Xruncom "non increasing values" "ff -t 10 -t 11 -t 11"
Xruncom "1 too many values" "ff -t 1 -t 2 -t 3 -t 4 -t 5 -t 6 -t 7 -t 8 -t 9 -t 10 -t 11 -t 12 -t 13 -t 14 -t 15 -t 16 -t 17 -t 18 -t 19 -t 20 -t 21"
Xruncom "max number of values - exits from unknown option" "ff -t 1 -t 2 -t 3 -t 4 -t 5 -t 6 -t 7 -t 8 -t 9 -t 10 -t 11 -t 12 -t 13 -t 14 -t 15 -t 16 -t 17 -t 18 -t 19 -t 20 -z"
Xruncom "huge tab value" "ff -t 300"
Xruncom "tab value at extreme" "ff -t 255 fourcol"
Xruncom "indented ff -U table" "ff -U | ff -t 20"
Xruncom "all plussed values" "ff -t +55 -t +15 fourcol"
Xruncom "more tabs than tabstops" "ff -t 10 -t +15 fourcol"
X
Xnewtest "UPPER CASE TITLE UPPER CASE TITLE UPPER CASE TITLE"
Xruncom "all titles" "ff -u ff.in"
Xruncom "centered titles" "ff -cu ff.in"
X
Xnewtest "SPACING SPACING SPACING SPACING SPACING SPACING SPACING"
Xruncom "24 lines spacing of 10 lines - 217 lines" "series 1 10 | ff -bs 24 | wc"
X
Xnewtest "NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH"
Xruncom "1 value" "ff -N 1 ff.in"
Xruncom "numwidth = 10" "ff -N 10 ff.in"
Xruncom "numwidth 20 centered" "ff -N 20 -c ff.in"
Xruncom "numwidth=10 indent=10 width=50 tindent=-5 justified" "ff -N 10 -i 10 -w 50 -I -5 -j ff.in"
X
Xnewtest "NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER"
Xruncom "number zero lines" "ff -n /dev/null"
Xruncom "number centered lines" "ff -n -c ff.in"
Xruncom "number 4 spaced broken lines" "ff -s 4 -n ff.in"
Xruncom "number 3 spaced lines on 23 line pages" "series 1 200 | ff -n -s 3 -b -P 23 | wc"
X
Xnewtest "TINDENT TINDENT TINDENT TINDENT TINDENT TINDENT TINDENT"
Xruncom "temp indent 5" "ff -I 5 ff.in"
Xruncom "negative temp indent will automatically bump -i option" "ff -I -5 ff.in"
Xruncom "negative temp indent less than -i option" "ff -I -5 -i 10 ff.in"
X
Xnewtest "INDENT INDENT INDENT INDENT INDENT INDENT INDENT INDENT"
Xruncom "indent 10" "ff -i 10 ff.in"
Xruncom "indent 50" "ff -i 50 ff.in"
X#runcom "indent 300 - does not crash but is really tedious" "ff -i 300 ff.in"
X
Xnewtest "HEADSIZE HEADSIZE HEADSIZE HEADSIZE HEADSIZE HEADSIZE"
Xruncom "1 header size" "ff -H 1 ff.in | wc"
Xruncom "100 header size" "ff -h 'Huge header!!' -H 100 ff.in | wc"
Xnewtest "tricky part can come with even and odd sizes"
Xruncom "20 header w/out -p option" "ff -H 20 ff.in | wc"
Xruncom "odd header size = 19" "ff -H 19 ff.in | wc"
X
Xnewtest "HEADER HEADER HEADER HEADER HEADER HEADER HEADER"
Xruncom "nice header" 'ff -h "@$NAME on $TERM@@`date`" ff.in'
X
Xnewtest "FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE"
Xruncom "1 foot size" 'ff -F 0 -f "Howdy $NAME" ff.in | wc'
Xruncom "zero foot size without -p" "ff -F 0 ff.in"
Xruncom "20 foot size" 'ff -F 20 -f "Howdy $NAME" ff.in | wc'
Xruncom "19 foot size" 'ff -F 19 -f "Howdy $NAME" ff.in | wc'
X
Xnewtest "FOOTER FOOTER FOOTER FOOTER FOOTER FOOTER FOOTER"
Xruncom "nice threepart" 'ff -f "@`date`@$NAME at File * Page %@" ff.in'
X
Xnewtest "DELETE DELETE DELETE DELETE DELETE DELETE DELETE"
Xruncom "delete blank lines - not really blank" "ff -D ff.in"
Xruncom "delete blank chars - breaking all lines" "ff -bd ff.in | diff ff.in -"
Xruncom "delete chars then lines" "ff -Dd ff.in"
X
Xnewtest "BREAKCHARS BREAKCHARS BREAKCHARS BREAKCHARS"
Xruncom "null break chars" 'ff -B "" ff.in'
Xruncom "break on T" "ff -B T ff.in"
X
Xnewtest "PAGELENGTH PAGELENGTH PAGELENGTH PAGELENGTH PAGELENGTH"
Xruncom "0dd page length of 19 should imply -p option" "ff -P 19 ff.in | wc"
Xruncom "ridiculously small page length" "ff -P 1 ff.in | wc"
X
Xnewtest "PAGINATE PAGINATE PAGINATE PAGINATE PAGINATE PAGINATE"
Xruncom "paginate" "ff -p ff.in | wc"
X
Xnewtest "BREAK BREAK BREAK BREAK BREAK BREAK BREAK BREAK"
Xruncom "break lines + check with diff" "ff -b ff.in | diff - ff.in"
X
Xnewtest "CENTER CENTER CENTER CENTER CENTER CENTER CENTER "
Xruncom "center all lines" "ff -c ff.in"
Xruncom "center on lines 50 wide" "ff -c -w 50 ff.in"
Xruncom "center on lines 1 wide" "ff -c -w 1 ff.in"
X
Xnewtest "BASIC BASIC BASIC BASIC BASIC BASIC BASIC BASIC "
Xruncom "no options from stdin" "ff < ff.in"
Xruncom "no options from stdin -" "ff - < ff.in"
Xruncom "no options from ff.in" "ff ff.in"
Xruncom "three times: ff.in - ff.in" "ff ff.in - ff.in < ff.in"
Xruncom "usage menu" "ff -U"
X
Xnewtest "BAD OPTIONS BAD OPTIONS BAD OPTIONS BAD OPTIONS"
Xruncom "bad option" "ff -z"
Xruncom "bad file" "ff howdy pal"
Xruncom "too many calls to stdin" "ff - - - < ff.in"
X
Xnewtest "PARSER PARSER PARSER PARSER PARSER PARSER PARSER PARSER"
X
Xnewtest "CHECK OPTIONS CHECK OPTIONS CHECK OPTIONS CHECK OPTIONS"
Xruncom "center iff no justify" "ff -cj ff.in"
Xruncom "break lines iff no justify" "ff -bj ff.in"
Xruncom "justify iff not center" "ff -cj"
Xruncom "justify iff not breaklines" "ff -bj"
Xruncom "justify iff not tabs" "ff -t 5 -j"
X
Xnewtest "NUMBER OPTIONS NUMBER OPTIONS NUMBER OPTIONS NUMBER OPTIONS"
Xfor numopt in P w T t s N i I H F P
Xdo
X runcom "Missing Value" "ff -$numopt < ff.in"
X runcom "Bad Type Value" "ff -$numopt foo < ff.in"
X runcom "Zero Integer" "ff -$numopt 0 < ff.in"
X runcom "Negative Integer" "ff -$numopt -1 < ff.in"
Xdone
X
Xnewtest "MISSING ARGS MISSING ARGS MISSING ARGS MISSING ARGS"
Xfor argopt in h f B
Xdo
X runcom "Missing Value" "ff -$argopt < ff.in"
Xdone
SHAR_EOF
if test 7703 -ne "`wc -c < 'ff.test'`"
then
echo shar: "error transmitting 'ff.test'" '(should have been 7703 characters)'
fi
chmod +x 'ff.test'
fi
echo shar: "extracting 'makefile'" '(1056 characters)'
if test -f 'makefile'
then
echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^ X//' << \SHAR_EOF > 'makefile'
XMAIN=ff
XSRCS=number.c filter.c getopt.c
XOBJS=number.o filter.o getopt.o
XDOCS=ff.1 ff.test
XLIBS=
XDESTDIR=.
XCFLAGS=-O
XTEXT=$(HDRS) $(SRCS)
X
XLINT =/usr/bin/lint -hp
XPR =cpr
XSPELL =sp
XSHAR =shar -a
XRCS =ci -l
XCC =/bin/cc
X
X$(MAIN): $(MAIN).o $(OBJS)
X $(CC) $(CFLAGS) -o $@ $@.o $(OBJS)
X
Xinstall: $(MAIN)
X cp -i $(MAIN) $(DESTDIR)/$(MAIN)
X
Xprint:
X @$(PR) $(MAIN).c
X
Xlint:
X $(LINT) $(TEXT) $(MAIN).c
X
Xspell:
X seec -cqe $(MAIN).c | $(SPELL)
X
Xtest:
X $(MAIN).test
X
Xarchive: $(DOCS) [Mm]akefile $(TEXT) $(MAIN).c
X @$(SHAR) $(DOCS) [Mm]akefile $(TEXT) > archive.1
X @$(SHAR) $(MAIN).c > archive.2
X
Xclean:
X rm -f *.o core a.out mon.out gmon.out scmon.out
X
Xgprof:
X make CFLAGS="$(CFLAGS) -pg"
Xscprof:
X make CFLAGS="$(CFLAGS) -p" CC=sc
X
Xxref: cscope.out
X ccall -dr > xref.r
X ccall -a > xref.a
X touch xref
Xcscope.out: $(MAIN).c
X cscope $(MAIN).c
X
Xstyle: style.out
Xstyle.out:
X cstyle $(MAIN).c > style.out
X
Xrcs: RCS
X $(RCS) $(TEXT) $(MAIN).c
XRCS: $(TEXT) $(MAIN).c
X
X$(MAIN).1: $(MAIN).c
X @seec -t MANUAL $(MAIN).c > $(MAIN).1
X
X.PRECIOUS: $(TEXT) $(DOCS) $(MAIN).c
SHAR_EOF
if test 1056 -ne "`wc -c < 'makefile'`"
then
echo shar: "error transmitting 'makefile'" '(should have been 1056 characters)'
fi
fi
echo shar: "extracting 'number.c'" '(4039 characters)'
if test -f 'number.c'
then
echo shar: "will not over-write existing file 'number.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'number.c'
X/* Copyright (c) 1982, 1985 Gary Perlman */
X/* Copies can be made if not for material gain */
X
X/*
X number: report if a string is a UNIX formatted number
X
X notes:
X a number in UNIX is one that can be converted from
X a string to an integer or real with no loss of information
X due to bad format
X all numbers can be surrounded by whitespace
X an integer has an optional minus sign, followed by digits
X a real number has an optional minus sign followed by digits
X if a string has a decimal point, followed by zeros, it is real, not int
X
X value:
X 1 is string is an integer [-] 0-9+
X 2 is string is a real number (as seen by atof)
X 0 for non-numbers
X
X compilation flags:
X -DSTANDALONE includes test main program
X $Compile: cc -DSTANDALONE -O -o %F %f
X
X deficiencies:
X does not check to see if significant digits will be ignored
X
X author:
X Gary Perlman
X
X date:
X Wed May 22 13:30:40 EDT 1985
X Sun Sep 1 14:53:51 EDT 1985 (modified test module)
X
X*/
X#include <ctype.h>
X
X#ifndef lint
Xstatic char sccsfid[] = "@(#) number.c 5.2 (unix|stat) 9/1/85";
X#endif
X
X#define IS_NOT 0 /* not a number */
X#define IS_INT 1 /* an integer */
X#define IS_REAL 2 /* a real number */
X
X#define EOS '\0'
X
X/*LINTLIBRARY*/
X
Xnumber (string)
Xchar *string; /* the string to be tested */
X {
X int answer = IS_INT; /* start by assuming it is an integer */
X int before = 0; /* anything before the decimal? */
X int after = 0; /* anything after the decimal? */
X while (isspace (*string)) /* skip over blank space */
X string++;
X if (*string == EOS) /* empty string not allowed */
X return (IS_NOT);
X if (*string == '+' || *string == '-') /* old atoi didn't allow '+' */
X {
X string++;
X if (!isdigit (*string) && *string != '.')
X return (IS_NOT);
X }
X if (isdigit (*string)) /* note that there was a digit before . */
X {
X before = 1;
X while (isdigit (*string))
X string++;
X }
X if (*string == '.') /* found a decimal point, parse for real */
X {
X answer = IS_REAL;
X string++;
X if (isdigit (*string)) /* note that there was a digit after . */
X {
X after = 1;
X while (isdigit (*string))
X string++;
X }
X }
X if (!before && !after) /* must be digit somewhere */
X return (IS_NOT);
X if (*string == 'E' || *string == 'e') /* exponent */
X {
X answer = IS_REAL;
X string++;
X if (*string == '+' || *string == '-') /* optional sign */
X string++;
X if (!isdigit (*string)) /* missing exponent */
X return (IS_NOT);
X while (isdigit (*string))
X string++;
X }
X while (isspace (*string)) /* skip optional spaces */
X string++;
X /* should now have exhausted the input string */
X return (*string == EOS ? answer : IS_NOT);
X }
X
X#ifdef STANDALONE
X
X#include <stdio.h>
X/*
X exits with status = the number of args not numerical
X Shell Example:
X if number -i $*
X then
X echo processing $*
X else
X echo $0: arguments must be integers
X fi
X Options:
X -i arguments must be integer
X -n arguments must be non-negative
X*/
Xint NoNegative; /* do the values have to be non-negative? */
Xint Integer; /* do the values have to be integers? */
X
Xstatic
Xint
Xinitial (argc, argv) char **argv;
X {
X extern char *optarg;
X extern int optind;
X int errflg = 0;
X int C;
X char *optstring = "in";
X char *usage = "[-in] string ...";
X while ((C = getopt (argc, argv, optstring)) != EOF)
X switch (C)
X {
X case 'i': Integer = 1; break;
X case 'n': NoNegative = 1; break;
X default: errflg++; break;
X }
X if (errflg)
X {
X fprintf (stderr, "Usage: %s %s\n", argv[0], usage);
X exit (1);
X }
X return (optind);
X }
X
Xmain (argc, argv) char **argv;
X {
X int status = 0;
X int arg = initial (argc, argv);
X char *string;
X while (arg < argc)
X {
X string = argv[arg++];
X if (NoNegative && *string == '-') status++;
X else switch (number (string))
X {
X case IS_NOT: status++; break;
X case IS_REAL: if (Integer) status++; break;
X case IS_INT: break;
X default: /* CAN'T HAPPEN */ break;
X }
X }
X exit (status);
X }
X
X#endif
SHAR_EOF
if test 4039 -ne "`wc -c < 'number.c'`"
then
echo shar: "error transmitting 'number.c'" '(should have been 4039 characters)'
fi
fi
echo shar: "extracting 'filter.c'" '(4306 characters)'
if test -f 'filter.c'
then
echo shar: "will not over-write existing file 'filter.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'filter.c'
X/*
X Function: filter "Filter Command Line Files In Classic UNIX Style"
X Created: Sat Aug 10 21:57:12 EDT 1985
X By: Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
X Compilation: nothing unusual
X Tester: $Compile: cc -DSTANDALONE -o filter %f
X Preconditions:
X The index of the first file operand has been determined.
X Postconditions:
X All files have been opened, processed, and closed.
X Returns:
X The return status (non-zero is bad) depends on the accessibility
X of files, the ability to open them, and the return statuses of
X the called function.
X Exceptions:
X If any file cannot be accessed, then none will be processed.
X During processing, if something goes wrong (a file that could
X be accessed cannot be opened, or the file processor returns a
X non-zero status), processing continues.
X Notes:
X "-" is the conventional name for the standard input.
X It can only be read once.
X Fputs and putc are used to print error messages to avoid
X loading fat fprintf just because filter used it.
X*/
X
X
X#include <stdio.h>
X
X#ifdef STANDALONE
X
Xint
Xcat (file, ioptr)
Xchar *file;
Xregister FILE *ioptr;
X {
X register int C;
X while ((C = getc (ioptr)) != EOF)
X putchar (C);
X return (0);
X }
X
Xmain (argc, argv) char **argv;
X {
X int cat ();
X
X if (filter (argc, argv, 1, cat))
X {
X putc ('\007', stderr); /* UNIX friendly error message */
X exit (1);
X }
X exit (0);
X }
X
X#endif STANDALONE
X
X
X/* LINTLIBRARY */
Xstatic
Xvoid
Xerrmsg (pgm, file, errorno, dflt)
Xchar *pgm; /* name of the program running */
Xchar *file; /* file operand to be mentioned (if any) */
Xint errorno; /* system errno or some bad value */
Xchar *dflt; /* default message for bad error numbers */
X {
X extern char *sys_errlist[]; /* list of error messages */
X extern int sys_nerr; /* number of error messages */
X
X fputs (pgm, stderr);
X putc (':', stderr);
X putc (' ', stderr);
X if (errorno > 0 && errorno < sys_nerr)
X fputs (sys_errlist[errorno], stderr);
X else
X fputs (dflt, stderr);
X if (file)
X {
X putc (' ', stderr);
X putc ('\'', stderr);
X fputs (file, stderr);
X putc ('\'', stderr);
X }
X putc ('\n', stderr);
X }
X
X
X#define isstdin(file) (file[0] == '-' && file[1] == '\0')
X
Xint
Xfilter (argc, argv, curarg, process)
Xint argc; /* real number of command line args */
Xchar **argv; /* command line argument pointer */
Xint curarg; /* first argv to filter */
Xint (*process) (); /* status process (char *name, FILE *ioptr) */
X {
X int status = 0; /* return status of this function */
X int arg; /* loop index variable */
X char *file; /* name of the current file */
X char *pgm = argv[0]; /* name of the program */
X FILE *ioptr; /* file pointer for opening */
X int countstdin = 0; /* number of times stdin is processed */
X extern int errno; /* system error number */
X
X if (curarg == argc)
X status += ((*process) ("-", stdin));
X else
X {
X /* first check to make sure all files can be opened to read */
X for (arg = curarg; arg < argc; arg++)
X {
X file = argv[arg];
X if (isstdin (file))
X countstdin++;
X else if (access (file, 4))
X {
X errmsg (pgm, file, errno, "Can't access file");
X status++;
X }
X }
X if (countstdin > 1)
X {
X errmsg (pgm, NULL, -1, "Can only read standard input once");
X status++;
X }
X if (status == 0)
X for (arg = curarg; arg < argc; arg++)
X {
X file = argv[arg];
X if (isstdin (file))
X status += ((*process) (file, stdin) != 0);
X else if (ioptr = fopen (file, "r"))
X {
X status += ((*process) (file, ioptr) != 0);
X (void) fclose (ioptr);
X }
X else
X {
X errmsg (pgm, file, errno, "Can't open file");
X status++;
X }
X }
X }
X return (status);
X }
X
X/*NOTES
X Some modifications might be useful but unpopular:
X If there is piped input (!isatty (fileno (stdin))),
X and the standard input is not read,
X then some information may be ignored,
X so a warning should be printed.
X Unfortunately, this would break things like vi filters.
X
X If there is not piped input,
X and the standard input is being read from the keyboard,
X then prompt the user for input with something like:
X pgm: reading input from terminal
X This would avoid the problem of people forgetting to supply
X an input redirection.
X*/
SHAR_EOF
if test 4306 -ne "`wc -c < 'filter.c'`"
then
echo shar: "error transmitting 'filter.c'" '(should have been 4306 characters)'
fi
fi
echo shar: "extracting 'getopt.c'" '(3008 characters)'
if test -f 'getopt.c'
then
echo shar: "will not over-write existing file 'getopt.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'getopt.c'
X/*
X I got this off net.sources from Henry Spencer.
X It is a public domain getopt(3) like in System V.
X I have made the following modifications:
X
X index(s,c) was added because too many people could
X not compile getopt without it.
X
X A test main program was added, ifdeffed by STANDALONE.
X This main program is a public domain implementation
X of the getopt(1) program like in System V. The getopt
X program can be used to standardize shell option handling.
X e.g. cc -DSTANDALONE getopt.c -o getopt
X*/
X#include <stdio.h>
X
X#ifndef lint
Xstatic char sccsfid[] = "@(#) getopt.c 5.0 (UTZoo) 1985";
X#endif
X
X#define ARGCH (int)':'
X#define BADCH (int)'?'
X#define EMSG ""
X#define ENDARGS "--"
X
X/* this is included because index is not on some UNIX systems */
Xstatic
Xchar *
Xindex (s, c)
Xregister char *s;
Xregister int c;
X {
X while (*s)
X if (c == *s) return (s);
X else s++;
X return (NULL);
X }
X
X/*
X * get option letter from argument vector
X */
Xint opterr = 1, /* useless, never set or used */
X optind = 1, /* index into parent argv vector */
X optopt; /* character checked for validity */
Xchar *optarg; /* argument associated with option */
X
X#define tell(s) fputs(*nargv,stderr);fputs(s,stderr); \
X fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
X
X
Xgetopt(nargc,nargv,ostr)
Xint nargc;
Xchar **nargv,
X *ostr;
X{
X static char *place = EMSG; /* option letter processing */
X register char *oli; /* option letter list index */
X char *index();
X
X if(!*place) { /* update scanning pointer */
X if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
X if (*place == '-') { /* found "--" */
X ++optind;
X return(EOF);
X }
X } /* option letter okay? */
X if ((optopt = (int)*place++) == ARGCH || !(oli = index(ostr,optopt))) {
X if(!*place) ++optind;
X tell(": illegal option -- ");
X }
X if (*++oli != ARGCH) { /* don't need argument */
X optarg = NULL;
X if (!*place) ++optind;
X }
X else { /* need an argument */
X if (*place) optarg = place; /* no white space */
X else if (nargc <= ++optind) { /* no arg */
X place = EMSG;
X tell(": option requires an argument -- ");
X }
X else optarg = nargv[optind]; /* white space */
X place = EMSG;
X ++optind;
X }
X return(optopt); /* dump back option letter */
X}
X
X
X#ifdef STANDALONE
X
X#ifndef lint
Xstatic char sccspid[] = "@(#) getopt.c 5.1 (WangInst) 6/15/85";
X#endif
X
Xmain (argc, argv) char **argv;
X {
X char *optstring = argv[1];
X char *argv0 = argv[0];
X extern int optind;
X extern char *optarg;
X int opterr = 0;
X int C;
X char *opi;
X if (argc == 1)
X {
X fprintf (stderr, "Usage: %s optstring args\n", argv0);
X exit (1);
X }
X argv++;
X argc--;
X argv[0] = argv0;
X while ((C = getopt (argc, argv, optstring)) != EOF)
X {
X if (C == BADCH) opterr++;
X printf ("-%c ", C);
X opi = index (optstring, C);
X if (opi && opi[1] == ARGCH)
X if (optarg)
X printf ("\"%s\" ", optarg);
X else opterr++;
X }
X printf ("%s", ENDARGS);
X while (optind < argc)
X printf (" \"%s\"", argv[optind++]);
X putchar ('\n');
X exit (opterr);
X }
X
X#endif
SHAR_EOF
if test 3008 -ne "`wc -c < 'getopt.c'`"
then
echo shar: "error transmitting 'getopt.c'" '(should have been 3008 characters)'
fi
fi
exit 0
# End of shell archive
More information about the Mod.sources
mailing list