home *** CD-ROM | disk | FTP | other *** search
- Subject: ff: fast text formatter (part 1 of 2)
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- 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@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
-
-