home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume3 / ff / part01 next >
Encoding:
Internet Message Format  |  1986-11-30  |  32.3 KB

  1. Subject: ff: fast text formatter (part 1 of 2)
  2. Newsgroups: mod.sources
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 3, Issue 51
  6. Submitted by: decvax!wanginst!perlman
  7.  
  8.                  ff: A Fast Text Formatter
  9.  
  10. Here is ff, a fast text  formatter.  It fills a gap  between
  11. the fmt program in Berkeley UNIX and systems like nroff.  ff
  12. is sort  of an  inside-out  nroff.   There are  no  commands
  13. inside a file, but the common options like line width,  line
  14. spacing, indentation,  pagination,  etc., are  command  line
  15. options.  ff is a general  utility that lets you throw  away
  16. most uses of programs like pr, expand, and especially fmt.
  17.  
  18. There are  a lot  of options  for ff--some  would argue  too
  19. many--but they are necessary  to provide the  functionality.
  20. I make shell scripts that encode most of my needs.  Here  is
  21. the shell script I  am using to  format these paragraphs  (I
  22. have the filter bound to a function key; I go to the top  of
  23. the paragraph and type PF1).
  24.     exec ff -w 60 -j -B "     '*.@|" $*
  25. I have  scripts  for  centering  regions  and  for  indented
  26. paragraphs.   These  and  a  nice  one  for  making  program
  27. listings are listed in the manual entry.  emacs users  might
  28. find the centering  option useful, even  though many of  the
  29. other functions are built in to  emacs.  vi users will  find
  30. ff and option-variants on it much more useful.
  31.  
  32. ff really is fast--roughly  twice the speed  as fmt for  the
  33. formats fmt  supports.   For paginating  text, ff  is  about
  34. twice as fast as  pr.  The tab  expansion options on ff  are
  35. comparable to  those of  the  expand program,  but ff  is  a
  36. little slower than expand  on expanding tabs--it simply  has
  37. too many concerns that expand can ignore.  Still, ff is fast
  38. enough to bind  to keys in  emacs or vi  to filter  regions,
  39. making vi a passable wysiwyg editor.  One reason for this is
  40. extensive profiling and  optimization, some  by my  students
  41. for a programming efficiency assignment.
  42.  
  43. #! /bin/sh
  44. # This is a shell archive, meaning:
  45. # 1. Remove everything above the #! /bin/sh line.
  46. # 2. Save the resulting text in a file.
  47. # 3. Execute the file with /bin/sh (not csh) to create the files:
  48. #    ff.1
  49. #    ff.test
  50. #    makefile
  51. #    number.c
  52. #    filter.c
  53. #    getopt.c
  54. # This archive created: Wed Nov 13 19:27:58 1985
  55. # By:    Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
  56. export PATH; PATH=/bin:/usr/bin:$PATH
  57. echo shar: "extracting 'ff.1'" '(6812 characters)'
  58. if test -f 'ff.1'
  59. then
  60.     echo shar: "will not over-write existing file 'ff.1'"
  61. else
  62. sed 's/^    X//' << \SHAR_EOF > 'ff.1'
  63.     X.TH FF 1 "August 10, 1985" "Wang Institute" "UNIX User's Manual"
  64.     X.\" $Compile: iroff -man.new %f
  65.     X.SH NAME
  66.     Xff \- fast text formatter
  67.     X.SH USAGE
  68.     X.B ff
  69.     X[options] [-] [files]
  70.     X.SH DESCRIPTION
  71.     X.I ff
  72.     Xis a simple text formatter for flexible uniform formatting of
  73.     Xinput files.
  74.     XProgram options are used to control formatting.
  75.     XThis is in contrast to text formatters like
  76.     X.I nroff (1)
  77.     Xthat require special format requests to be part of their input files.
  78.     XBesides avoiding cryptic format requests in text,
  79.     X.I ff
  80.     Xis considerably faster than traditional formatters like
  81.     X.I nroff (1)
  82.     Xand even simple formatters like
  83.     X.I fmt (1).
  84.     X.PP
  85.     XThe most complicated concept with
  86.     X.I ff
  87.     Xis that of a line break.
  88.     XA line break causes an interruption in the filling
  89.     X(evening out of the text lines).
  90.     XLine breaks occur when special characters are seen at the beginnings
  91.     Xof lines, or when all lines are broken.
  92.     XBy default, any non-alphanumeric character will cause a break,
  93.     Xbut this can be controlled with the
  94.     X.B -B
  95.     Xoption.
  96.     XA blank line always causes a break.
  97.     X.SH OPTIONS
  98.     XThere are many, many options to allow control of
  99.     Xindentation, line width, line spacing, filling,
  100.     Xpagination with headers and footers,
  101.     Xline numbering, right justification,
  102.     Xand perhaps some other things.
  103.     XThey have extensive type and range checking
  104.     Xthat produces diagnostic error messages,
  105.     Xso warnings of obviously wrong options will not be discussed here.
  106.     XIn general, options that imply the use of others
  107.     Xwork the way they should; if the page size is set,
  108.     Xthen pagination is automatically assumed.
  109.     XSome combinations of options give impressive, even artistic, effects.
  110.     XMaking a small text file and playing with it is the easiest
  111.     Xway to learn how the options interact.
  112.     X.de OP
  113.     X.TP
  114.     X.B -\\$1 \\$2
  115.     X..
  116.     X.OP b
  117.     XBreak all lines of text.
  118.     XThat is, don't even-out lines by filling.
  119.     XBy default, text lines are filled.
  120.     X.OP B breakchars
  121.     XChange the set of characters that cause line breaks at the start of lines to
  122.     X.I breakchars.
  123.     XBy default, any characters but letters and numbers cause a break.
  124.     XA good choice for break characters might be "*-+" and TABS
  125.     Xthat might be used for lists.
  126.     X.OP c
  127.     XCenter all lines of text.
  128.     XThis option stops all filling of text.
  129.     X.OP d
  130.     XDelete white space at the beginning and end of lines.
  131.     XThis option is useful to help un-format text to be re-formatted.
  132.     X.OP D
  133.     XDelete empty input lines.
  134.     XAn input line is empty if it has no characters,
  135.     Xnot even invisible character like tabs or spaces.
  136.     XThis option can be combined with the option to remove white space
  137.     Xto delete visibly blank lines.
  138.     X.OP f footer
  139.     XSet the page footer to the string
  140.     X.I footer.
  141.     XThis can be any string,
  142.     Xbut if the first character is not a letter or a digit,
  143.     Xbut a punctuation character like /,
  144.     Xthen that character separates the left,
  145.     Xcenter, and right fields of a title.
  146.     XFor example, the title
  147.     X.ce
  148.     X"/ff: fast formatter//1985/"
  149.     Xwould have "ff: fast formatter" as a left justified field
  150.     Xand 1985 as a right justified field on each page.
  151.     XNote that there is no middle field in this example,
  152.     Xbut there could have been, between the two consecutive /'s.
  153.     XThere are two special characters, % and *,
  154.     Xthat respectively are variables for the page number
  155.     Xand the input file name.
  156.     XThe default page footer is blank.
  157.     X.OP F footersize
  158.     XSet the number of blank lines at the bottom of the page.
  159.     XThe footer, if any, is placed in the middle of the space,
  160.     Xwhich by default, is five lines.
  161.     XIf
  162.     X.I footersize
  163.     Xis 0, no footer will be printed.
  164.     X.OP h header
  165.     XSet the page header.
  166.     XSee the description of three-part titles for the
  167.     X.B -f footer
  168.     Xoption.
  169.     XThe default page header is
  170.     X.ce
  171.     X"|File: *||Page: %|".
  172.     X.OP H headersize
  173.     XSee the description of the footer size.
  174.     X.OP i indent
  175.     XSet the indentation of the text to
  176.     X.I indent
  177.     Xspaces.
  178.     XNote that this effectively reduces the usable width of the page.
  179.     X.OP I tempindent
  180.     XSet the temporary indent.
  181.     XThis causes filled text found immediately after a break to
  182.     Xbe indented for one line.
  183.     XIt is useful for indenting the first lines of paragraphs.
  184.     XIf
  185.     X.I tempindent
  186.     Xis negative,
  187.     Xthe the temporary indent will be relative to the current
  188.     X.I indent
  189.     Xvalue.
  190.     XIf the
  191.     X.I tempindent
  192.     Xvalue is more negative than the
  193.     X.I indent
  194.     Xvalue is positive,
  195.     X.I ff
  196.     Xwill automatically increase
  197.     X.I indent.
  198.     X.OP j
  199.     XJustify the text.
  200.     XThat is, even the right margin by inserting spaces in the line.
  201.     XOnly filled text can be justified.
  202.     X.OP n
  203.     XNumber all output lines produced by the input text.
  204.     XLines from multiple line spacing or pagination will not
  205.     Xbe numbered.
  206.     X.OP N numberwidth
  207.     XSet the width of the line numbers.
  208.     XThe default is to take up 4 spaces.
  209.     XNote that this effectively reduces the usable part of the page.
  210.     X.OP p
  211.     XPaginate the output.
  212.     XSee the options for page header and footer control.
  213.     X.OP P pagesize
  214.     XSet the number of lines in a page to
  215.     X.I pagesize.
  216.     XBy default, the standard 66 line page is assumed.
  217.     X.OP s spacing
  218.     XSet the line spacing.
  219.     XBy default, text is single spaced (\fIspacing\fR equals 1).
  220.     X.OP t tab
  221.     XSet individual absolute and relative tab stops.
  222.     XThese values tell the formatter
  223.     Xwhere to put the text (from an unfilled line)
  224.     Xthat follows a tab character.
  225.     XEach tab stop is supplied with its own
  226.     X.B -t
  227.     Xoption; there is no way to bundle them.
  228.     X.I tab
  229.     Xvalues can be integers without a plus sign.
  230.     XThese are \fIabsolute\fR tab settings;
  231.     Xthe tabs go to that position.
  232.     XThe values must increase monotonically.
  233.     XIf a
  234.     X.I tab
  235.     Xvalue is preceded by a plus sign,
  236.     Xthen it is interpreted \fIrelative\fR to the previous tab setting.
  237.     XFor example, a tab setting of 40 followed by one of +20
  238.     Xwill set the second tab stop to 60.
  239.     X.OP T tabs
  240.     XSet tab stops to every
  241.     X.I tabs
  242.     Xspaces.
  243.     XIt is useful to get equally spaced tabs.
  244.     XThis option cannot be used with the other tab setting option.
  245.     X.OP u
  246.     XPrint All Input Text As Initial Upper-Case Titles,
  247.     XLike This Sentence.
  248.     XThis option goes well with the one for centering lines.
  249.     X.OP U
  250.     XPrint a usage summary of all the options and stop.
  251.     X.OP w width
  252.     XSet the page width.
  253.     XBy default, the page width is 72 characters.
  254.     XNote that the usable line length is sometimes less
  255.     Xthan the page width.
  256.     XIf line numbering or indentation is requested,
  257.     Xthese subtract from the line length.
  258.     X.SH EXAMPLES
  259.     XSome of these examples can make shell scripts or aliases.
  260.     X.nf
  261.     X.ta .5i
  262.     X.sp
  263.     XCentered Titles: title
  264.     X    ff -dcu $*
  265.     XDouble Spaced Unfilled Paginated indented (for editing): draft
  266.     X    ff -s 2 -b -p -f "`date`" -i 8 $*
  267.     XProgram Listing: cpr
  268.     X    H="@        Dir: `pwd`@@File: *@"
  269.     X    F="@        $NAME@`date`@Page %@"
  270.     X    ff -b -N 8 -H 3 -h "$H" -F 3 -f "$F" -T 4 -w 79 -i 2 $*
  271.     XReformat Paragraphed Text: nr
  272.     X    ff -jd -I 5 -i 10 -w 65 -B "TAB SP'*.@" $*
  273.     X.fi
  274.     X.SH DIAGNOSTICS
  275.     XSome options are incompatible with others.
  276.     XFor example, centered text cannot be right-justified.
  277.     X.I ff
  278.     Xwill not allow inconsistent combinations of options.
  279.     X.SH "SEE ALSO"
  280.     Xfmt(1), nroff(1), scribe(1w)
  281.     X.SH AUTHOR
  282.     XGary Perlman (with help from many students)
  283.     X.SH STATUS
  284.     XPretty well tested.
  285. SHAR_EOF
  286. if test 6812 -ne "`wc -c < 'ff.1'`"
  287. then
  288.     echo shar: "error transmitting 'ff.1'" '(should have been 6812 characters)'
  289. fi
  290. fi
  291. echo shar: "extracting 'ff.test'" '(7703 characters)'
  292. if test -f 'ff.test'
  293. then
  294.     echo shar: "will not over-write existing file 'ff.test'"
  295. else
  296. sed 's/^    X//' << \SHAR_EOF > 'ff.test'
  297.     X#! /usr/local/bin/ksh
  298.     X# test script for ff fast text formatter
  299.     X
  300.     XPATH=$PATH:/tmp
  301.     Xdelim="-------------- "
  302.     Xtrap "rm -f /tmp/linelength fourcol ff.in; exit 1" 2
  303.     X
  304.     X# Define utility functions
  305.     Xfunction runcom
  306.     X    {
  307.     X    echo "$delim($1):" "$2"
  308.     X    shift
  309.     X    echo $* | sh
  310.     X    }
  311.     Xfunction newtest
  312.     X    {
  313.     X    echo
  314.     X    echo $1
  315.     X    echo ===============================================
  316.     X    }
  317.     X# the following must be available to the Bourne shell
  318.     Xecho "dm '#INPUT'" > /tmp/linelength
  319.     Xchmod +x /tmp/linelength
  320.     X
  321.     X# create utility files
  322.     Xcat << \EOF > fourcol
  323.     Xa    b    c    d
  324.     X    w    x    y    z
  325.     XEOF
  326.     Xcat << \EOF > ff.in
  327.     XThe rain in Spain falls mainly in the plains.
  328.     XShe sells sea shells on the sea shore. 
  329.     XPeter piper picked a peck of pickled peppers.
  330.     XThe quick red fox jumped over the lazy brown dog.
  331.     XA stitch in time saves nine.
  332.     XNow is the time for all good men to come to the aid of the party.
  333.     XAnd now a word from our sponsor...
  334.     X    
  335.     XThe rain in Spain falls mainly in the plains.  She sells sea
  336.     Xshells on  the sea  shore.   Peter piper  picked a  peck  of
  337.     Xpickled peppers.   The quick  red fox jumped  over the  lazy
  338.     Xbrown dog.  A stitch  in time saves nine.   Now is the  time
  339.     Xfor all good men to come to the aid of the party.  And now a
  340.     Xword from our sponsor...
  341.     XEOF
  342.     X
  343.     Xnewtest "WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH WIDTH"
  344.     Xruncom "width of 1"                  "ff -w 1 ff.in | linelength"
  345.     Xruncom "width of 20"                 "ff -w 20 ff.in | linelength"
  346.     Xruncom "width of 60"                 "ff -w 60 ff.in | linelength"
  347.     X
  348.     Xnewtest "JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY JUSTIFY"
  349.     Xruncom "justify text"                    "ff -j ff.in"
  350.     Xruncom "justify with width = 30"         "ff -w 30 -j ff.in | linelength"
  351.     Xruncom "justify with indent and temp indent"  "ff -j -i 20 -I 5 ff.in | linelength"
  352.     X
  353.     Xnewtest "ALLTABS ALLTABS ALLTABS ALLTABS ALLTABS ALLTABS"
  354.     Xruncom "tabs set at 1"          "ff -T 1 -b fourcol"
  355.     Xruncom "tabs set at 10"         "ff -T 10 -b fourcol"
  356.     Xruncom "tabs set at 100"        "ff -T 100 -b fourcol"
  357.     X
  358.     Xnewtest "TABS TABS TABS TABS TABS TABS TABS TABS TABS TABS"
  359.     Xruncom "decreasing values"      "ff -t 10 -t 11 -t 10"
  360.     Xruncom "non increasing values"  "ff -t 10 -t 11 -t 11"
  361.     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"
  362.     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"
  363.     Xruncom "huge tab value"         "ff -t 300"
  364.     Xruncom "tab value at extreme"   "ff -t 255 fourcol"
  365.     Xruncom "indented ff -U table"   "ff -U | ff -t 20"
  366.     Xruncom "all plussed values" "ff -t +55 -t +15 fourcol"
  367.     Xruncom "more tabs than tabstops" "ff -t 10 -t +15 fourcol"
  368.     X
  369.     Xnewtest "UPPER CASE TITLE UPPER CASE TITLE UPPER CASE TITLE"
  370.     Xruncom "all titles"              "ff -u ff.in"
  371.     Xruncom "centered titles"         "ff -cu ff.in"
  372.     X
  373.     Xnewtest "SPACING SPACING SPACING SPACING SPACING SPACING SPACING"
  374.     Xruncom "24 lines spacing of 10 lines - 217 lines" "series 1 10 | ff -bs 24 | wc"
  375.     X
  376.     Xnewtest "NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH NUMWIDTH"
  377.     Xruncom "1 value"                 "ff -N 1 ff.in"
  378.     Xruncom "numwidth = 10"           "ff -N 10 ff.in"
  379.     Xruncom "numwidth 20 centered"    "ff -N 20 -c ff.in"
  380.     Xruncom "numwidth=10 indent=10 width=50 tindent=-5 justified" "ff -N 10 -i 10 -w 50 -I -5 -j ff.in"
  381.     X
  382.     Xnewtest "NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER"
  383.     Xruncom "number zero lines"       "ff -n /dev/null"
  384.     Xruncom "number centered lines"   "ff -n -c ff.in"
  385.     Xruncom "number 4 spaced broken lines" "ff -s 4 -n ff.in"
  386.     Xruncom "number 3 spaced lines on 23 line pages" "series 1 200 | ff -n -s 3 -b -P 23 | wc"
  387.     X
  388.     Xnewtest "TINDENT TINDENT TINDENT TINDENT TINDENT TINDENT TINDENT"
  389.     Xruncom "temp indent 5"                   "ff -I 5 ff.in"
  390.     Xruncom "negative temp indent will automatically bump -i option" "ff -I -5 ff.in"
  391.     Xruncom "negative temp indent less than -i option" "ff -I -5 -i 10 ff.in"
  392.     X
  393.     Xnewtest "INDENT INDENT INDENT INDENT INDENT INDENT INDENT INDENT"
  394.     Xruncom "indent 10"                  "ff -i 10 ff.in"
  395.     Xruncom "indent 50"                  "ff -i 50 ff.in"
  396.     X#runcom "indent 300 - does not crash but is really tedious" "ff -i 300 ff.in"
  397.     X
  398.     Xnewtest "HEADSIZE HEADSIZE HEADSIZE HEADSIZE HEADSIZE HEADSIZE"
  399.     Xruncom "1 header size"              "ff -H 1 ff.in | wc"
  400.     Xruncom "100 header size"            "ff -h 'Huge header!!' -H 100 ff.in | wc"
  401.     Xnewtest "tricky part can come with even and odd sizes"
  402.     Xruncom "20 header w/out -p option"  "ff -H 20 ff.in | wc"
  403.     Xruncom "odd header size = 19"       "ff -H 19 ff.in | wc"
  404.     X
  405.     Xnewtest "HEADER HEADER HEADER HEADER HEADER HEADER HEADER"
  406.     Xruncom "nice header"                'ff -h "@$NAME on $TERM@@`date`" ff.in'
  407.     X
  408.     Xnewtest "FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE FOOTSIZE"
  409.     Xruncom "1 foot size"                'ff -F 0 -f "Howdy $NAME" ff.in | wc'
  410.     Xruncom "zero foot size without -p"  "ff -F 0 ff.in"
  411.     Xruncom "20 foot size"               'ff -F 20 -f "Howdy $NAME" ff.in | wc'
  412.     Xruncom "19 foot size"               'ff -F 19 -f "Howdy $NAME" ff.in | wc'
  413.     X
  414.     Xnewtest "FOOTER FOOTER FOOTER FOOTER FOOTER FOOTER FOOTER"
  415.     Xruncom "nice threepart"             'ff -f "@`date`@$NAME@File * Page %@" ff.in'
  416.     X
  417.     Xnewtest "DELETE DELETE DELETE DELETE DELETE DELETE DELETE"
  418.     Xruncom "delete blank lines - not really blank" "ff -D ff.in"
  419.     Xruncom "delete blank chars - breaking all lines" "ff -bd ff.in | diff ff.in -"
  420.     Xruncom "delete chars then lines"    "ff -Dd ff.in"
  421.     X
  422.     Xnewtest "BREAKCHARS BREAKCHARS BREAKCHARS BREAKCHARS"
  423.     Xruncom "null break chars"            'ff -B "" ff.in'
  424.     Xruncom "break on T"                  "ff -B T ff.in"
  425.     X
  426.     Xnewtest "PAGELENGTH PAGELENGTH PAGELENGTH PAGELENGTH PAGELENGTH"
  427.     Xruncom "0dd page length of 19 should imply -p option" "ff -P 19 ff.in | wc"
  428.     Xruncom "ridiculously small page length" "ff -P 1 ff.in | wc"
  429.     X
  430.     Xnewtest "PAGINATE PAGINATE PAGINATE PAGINATE PAGINATE PAGINATE"
  431.     Xruncom "paginate"                    "ff -p ff.in | wc"
  432.     X
  433.     Xnewtest "BREAK BREAK BREAK BREAK BREAK BREAK BREAK BREAK"
  434.     Xruncom "break lines + check with diff" "ff -b ff.in | diff - ff.in"
  435.     X
  436.     Xnewtest "CENTER CENTER CENTER CENTER CENTER CENTER CENTER "
  437.     Xruncom "center all lines"            "ff -c ff.in"
  438.     Xruncom "center on lines 50 wide"     "ff -c -w 50 ff.in"
  439.     Xruncom "center on lines 1 wide"      "ff -c -w 1 ff.in"
  440.     X
  441.     Xnewtest "BASIC BASIC BASIC BASIC BASIC BASIC BASIC BASIC "
  442.     Xruncom "no options from stdin"       "ff < ff.in"
  443.     Xruncom "no options from stdin -"     "ff - < ff.in"
  444.     Xruncom "no options from ff.in"       "ff ff.in"
  445.     Xruncom "three times: ff.in - ff.in"  "ff ff.in - ff.in < ff.in"
  446.     Xruncom "usage menu"                  "ff -U"
  447.     X
  448.     Xnewtest "BAD OPTIONS BAD OPTIONS BAD OPTIONS BAD OPTIONS"
  449.     Xruncom "bad option"                  "ff -z"
  450.     Xruncom "bad file"                    "ff howdy pal"
  451.     Xruncom "too many calls to stdin"     "ff - - - < ff.in"
  452.     X
  453.     Xnewtest "PARSER PARSER PARSER PARSER PARSER PARSER PARSER PARSER"
  454.     X
  455.     Xnewtest "CHECK OPTIONS CHECK OPTIONS CHECK OPTIONS CHECK OPTIONS"
  456.     Xruncom "center iff no justify"       "ff -cj ff.in"
  457.     Xruncom "break lines iff no justify"  "ff -bj ff.in"
  458.     Xruncom "justify iff not center"          "ff -cj"
  459.     Xruncom "justify iff not breaklines"      "ff -bj"
  460.     Xruncom "justify iff not tabs"            "ff -t 5 -j"
  461.     X
  462.     Xnewtest "NUMBER OPTIONS NUMBER OPTIONS NUMBER OPTIONS NUMBER OPTIONS"
  463.     Xfor numopt in P w T t s N i I H F P
  464.     Xdo
  465.     X    runcom "Missing Value"               "ff -$numopt < ff.in"
  466.     X    runcom "Bad Type Value"              "ff -$numopt foo < ff.in"
  467.     X    runcom "Zero Integer"                "ff -$numopt 0 < ff.in"
  468.     X    runcom "Negative Integer"            "ff -$numopt -1 < ff.in"
  469.     Xdone
  470.     X
  471.     Xnewtest "MISSING ARGS MISSING ARGS MISSING ARGS MISSING ARGS"
  472.     Xfor argopt in h f B
  473.     Xdo
  474.     X    runcom "Missing Value"               "ff -$argopt < ff.in"
  475.     Xdone
  476. SHAR_EOF
  477. if test 7703 -ne "`wc -c < 'ff.test'`"
  478. then
  479.     echo shar: "error transmitting 'ff.test'" '(should have been 7703 characters)'
  480. fi
  481. chmod +x 'ff.test'
  482. fi
  483. echo shar: "extracting 'makefile'" '(1056 characters)'
  484. if test -f 'makefile'
  485. then
  486.     echo shar: "will not over-write existing file 'makefile'"
  487. else
  488. sed 's/^    X//' << \SHAR_EOF > 'makefile'
  489.     XMAIN=ff
  490.     XSRCS=number.c filter.c getopt.c
  491.     XOBJS=number.o filter.o getopt.o
  492.     XDOCS=ff.1 ff.test
  493.     XLIBS=
  494.     XDESTDIR=.
  495.     XCFLAGS=-O
  496.     XTEXT=$(HDRS) $(SRCS)
  497.     X
  498.     XLINT  =/usr/bin/lint -hp
  499.     XPR    =cpr
  500.     XSPELL =sp
  501.     XSHAR  =shar -a
  502.     XRCS   =ci -l
  503.     XCC    =/bin/cc
  504.     X
  505.     X$(MAIN): $(MAIN).o $(OBJS)
  506.     X    $(CC) $(CFLAGS) -o $@ $@.o $(OBJS)
  507.     X
  508.     Xinstall: $(MAIN)
  509.     X    cp -i $(MAIN) $(DESTDIR)/$(MAIN)
  510.     X
  511.     Xprint:
  512.     X    @$(PR) $(MAIN).c
  513.     X
  514.     Xlint:
  515.     X    $(LINT) $(TEXT) $(MAIN).c
  516.     X
  517.     Xspell:
  518.     X    seec -cqe $(MAIN).c | $(SPELL)
  519.     X
  520.     Xtest:
  521.     X    $(MAIN).test
  522.     X
  523.     Xarchive: $(DOCS) [Mm]akefile $(TEXT) $(MAIN).c
  524.     X    @$(SHAR) $(DOCS) [Mm]akefile $(TEXT) > archive.1
  525.     X    @$(SHAR) $(MAIN).c > archive.2
  526.     X
  527.     Xclean:
  528.     X    rm -f *.o core a.out mon.out gmon.out scmon.out
  529.     X
  530.     Xgprof:
  531.     X    make CFLAGS="$(CFLAGS) -pg"
  532.     Xscprof:
  533.     X    make CFLAGS="$(CFLAGS) -p" CC=sc
  534.     X
  535.     Xxref: cscope.out
  536.     X    ccall -dr > xref.r
  537.     X    ccall -a > xref.a
  538.     X    touch xref
  539.     Xcscope.out: $(MAIN).c
  540.     X    cscope $(MAIN).c
  541.     X
  542.     Xstyle: style.out
  543.     Xstyle.out:
  544.     X    cstyle $(MAIN).c > style.out
  545.     X
  546.     Xrcs: RCS
  547.     X    $(RCS) $(TEXT) $(MAIN).c
  548.     XRCS: $(TEXT) $(MAIN).c
  549.     X
  550.     X$(MAIN).1: $(MAIN).c
  551.     X    @seec -t MANUAL $(MAIN).c > $(MAIN).1
  552.     X
  553.     X.PRECIOUS: $(TEXT) $(DOCS) $(MAIN).c
  554. SHAR_EOF
  555. if test 1056 -ne "`wc -c < 'makefile'`"
  556. then
  557.     echo shar: "error transmitting 'makefile'" '(should have been 1056 characters)'
  558. fi
  559. fi
  560. echo shar: "extracting 'number.c'" '(4039 characters)'
  561. if test -f 'number.c'
  562. then
  563.     echo shar: "will not over-write existing file 'number.c'"
  564. else
  565. sed 's/^    X//' << \SHAR_EOF > 'number.c'
  566.     X/* Copyright (c) 1982, 1985 Gary Perlman */
  567.     X/* Copies can be made if not for material gain */
  568.     X
  569.     X/*
  570.     X    number: report if a string is a UNIX formatted number
  571.     X
  572.     X    notes:
  573.     X        a number in UNIX is one that can be converted from
  574.     X        a string to an integer or real with no loss of information
  575.     X            due to bad format
  576.     X        all numbers can be surrounded by whitespace
  577.     X        an integer has an optional minus sign, followed by digits
  578.     X        a real number has an optional minus sign followed by digits
  579.     X        if a string has a decimal point, followed by zeros, it is real, not int
  580.     X
  581.     X    value:
  582.     X        1 is string is an integer [-] 0-9+
  583.     X        2 is string is a real number (as seen by atof)
  584.     X        0 for non-numbers
  585.     X
  586.     X    compilation flags:
  587.     X        -DSTANDALONE    includes test main program
  588.     X        $Compile: cc -DSTANDALONE -O -o %F %f
  589.     X    
  590.     X    deficiencies:
  591.     X        does not check to see if significant digits will be ignored
  592.     X    
  593.     X    author:
  594.     X        Gary Perlman
  595.     X
  596.     X    date:
  597.     X        Wed May 22 13:30:40 EDT 1985
  598.     X        Sun Sep  1 14:53:51 EDT 1985 (modified test module)
  599.     X        
  600.     X*/
  601.     X#include <ctype.h>
  602.     X
  603.     X#ifndef lint
  604.     Xstatic char sccsfid[] = "@(#) number.c 5.2 (unix|stat) 9/1/85";
  605.     X#endif
  606.     X
  607.     X#define    IS_NOT      0            /* not a number */
  608.     X#define    IS_INT      1            /* an integer */
  609.     X#define    IS_REAL     2            /* a real number */
  610.     X
  611.     X#define    EOS         '\0'
  612.     X
  613.     X/*LINTLIBRARY*/
  614.     X
  615.     Xnumber (string)
  616.     Xchar    *string;                 /* the string to be tested */
  617.     X    {
  618.     X    int     answer = IS_INT;     /* start by assuming it is an integer */
  619.     X    int     before = 0;          /* anything before the decimal? */
  620.     X    int     after = 0;           /* anything after the decimal? */
  621.     X    while (isspace (*string))    /* skip over blank space */
  622.     X        string++;
  623.     X    if (*string == EOS)          /* empty string not allowed */
  624.     X        return (IS_NOT);
  625.     X    if (*string == '+' || *string == '-') /* old atoi didn't allow '+' */
  626.     X        {
  627.     X        string++;
  628.     X        if (!isdigit (*string) && *string != '.')
  629.     X            return (IS_NOT);
  630.     X        }
  631.     X    if (isdigit (*string))       /* note that there was a digit before . */
  632.     X        {
  633.     X        before = 1;
  634.     X        while (isdigit (*string))
  635.     X            string++;
  636.     X        }
  637.     X    if (*string == '.')          /* found a decimal point, parse for real */
  638.     X        {
  639.     X        answer = IS_REAL;
  640.     X        string++;
  641.     X        if (isdigit (*string))   /* note that there was a digit after . */
  642.     X            {
  643.     X            after = 1;
  644.     X            while (isdigit (*string))
  645.     X                string++;
  646.     X            }
  647.     X        }
  648.     X    if (!before && !after)       /* must be digit somewhere */
  649.     X        return (IS_NOT);
  650.     X    if (*string == 'E' || *string == 'e') /* exponent */
  651.     X        {
  652.     X        answer = IS_REAL;
  653.     X        string++;
  654.     X        if (*string == '+' || *string == '-') /* optional sign */
  655.     X            string++;
  656.     X        if (!isdigit (*string))  /* missing exponent */
  657.     X            return (IS_NOT);
  658.     X        while (isdigit (*string))
  659.     X            string++;
  660.     X        }
  661.     X    while (isspace (*string))    /* skip optional spaces */
  662.     X        string++;
  663.     X    /* should now have exhausted the input string */
  664.     X    return (*string == EOS ? answer : IS_NOT);
  665.     X    }
  666.     X
  667.     X#ifdef STANDALONE
  668.     X
  669.     X#include <stdio.h>
  670.     X/*
  671.     X    exits with status = the number of args not numerical
  672.     X    Shell Example:
  673.     X        if number -i $*
  674.     X        then
  675.     X            echo processing $*
  676.     X        else
  677.     X            echo $0: arguments must be integers 
  678.     X        fi
  679.     X    Options:
  680.     X        -i  arguments must be integer
  681.     X        -n  arguments must be non-negative
  682.     X*/
  683.     Xint     NoNegative;   /* do the values have to be non-negative? */
  684.     Xint     Integer;      /* do the values have to be integers? */
  685.     X
  686.     Xstatic
  687.     Xint
  688.     Xinitial (argc, argv) char **argv;
  689.     X    {
  690.     X    extern    char    *optarg;
  691.     X    extern    int     optind;
  692.     X    int     errflg = 0;
  693.     X    int     C;
  694.     X    char    *optstring = "in";
  695.     X    char    *usage = "[-in] string ...";
  696.     X    while ((C = getopt (argc, argv, optstring)) != EOF)
  697.     X        switch (C)
  698.     X            {
  699.     X            case 'i': Integer = 1; break;
  700.     X            case 'n': NoNegative = 1; break;
  701.     X            default: errflg++; break;
  702.     X            }
  703.     X    if (errflg)
  704.     X        {
  705.     X        fprintf (stderr, "Usage: %s %s\n", argv[0], usage);
  706.     X        exit (1);
  707.     X        }
  708.     X    return (optind);
  709.     X    }
  710.     X
  711.     Xmain (argc, argv) char **argv;
  712.     X    {
  713.     X    int     status = 0;
  714.     X    int     arg = initial (argc, argv);
  715.     X    char    *string;
  716.     X    while (arg < argc)
  717.     X        {
  718.     X        string = argv[arg++];
  719.     X        if (NoNegative && *string == '-') status++;
  720.     X        else switch (number (string))
  721.     X            {
  722.     X            case IS_NOT:  status++; break;
  723.     X            case IS_REAL: if (Integer) status++; break;
  724.     X            case IS_INT:  break;
  725.     X            default: /* CAN'T HAPPEN */ break;
  726.     X            }
  727.     X        }
  728.     X    exit (status);
  729.     X    }
  730.     X
  731.     X#endif
  732. SHAR_EOF
  733. if test 4039 -ne "`wc -c < 'number.c'`"
  734. then
  735.     echo shar: "error transmitting 'number.c'" '(should have been 4039 characters)'
  736. fi
  737. fi
  738. echo shar: "extracting 'filter.c'" '(4306 characters)'
  739. if test -f 'filter.c'
  740. then
  741.     echo shar: "will not over-write existing file 'filter.c'"
  742. else
  743. sed 's/^    X//' << \SHAR_EOF > 'filter.c'
  744.     X/*
  745.     X    Function:    filter "Filter Command Line Files In Classic UNIX Style"
  746.     X    Created:     Sat Aug 10 21:57:12 EDT 1985
  747.     X    By:          Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
  748.     X    Compilation: nothing unusual
  749.     X    Tester:      $Compile: cc -DSTANDALONE -o filter %f
  750.     X    Preconditions:
  751.     X        The index of the first file operand has been determined.
  752.     X    Postconditions:
  753.     X        All files have been opened, processed, and closed.
  754.     X    Returns:
  755.     X        The return status (non-zero is bad) depends on the accessibility
  756.     X        of files, the ability to open them, and the return statuses of
  757.     X        the called function.
  758.     X    Exceptions:
  759.     X        If any file cannot be accessed, then none will be processed.
  760.     X        During processing, if something goes wrong (a file that could
  761.     X        be accessed cannot be opened, or the file processor returns a
  762.     X        non-zero status), processing continues.
  763.     X    Notes:
  764.     X        "-" is the conventional name for the standard input.
  765.     X            It can only be read once.
  766.     X        Fputs and putc are used to print error messages to avoid
  767.     X            loading fat fprintf just because filter used it.
  768.     X*/
  769.     X
  770.     X
  771.     X#include <stdio.h>
  772.     X
  773.     X#ifdef STANDALONE
  774.     X
  775.     Xint
  776.     Xcat (file, ioptr)
  777.     Xchar    *file;
  778.     Xregister    FILE    *ioptr;
  779.     X    {
  780.     X    register    int     C;
  781.     X    while ((C = getc (ioptr)) != EOF)
  782.     X        putchar (C);
  783.     X    return (0);
  784.     X    }
  785.     X
  786.     Xmain (argc, argv) char **argv;
  787.     X    {
  788.     X    int     cat ();
  789.     X
  790.     X    if (filter (argc, argv, 1, cat))
  791.     X        {
  792.     X        putc ('\007', stderr); /* UNIX friendly error message */
  793.     X        exit (1);
  794.     X        }
  795.     X    exit (0);
  796.     X    }
  797.     X
  798.     X#endif STANDALONE
  799.     X
  800.     X
  801.     X/* LINTLIBRARY */
  802.     Xstatic
  803.     Xvoid
  804.     Xerrmsg (pgm, file, errorno, dflt)
  805.     Xchar    *pgm;       /* name of the program running */
  806.     Xchar    *file;      /* file operand to be mentioned (if any) */
  807.     Xint     errorno;    /* system errno or some bad value */
  808.     Xchar    *dflt;      /* default message for bad error numbers */
  809.     X    {
  810.     X    extern    char *sys_errlist[];  /* list of error messages */
  811.     X    extern    int sys_nerr;         /* number of error messages */
  812.     X
  813.     X    fputs (pgm, stderr);
  814.     X    putc (':', stderr);
  815.     X    putc (' ', stderr);
  816.     X    if (errorno > 0 && errorno < sys_nerr)
  817.     X        fputs (sys_errlist[errorno], stderr);
  818.     X    else
  819.     X        fputs (dflt, stderr);
  820.     X    if (file)
  821.     X        {
  822.     X        putc (' ', stderr);
  823.     X        putc ('\'', stderr);
  824.     X        fputs (file, stderr);
  825.     X        putc ('\'', stderr);
  826.     X        }
  827.     X    putc ('\n', stderr);
  828.     X    }
  829.     X
  830.     X
  831.     X#define    isstdin(file) (file[0] == '-' && file[1] == '\0')
  832.     X
  833.     Xint
  834.     Xfilter (argc, argv, curarg, process)
  835.     Xint     argc;          /* real number of command line args */
  836.     Xchar    **argv;        /* command line argument pointer */
  837.     Xint     curarg;        /* first argv to filter */
  838.     Xint     (*process) (); /* status process (char *name, FILE *ioptr) */
  839.     X    {
  840.     X    int     status = 0;         /* return status of this function */
  841.     X    int     arg;                /* loop index variable */
  842.     X    char    *file;              /* name of the current file */
  843.     X    char    *pgm = argv[0];     /* name of the program */
  844.     X    FILE    *ioptr;             /* file pointer for opening */
  845.     X    int     countstdin = 0;     /* number of times stdin is processed */
  846.     X    extern    int errno;          /* system error number */
  847.     X
  848.     X    if (curarg == argc)
  849.     X        status += ((*process) ("-", stdin));
  850.     X    else
  851.     X        {
  852.     X        /* first check to make sure all files can be opened to read */
  853.     X        for (arg = curarg; arg < argc; arg++)
  854.     X            {
  855.     X            file = argv[arg];
  856.     X            if (isstdin (file))
  857.     X                countstdin++;
  858.     X            else if (access (file, 4))
  859.     X                {
  860.     X                errmsg (pgm, file, errno, "Can't access file");
  861.     X                status++;
  862.     X                }
  863.     X            }
  864.     X        if (countstdin > 1)
  865.     X            {
  866.     X            errmsg (pgm, NULL, -1, "Can only read standard input once");
  867.     X            status++;
  868.     X            }
  869.     X        if (status == 0)
  870.     X            for (arg = curarg; arg < argc; arg++)
  871.     X                {
  872.     X                file = argv[arg];
  873.     X                if (isstdin (file))
  874.     X                    status += ((*process) (file, stdin) != 0);
  875.     X                else if (ioptr = fopen (file, "r"))
  876.     X                    {
  877.     X                    status += ((*process) (file, ioptr) != 0);
  878.     X                    (void) fclose (ioptr);
  879.     X                    }
  880.     X                else
  881.     X                    {
  882.     X                    errmsg (pgm, file, errno, "Can't open file");
  883.     X                    status++;
  884.     X                    }
  885.     X                }
  886.     X        }
  887.     X    return (status);
  888.     X    }
  889.     X
  890.     X /*NOTES
  891.     X    Some modifications might be useful but unpopular:
  892.     X        If there is piped input (!isatty (fileno (stdin))),
  893.     X        and the standard input is not read,
  894.     X        then some information may be ignored,
  895.     X        so a warning should be printed.
  896.     X        Unfortunately, this would break things like vi filters.
  897.     X
  898.     X        If there is not piped input,
  899.     X        and the standard input is being read from the keyboard,
  900.     X        then prompt the user for input with something like:
  901.     X            pgm: reading input from terminal
  902.     X        This would avoid the problem of people forgetting to supply
  903.     X        an input redirection.
  904.     X*/
  905. SHAR_EOF
  906. if test 4306 -ne "`wc -c < 'filter.c'`"
  907. then
  908.     echo shar: "error transmitting 'filter.c'" '(should have been 4306 characters)'
  909. fi
  910. fi
  911. echo shar: "extracting 'getopt.c'" '(3008 characters)'
  912. if test -f 'getopt.c'
  913. then
  914.     echo shar: "will not over-write existing file 'getopt.c'"
  915. else
  916. sed 's/^    X//' << \SHAR_EOF > 'getopt.c'
  917.     X/*
  918.     X    I got this off net.sources from Henry Spencer.
  919.     X    It is a public domain getopt(3) like in System V.
  920.     X    I have made the following modifications:
  921.     X
  922.     X    index(s,c) was added because too many people could
  923.     X    not compile getopt without it.
  924.     X
  925.     X    A test main program was added, ifdeffed by STANDALONE.
  926.     X    This main program is a public domain implementation
  927.     X    of the getopt(1) program like in System V.  The getopt
  928.     X    program can be used to standardize shell option handling.
  929.     X        e.g.  cc -DSTANDALONE getopt.c -o getopt
  930.     X*/
  931.     X#include <stdio.h>
  932.     X
  933.     X#ifndef lint
  934.     Xstatic    char    sccsfid[] = "@(#) getopt.c 5.0 (UTZoo) 1985";
  935.     X#endif
  936.     X
  937.     X#define    ARGCH    (int)':'
  938.     X#define BADCH     (int)'?'
  939.     X#define EMSG     ""
  940.     X#define    ENDARGS  "--"
  941.     X
  942.     X/* this is included because index is not on some UNIX systems */
  943.     Xstatic
  944.     Xchar *
  945.     Xindex (s, c)
  946.     Xregister    char    *s;
  947.     Xregister    int     c;
  948.     X    {
  949.     X    while (*s)
  950.     X        if (c == *s) return (s);
  951.     X        else s++;
  952.     X    return (NULL);
  953.     X    }
  954.     X
  955.     X/*
  956.     X * get option letter from argument vector
  957.     X */
  958.     Xint    opterr = 1,        /* useless, never set or used */
  959.     X    optind = 1,        /* index into parent argv vector */
  960.     X    optopt;            /* character checked for validity */
  961.     Xchar    *optarg;        /* argument associated with option */
  962.     X
  963.     X#define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  964.     X        fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  965.     X
  966.     X
  967.     Xgetopt(nargc,nargv,ostr)
  968.     Xint    nargc;
  969.     Xchar    **nargv,
  970.     X    *ostr;
  971.     X{
  972.     X    static char    *place = EMSG;    /* option letter processing */
  973.     X    register char    *oli;        /* option letter list index */
  974.     X    char    *index();
  975.     X
  976.     X    if(!*place) {            /* update scanning pointer */
  977.     X        if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  978.     X        if (*place == '-') {    /* found "--" */
  979.     X            ++optind;
  980.     X            return(EOF);
  981.     X        }
  982.     X    }                /* option letter okay? */
  983.     X    if ((optopt = (int)*place++) == ARGCH || !(oli = index(ostr,optopt))) {
  984.     X        if(!*place) ++optind;
  985.     X        tell(": illegal option -- ");
  986.     X    }
  987.     X    if (*++oli != ARGCH) {        /* don't need argument */
  988.     X        optarg = NULL;
  989.     X        if (!*place) ++optind;
  990.     X    }
  991.     X    else {                /* need an argument */
  992.     X        if (*place) optarg = place;    /* no white space */
  993.     X        else if (nargc <= ++optind) {    /* no arg */
  994.     X            place = EMSG;
  995.     X            tell(": option requires an argument -- ");
  996.     X        }
  997.     X         else optarg = nargv[optind];    /* white space */
  998.     X        place = EMSG;
  999.     X        ++optind;
  1000.     X    }
  1001.     X    return(optopt);            /* dump back option letter */
  1002.     X}
  1003.     X
  1004.     X
  1005.     X#ifdef STANDALONE
  1006.     X
  1007.     X#ifndef lint
  1008.     Xstatic    char    sccspid[] = "@(#) getopt.c 5.1 (WangInst) 6/15/85";
  1009.     X#endif
  1010.     X
  1011.     Xmain (argc, argv) char **argv;
  1012.     X    {
  1013.     X    char    *optstring = argv[1];
  1014.     X    char    *argv0 = argv[0];
  1015.     X    extern    int     optind;
  1016.     X    extern    char    *optarg;
  1017.     X    int     opterr = 0;
  1018.     X    int     C;
  1019.     X    char    *opi;
  1020.     X    if (argc == 1)
  1021.     X        {
  1022.     X        fprintf (stderr, "Usage: %s optstring args\n", argv0);
  1023.     X        exit (1);
  1024.     X        }
  1025.     X    argv++;
  1026.     X    argc--;
  1027.     X    argv[0] = argv0;
  1028.     X    while ((C = getopt (argc, argv, optstring)) != EOF)
  1029.     X        {
  1030.     X        if (C == BADCH) opterr++;
  1031.     X        printf ("-%c ", C);
  1032.     X        opi = index (optstring, C);
  1033.     X        if (opi && opi[1] == ARGCH)
  1034.     X            if (optarg)
  1035.     X                printf ("\"%s\" ", optarg);
  1036.     X            else opterr++;
  1037.     X        }
  1038.     X    printf ("%s", ENDARGS);
  1039.     X    while (optind < argc)
  1040.     X        printf (" \"%s\"", argv[optind++]);
  1041.     X    putchar ('\n');
  1042.     X    exit (opterr);
  1043.     X    }
  1044.     X
  1045.     X#endif
  1046. SHAR_EOF
  1047. if test 3008 -ne "`wc -c < 'getopt.c'`"
  1048. then
  1049.     echo shar: "error transmitting 'getopt.c'" '(should have been 3008 characters)'
  1050. fi
  1051. fi
  1052. exit 0
  1053. #    End of shell archive
  1054.  
  1055.