sources-request@panda.UUCP (11/28/85)
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