ast@cs.vu.nl (09/11/89)
Oops. Mark isn't going to post the diffs to nroff. He didn't keep them. He thought I was going to post them. On the other hand, I didn't keep them either. I thought he was going to post them. Communication failure. Sorry. Here's the whole thing, with all corrections, all over again. I changed the names of the files while I was at it. The program is now called nroff. Andy Tanenbaum : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. : --------------------------- cut here -------------------------- PATH=/bin:/usr/bin:/usr/ucb echo Extracting 'README' sed 's/^X//' > 'README' << '+ END-OF-FILE ''README' XNRO is a Word Processor similar to Unix NROFF or RSX-11M RNO - Xit is an adaptation of the text processor given in "Software Tools", Xby Kernighan and Plauger. X XNRO was written by Stephen L. Browning, 5723 North Parker Avenue, XIndianapolis, Indiana 46220, and contributed to the C Users' Group. X XNRO was originally written in BDS C for CP/M systems, and was Xadapted (rather less than perfectly) to compile under standard, K & R Xand UNIX-compatible compilers. X XNRO comes in three parts: X Xnro.c the main function, parameter initialization, and several X support routines; X Xnro2.c the command processor and related routines; X Xnro3.c the text processing portion and related routines. X XThere is also a header file, nro.h, which declares constants, external Xvariables, and structures used by the program. X XThe NRO manual is in nro.1, and is in nro-input format. To format it, Xthe macro package, tmac.an, should be used. It needs to be installed Xin a directory which corresponds to the string constant TMAC which is Xdefined in nro.h. The default definition corresponds to the location Xof nroff/troff macro packages on UNIX systems, /usr/lib/tmac/tmac.*, Xbut can of course be changed. The command to format the NRO Manual to Xthe screen, then, would be as follows: X X nro -man nro.1 X XThere are a number of features which are not currently supported by XNRO, but which would be useful. Here is a partial list: X X- "define string" capability X X- non-expandable space (i.e for fixed gutters in numbered paragraphs) X X- table-driven printer control strings (i.e. printcap definitions for X various printers, specified by a command-line option). X X- diversions X X- a simple table pre-processor X XAccording to Robert Ward of the C Users Group, they have not heard Xfrom the author of the program in a few years, so I guess he is no Xlonger working on it or even interested in it. X----------------------- XWolf N. Paul, 290 Dogwood, Plano, TX. 75075 Xihnp4!killer!mcomp!wnp + END-OF-FILE README chmod 'u=rw,g=r,o=r' 'README' set `wc -c 'README'` count=$1 case $count in 1954) :;; *) echo 'Bad character count in ''README' >&2 echo 'Count should be 1954' >&2 esac echo Extracting 'makefile' sed 's/^X//' > 'makefile' << '+ END-OF-FILE ''makefile' XOBJS = nroff1.s nroff2.s nroff3.s X Xnro: $(OBJS) nroff.h X cc -i -o nroff $(OBJS) X X + END-OF-FILE makefile chmod 'u=rw,g=r,o=r' 'makefile' set `wc -c 'makefile'` count=$1 case $count in 82) :;; *) echo 'Bad character count in ''makefile' >&2 echo 'Count should be 82' >&2 esac echo Extracting 'nroff.1' sed 's/^X//' > 'nroff.1' << '+ END-OF-FILE ''nroff.1' X.TH NRO 1 "Programmer's Manual" X.SH NAME Xnro - text processor similar to X.ul Xnroff. X.SH SYNOPSIS X.bo Xnro [-/+n] [-pxx] [-v] [-b] [-mmfile] [-P] ifile X.SH DESCRIPTION X.ul XNRO Xis a text processor and formatter based on the design Xprovided in X.bo X"Software Tools" Xby Kernighan and Plauger. XThe text and commands found in the X.cu Xifile(s) Xare processed to Xgenerate formatted text. XThe output may be directed into a file if X.ul Xofile Xis present Xin the command line; otherwise, the output will appear at Xthe user console. XUsing the command line option, X.bo X-P, Xwill cause the output to be sent to the printer. X.sp XThe X.ul X+n Xoption causes the output to start with page X.ul Xn. XThe X.ul X-n Xoption causes the output to stop after page X.ul Xn. X.sp XThe X.ul X-v Xoption prints the version number to the console. X.sp XThe X.ul X-p Xoption causes the output to be shifted to the right by X.ul Xxx Xspaces. XThis has the same effect as the X.cc + X+bo X.po Xcommand. X+cc . X.sp XThe X.ul X-b Xoption allows backspaces to appear in the output text when Xunderlining or overstriking. XThis has the same effect as the X.cc + X+bo X.bs Xcommand with a non-zero argument. X+cc . X.sp XThe X.ul X-m Xoption processes the file X.ul Xmfile Xfor macro definitions. The name given after -m will have the Xstring "/usr/lib/tmac/tmac." prepended to it; thus, X.bo X-man Xwill process the file "/usr/lib/tmac/tmac.an". XNote that files processed in this way should contain only macro Xdefinitions, no immediate output should be generated from this file. X.sp XCommands typically are distinguished by a period in column one of the input Xfollowed by a two character abbreviation for the command funtion. XThe abbreviation may then be followed by an optional numeric or Xcharacter argument. XThe numeric argument may be an absolute value such as setting Xthe right margin to a particular column, or the argument may be Xpreceded by a plus sign or a minus sign to indicate that the Xparameter should be modified relative to a previous setting. XThe following commands are recognized: X.sp X.nj X.in +6 X.br X.ti -6 X.cc ! X.bo - causes the following lines of text to appear in Xboldface. XThe optional argument specifies the number of lines to Xbe typed in boldface. XBoldface and underlining are mutually exclusive features. XThe appearance of a boldface command will cause any underlining Xto cease. X!sp X!ti -6 X.bp - causes succeeding text to appear at the top of Xa new page. XThe optional argument specifies the page number for the new page. XThe initial value is one and the default value is one more than Xthe previous page number. X!sp X!ti -6 X.br - causes succeeding text to start on a new line at the Xcurrent left margin. XThere is no numeric argument for this command. X!sp X!ti -6 X.bs - enables or disables the appearance of backspaces Xin the output text. XUnderlining and boldface options are implemented by inserting Xcharacter - backspace - character combinations into the output Xbuffer. XThis is fine for devices which properly recognize the backspace Xcharacter. XSome printers, however, do not recognize backspaces, so the option is Xprovided to overprint one line buffer with another. XThe first line buffer is terminated with just a carriage return Xrather than the carriage return - linefeed combination. XA zero argument or no argument to the backspace command removes Xbackspaces from the output. XA non-zero argument leaves them in the output. XThe default is to remove backspaces. X!sp X!ti -6 X.cc - changes the X!ul XNRO Xcommand character to that specified by the character argument. XIf no argument is provided, the default is a period. X!sp X!ti -6 X.ce - causes the next line of text to appear centered on the output. XThe optional argument specifies if more than one line is to be centered. X!sp X!ti -6 X.de - causes all text and commands following to be used to define Xa macro. XThe definition is terminated by a X!bo X.en Xcommand. XThe first two characters of the argument following the X!bo X.de Xcommand become the name of the new command. XIt should be noted that upper and lower case arguments are considered Xdifferent. XThus, the commands X!bo X.PP Xand X!bo X.pp Xcould define two different macros. XCare should be exercised since existing commands may be redefined. X!sp XA macro may contain up to ten arguments. XIn the macro definition, the placement of arguments is designated by the Xtwo character sequences, $0, $1, ... $9. XWhen the macro is invoked, each argument of the macro command line is Xsubstituted for its corresponding designator in the expansion. XThe first argument of the macro command is substituted for the $0 Xin the expansion, the second argument for the $1, and so forth. XArguments are typically strings which do not contain blanks or tabs. XIf an argument is to contain blanks, then it should be surrounded by Xeither single or double quotes. X!sp X!ti -6 X.cu - causes the next line(s) of text to be continuously underlined. XUnlike the underline command (see X!bo X.ul) Xwhich underlines only alphanumerics, continuous underlining underlines Xall printable characters. XThe optional argument specifies the number of lines of text to underlined. XAny normal underlining or boldface commands currently in effect will be Xterminated. X!sp X!ti -6 X.ef - specifies the text for the footer on even numbered pages. XThe format is the same as for the footer command (see X!bo X.fo). X!sp X!ti -6 X.eh - specifies the text for the header on even numbered pages. XThe format is the same as for the footer command (see X!bo X.fo). X!sp X!ti -6 X.en - designates the end of a macro definition. X!sp X!ti -6 X.fi - causes the input text to be rearranged or filled to obtain the Xmaximum word count possible between the previously set left and Xright margins. XNo argument is expected. X!sp X!ti -6 X.fo - specifies text to be used for a footer. XThe footer text contains three strings seperated by a delimiter Xcharacter. XThe first non-blank character following the command is designated Xas the delimiter. XThe first text string is left justified to the current indentation Xvalue (specified by X!bo X.in). XThe second string is centered between the current indentation value Xand the current right margin value (specified by X!bo X.rm). XThe third string is right justified to the current right margin value. XThe absence of footer text will result in the footer being printed as Xone blank line. XThe presence of the page number character (set by X!bo X.pc) Xin the footer text results Xin the current page number being inserted at that position. XMultiple occurrances of the page number character are allowed. X!sp X!ti -6 X.he - specifies text to be used for a header. XThe format is the same as for the footer (see X!bo X.fo). X!sp X!ti -6 X.in - indents the left margin to the column value specified by the argument. XThe default left margin is set to zero. X!sp X!ti -6 X.ju - causes blanks to be inserted between words in a line of Xoutput in order to align or justify the right margin. XThe default is to justify. X!sp X!ti -6 X.ls - sets the line spacing to the value specified by the argument. XThe default is for single spacing. X!sp X!ti -6 X.m1 - specifies the number of lines in the header margin. XThis is the space from the physical top of page to and including Xthe header text. XA value of zero causes the header to not be printed. XA value of one causes the header to appear at the physical top of page. XLarger argument values cause the appropriate number of blank Xlines to appear before the header is printed. X!sp X!ti -6 X.m2 - specifies the number of blank lines to be printed between Xthe header line and the first line of the processed text. X!sp X!ti -6 X.m3 - specifies the number of blank lines to be printed between Xthe last line of processed text and the footer line. X!sp X!ti -6 X.m4 - specifies the number of lines in the footer margin. XThis command affects the footer the same way the X!bo X.m1 Xcommand Xaffects the header. X!sp X!ti -6 X.ne - specifies a number of lines which should not be broken Xacross a page boundary. XIf the number of lines remaining on a page is less than the Xvalue needed, then a new output page is started. X!sp X!ti -6 X.nf - specifies that succeeding text should be printed without Xrearrangement, or with no fill. XNo argument is expected. X!sp X!ti -6 X.nj - specifies that no attempt should be made to align or justify Xthe right margin. XNo argument is expected. X!sp X!ti -6 X.nr - causes the value of a number register to be set or modified. XA total of twenty-six number registers are available designated X@@na through @@nz (either upper or lower case is allowed). XWhen the sequence @@nc is imbedded in the text, the current value Xof number register c replaces the sequence, thus, such things as Xparagraph numbering can be accomplished with relative ease. X!sp X!ti -6 X.of - specifies the text for the footer on odd numbered pages. XThe format is the same as the footer command (see X!bo X.fo). X!sp X!ti -6 X.oh - specifies the text for the header on odd numbered pages. XThe format is the same as the footer command (see X!bo X.fo). X!sp X!ti -6 X.pc - specifies the page number character to be used in headers Xand footers. XThe occurrance of this character in the header or footer text Xresults in the current page number being printed. XThe default for this character is the hash mark (#). X!sp X!ti -6 X.pl - specifies the page lenght or the number of lines per output page. XThe default is sixty-six. X!sp X!ti -6 X.po - specifies a page offset value. XThis allows the formatted text to be shifted to the right by Xthe number of spaces specified. XThis feature may also be invoked by a switch on the command line. X!sp X!ti -6 X.rm - sets the column value for the right margin. XThe default is eighty. X!sp X!ti -6 X.so - causes input to be retrieved from the file specified Xby the command's character string argument. XThe contents of the new file are inserted into the output Xstream until an EOF is detected. XProcessing of the original file is then resumed. XCommand nesting is allowed. X!sp X!ti -6 X.sp - specifies a number of blank lines to be output before Xprinting the next line of text. X!sp X!ti -6 X.ti - temporarily alters the indentation or left margin value for a single Xsucceeding input line. X!sp X!ti -6 X.ul - causes the next line(s) of text to be underlined. Unlike the X.bo X.cu Xcommand, this command causes only alphanumerics to be underlined, Xskipping punctuation and white space. Underline and boldface are Xmutually exclusive. + END-OF-FILE nroff.1 chmod 'u=rw,g=r,o=r' 'nroff.1' set `wc -c 'nroff.1'` count=$1 case $count in 10271) :;; *) echo 'Bad character count in ''nroff.1' >&2 echo 'Count should be 10271' >&2 esac echo Extracting 'nroff.h' sed 's/^X//' > 'nroff.h' << '+ END-OF-FILE ''nroff.h' X/* X * Parameter file for NRO word processor X * X * Stephen L. Browning X * 5723 North Parker Avenue X * Indianapolis, Indiana 46220 X */ X X#include <ctype.h> X X#define TMAC "/usr/lib/tmac/tmac." /* Prefix for Macro Files */ X X#define MACRO 0 /* macro definition */ X#define BP 1 /* begin page */ X#define BR 2 /* break */ X#define CE 3 /* center */ X#define FI 4 /* fill */ X#define FO 5 /* footer */ X#define HE 6 /* header */ X#define IN 7 /* indent */ X#define LS 8 /* line spacing */ X#define NF 9 /* no fill */ X#define PL 10 /* page lenght */ X#define RM 11 /* right margin */ X#define SP 12 /* line space */ X#define TI 13 /* temp indent */ X#define UL 14 /* underline */ X#define JU 15 /* justify */ X#define NJ 16 /* no justify */ X#define M1 17 /* top margin */ X#define M2 18 /* second top margin */ X#define M3 19 /* first bottom margin */ X#define M4 20 /* bottom-most margin */ X#define BS 21 /* allow/disallow '\b' in output */ X#define NE 22 /* need n lines */ X#define PC 23 /* page number character */ X#define CC 24 /* control character */ X#define PO 25 /* page offset */ X#define BO 26 /* bold face */ X#define EH 27 /* header for even numbered pages */ X#define OH 28 /* header for odd numbered pages */ X#define EF 29 /* footer for even numbered pages */ X#define OF 30 /* footer for odd numbered pages */ X#define SO 31 /* source file */ X#define CU 32 /* continuous underline */ X#define DE 33 /* define macro */ X#define EN 34 /* end macro definition */ X#define NR 35 /* set number register */ X X#define UNKNOWN -1 X X/* X * MAXLINE is set to a value slightly larger X * than twice the longest expected input line. X * Because of the way underlining is handled, the X * input line which is to be underlined, can almost X * triple in length. Unlike normal underlining and X * boldfacing, continuous underlining affects all X * characters in the buffer, and represents the X * worst case condition. If the distance between X * the left margin and the right margin is greater X * than about 65 characters, and continuous underlining X * is in effect, there is a high probability of buffer X * overflow. X */ X X#define MAXLINE 200 X#define PAGELEN 66 X#define PAGEWIDTH 80 X#define HUGE 256 X#define LEFT 0 /* indecies into header margin limit arrays */ X#define RIGHT 1 X#define Nfiles 4 /* nesting depth for input files */ X X/* X * The following parameters may be defined in bdscio.h X */ X X#define YES 1 X#define NO 0 X#define ERR -1 X#define EOS '\0' X#define FALSE 0 X#define TRUE !FALSE X#define OK !ERR X X X/* X * The parameter values selected for macro definitions X * are somewhat arbitrary. MACBUF is the storage area X * for both macro names and definitions. Since macro X * processing is handled by pushing back the expansion X * into the input buffer, the longest possible expansion X * would be MAXLINE characters. Allowing for argument X * expansion, MXMLEN was chosen slightly less than MAXLINE. X * It is assumed that most macro definitions will not X * exceed 20 characters, hence MXMDEF of 100. X */ X X#define MXMDEF 150 /* maximum no. of macro definitions */ X#define MACBUF 4000 /* macro definition buffer */ X#define MXMLEN 150 /* maximum length of each macro definition */ X#define MNLEN 10 /* maximum length of macro name */ X Xstruct macros { X char *mnames[MXMDEF]; /* table of pointers to macro names */ X int lastp; /* index to last mname */ X char *emb; /* next char avail in macro defn buffer */ X char mb[MACBUF]; /* table of macro definitions */ X char *ppb; /* pointer into push back buffer */ X char pbb[MAXLINE]; /* push back buffer */ X}; X X X/* control parameters for nro */ X Xstruct docctl { X int fill; /* fill if YES, init = YES */ X int lsval; /* current line spacing, init = 1 */ X int inval; /* current indent, >= 0, init = 0 */ X int rmval; /* current right margin, init = 60 */ X int tival; /* current temp indent, init = 0 */ X int ceval; /* number of lines to center, init = 0 */ X int ulval; /* number of lines to underline, init = 0 */ X int cuval; /* no. lines to continuously underline, init = 0 */ X int juval; /* justify if YES, init = YES */ X int boval; /* number of lines to bold face, init = 0 */ X int bsflg; /* can output contain '\b', init = FALSE */ X char pgchr; /* page number character, init = '#' */ X char cmdchr; /* command character, init = '.' */ X int prflg; /* print on or off, init = TRUE */ X int sprdir; /* direction for spread(), init = 0 */ X int flevel; /* nesting depth for source cmd, init = 0 */ X int nr[26]; /* number registers */ X}; X X X/* output buffer control parameters */ X Xstruct cout { X int outp; /* next avail char position in outbuf, init = 0 */ X int outw; /* width of text currently in buffer */ X int outwds; /* number of words in buffer, init = 0 */ X int lpr; /* output to printer, init = FALSE */ X char outbuf[MAXLINE]; /* output of filled text */ X}; X X/* page control parameters for nro */ X Xstruct page { X int curpag; /* current output page number, init =0 */ X int newpag; /* next output page number, init = 1 */ X int lineno; /* next line to be printed, init = 0 */ X int plval; /* page length in lines, init = 66 */ X int m1val; /* margin before and including header */ X int m2val; /* margin after header */ X int m3val; /* margin after last text line */ X int m4val; /* bottom margin, including footer */ X int bottom; /* last live line on page X = plval - m3val - m4val */ X int offset; /* page offset from left, init = 0 */ X int frstpg; /* first page to print, init = 0 */ X int lastpg; /* last page to print, init = 30000 */ X int ehlim[2]; /* left/right margins for headers/footers */ X int ohlim[2]; /* init = 0 and PAGEWIDTH */ X int eflim[2]; X int oflim[2]; X char ehead[MAXLINE]; /* top of page title, init = '\n' */ X char ohead[MAXLINE]; X char efoot[MAXLINE]; /* bottom of page title, init = '\n' */ X char ofoot[MAXLINE]; X}; X Xchar *getmac(); X X X/* X * external "common" for NRO word processor X * X */ X#ifdef MAIN Xstruct docctl dc; Xstruct page pg; Xstruct cout co; Xstruct macros mac; XFILE *pout, *sofile[Nfiles+1]; X#else Xextern struct docctl dc; Xextern struct page pg; Xextern struct cout co; Xextern struct macros mac; Xextern FILE *pout, *sofile[Nfiles+1]; X#endif + END-OF-FILE nroff.h chmod 'u=rw,g=r,o=r' 'nroff.h' set `wc -c 'nroff.h'` count=$1 case $count in 6090) :;; *) echo 'Bad character count in ''nroff.h' >&2 echo 'Count should be 6090' >&2 esac echo Extracting 'nroff1.c' sed 's/^X//' > 'nroff1.c' << '+ END-OF-FILE ''nroff1.c' X/* X * Word Processor X * similar to Unix NROFF or RSX-11M RNO - X * adaptation of text processor given in X * "Software Tools", Kernighan and Plauger. X * X * Stephen L. Browning X * 5723 North Parker Avenue X * Indianapolis, Indiana 46220 X * X * Originally written in BDS C; X * Adapted for standard C by W. N. Paul X */ X X#include <stdio.h> X#define MAIN 1 X#include "nroff.h" X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X int i; X int swflg; X int ifp = 0; X X swflg = FALSE; X pout = stdout; X X init(); X for (i=1; i<argc; ++i) { X if (*argv[i] == '-' || *argv[i] == '+') { X if (pswitch(argv[i],&swflg) == ERR) exit(-1); X } X } X for (i=1; i<argc; ++i) { X if (*argv[i] != '-' && *argv[i] != '+') { X if ((sofile[0] = fopen(argv[i],"r")) == NULL) { X printf("nro: unable to open file %s\n",argv[i]); X exit(-1); X } X else { X ifp = 1; X profile(); X fclose(sofile[0]); X } X } X X } X if ((ifp == 0 && swflg == FALSE) || argc <= 1) { X puts("Usage: nroff [-n] [+n] [-pxx] [-v] [-b] [-mmacfile] infile ... [>outfile]\n"); X exit(-1); X } X if (pout != stdout) { X fflush(pout); X fclose(pout); X } X} X X X X/* X * retrieve one line of input text X */ X Xgetlin(p,in_buf) Xchar *p; XFILE *in_buf; X{ X int i; X int c; X char *q; X X q = p; X for (i=0; i<MAXLINE-1; ++i) { X c = ngetc(in_buf); X if (c == EOF) { X *q = EOS; X c = strlen(p); X return(c == 0 ? EOF : c); X } X *q++ = c; X if (c == '\n') break; X } X *q = EOS; X return(strlen(p)); X} X X X X/* X * initialize parameters for nro word processor X */ X Xinit() X{ X int i; X X dc.fill = YES; X dc.lsval = 1; X dc.inval = 0; X dc.rmval = PAGEWIDTH - 1; X dc.tival = 0; X dc.ceval = 0; X dc.ulval = 0; X dc.cuval = 0; X dc.juval = YES; X dc.boval = 0; X dc.bsflg = FALSE; X dc.pgchr = '#'; X dc.cmdchr = '.'; X dc.prflg = TRUE; X dc.sprdir = 0; X for (i=0; i<26; ++i) dc.nr[i] = 0; X pg.curpag = 0; X pg.newpag = 1; X pg.lineno = 0; X pg.plval = PAGELEN; X pg.m1val = 2; X pg.m2val = 2; X pg.m3val = 2; X pg.m4val = 2; X pg.bottom = pg.plval - pg.m4val - pg.m3val; X pg.offset = 0; X pg.frstpg = 0; X pg.lastpg = 30000; X pg.ehead[0] = pg.ohead[0] = '\n'; X pg.efoot[0] = pg.ofoot[0] = '\n'; X for (i=1; i<MAXLINE; ++i) { X pg.ehead[i] = pg.ohead[i] = EOS; X pg.efoot[i] = pg.ofoot[i] = EOS; X } X pg.ehlim[LEFT] = pg.ohlim[LEFT] = dc.inval; X pg.eflim[LEFT] = pg.oflim[LEFT] = dc.inval; X pg.ehlim[RIGHT] = pg.ohlim[RIGHT] = dc.rmval; X pg.eflim[RIGHT] = pg.oflim[RIGHT] = dc.rmval; X co.outp = 0; X co.outw = 0; X co.outwds = 0; X co.lpr = FALSE; X for (i=0; i<MAXLINE; ++i) co.outbuf[i] = EOS; X for (i=0; i<MXMDEF; ++i) mac.mnames[i] = NULL; X mac.lastp = 0; X mac.emb = &mac.mb[0]; X mac.ppb = NULL; X} X X X/* X * get character from input file or push back buffer X */ X Xngetc(infp) XFILE *infp; X{ X int c; X X if (mac.ppb >= &mac.pbb[0]) { X c = *mac.ppb--; X } X else { X c = getc(infp); X } X return(c); X} X X X X/* X * process input files from command line X */ X Xprofile() X{ X char ibuf[MAXLINE]; X X for (dc.flevel=0; dc.flevel>=0; --dc.flevel) { X while (getlin(ibuf,sofile[dc.flevel]) != EOF) { X if (ibuf[0] == dc.cmdchr) comand(ibuf); X else text(ibuf); X } X if (dc.flevel > 0) fclose(sofile[dc.flevel]); X } X if (pg.lineno > 0) space(HUGE); X} X X X X/* X * process switch values from command line X */ X Xpswitch(p,q) Xchar *p; Xint *q; X{ X int swgood; X char mfile[25]; X X swgood = TRUE; X if (*p == '-') { X switch (*++p) { X case 'b': X dc.bsflg = TRUE; X break; X case 'm': X strcpy(mfile,TMAC ); X strcat(mfile, ++p); X if ((sofile[0] = fopen(mfile,"r")) == NULL) { X printf("***nro: unable to open file %s\n",p); X exit(-1); X } X profile(); X fclose(sofile[0]); X break; X case 'p': X set(&pg.offset,ctod(++p),'1',0,0,HUGE); X break; X case 'v': X printf("NRO version 1.0\n"); X *q = TRUE; X break; X case 'P': X pout = fopen("prn","w"); X co.lpr = TRUE; X break; X X case '0': X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X pg.lastpg = ctod(p); X break; X default: X swgood = FALSE; X break; X } X } X else if (*p == '+') { X pg.frstpg = ctod(++p); X } X else { X swgood = FALSE; X } X if (swgood == FALSE) { X printf("nro: illegal switch %s\n",p); X return(ERR); X } X return(OK); X} X/* #include "nro2.c" */ X/* #include "nro3.c" */ + END-OF-FILE nroff1.c chmod 'u=rw,g=r,o=r' 'nroff1.c' set `wc -c 'nroff1.c'` count=$1 case $count in 4175) :;; *) echo 'Bad character count in ''nroff1.c' >&2 echo 'Count should be 4175' >&2 esac echo Extracting 'nroff2.c' sed 's/^X//' > 'nroff2.c' << '+ END-OF-FILE ''nroff2.c' X/* X * Command processor for NRO text processor X * X * Stephen L. Browning X * 5723 North Parker Avenue X * Indianapolis, Indiana 46220 X * X * Originally written in BDS C; X * Adapted for standard C by W. N. Paul X */ X#include <stdio.h> X#include "nroff.h" Xchar *skipwd(), *skipbl(); X Xcomand(p) Xchar *p; X{ X int ct, val; X int spval; X int index; X char argtyp; X char name[MAXLINE]; X char macexp[MXMLEN]; X X ct = comtyp(p,macexp); X if (ct == UNKNOWN) { X printf("*** nro: unrecognized command %s\n",p); X return; X } X expesc(p,name); X val = getval(p,&argtyp); X switch (ct) { X case BO: /* bold face */ X set(&dc.boval,val,argtyp,1,0,HUGE); X dc.cuval = dc.ulval = 0; X break; X case BP: /* begin page */ X if(pg.lineno > 0) space(HUGE); X set(&pg.curpag,val,argtyp,pg.curpag+1,-HUGE,HUGE); X pg.newpag = pg.curpag; X break; X case BR: /* break */ X robrk(); X break; X case BS: /* backspaces in output */ X set(&dc.bsflg,val,argtyp,1,0,1); X break; X case CC: /* command character */ X if (argtyp == '\r' || argtyp == '\n') dc.cmdchr = '.'; X else dc.cmdchr = argtyp; X break; X case CE: /* center */ X robrk(); X set(&dc.ceval,val,argtyp,1,0,HUGE); X break; X case CU: /* continuous underline */ X set(&dc.cuval,val,argtyp,1,0,HUGE); X dc.ulval = dc.boval = 0; X break; X case DE: /* define macro */ X defmac(p,sofile[dc.flevel]); X break; X case EF: /* even footer */ X gettl(p,pg.efoot,&pg.eflim[0]); X break; X case EH: /* even header */ X gettl(p,pg.ehead,&pg.ehlim[0]); X break; X case EN: /* end macro definition */ X puts("***nro: missing .de command\n"); X break; X case FI: /* fill */ X robrk(); X dc.fill = YES; X break; X case FO: /* footer */ X gettl(p,pg.efoot,&pg.eflim[0]); X gettl(p,pg.ofoot,&pg.oflim[0]); X break; X case HE: /* header */ X gettl(p,pg.ehead,&pg.ehlim[0]); X gettl(p,pg.ohead,&pg.ohlim[0]); X break; X case IN: /* indenting */ X set(&dc.inval,val,argtyp,0,0,dc.rmval-1); X dc.tival = dc.inval; X break; X case JU: /* justify */ X dc.juval = YES; X break; X case LS: /* line spacing */ X set(&dc.lsval,val,argtyp,1,1,HUGE); X break; X case M1: /* set topmost margin */ X set(&pg.m1val,val,argtyp,2,0,HUGE); X break; X case M2: /* set second top margin */ X set(&pg.m2val,val,argtyp,2,0,HUGE); X break; X case M3: /* set first bottom margin */ X set(&pg.m3val,val,argtyp,2,0,HUGE); X pg.bottom = pg.plval - pg.m4val - pg.m3val; X break; X case M4: /* set bottom-most margin */ X set(&pg.m4val,val,argtyp,2,0,HUGE); X pg.bottom = pg.plval - pg.m4val - pg.m3val; X break; X case MACRO: /* macro expansion */ X maceval(p,macexp); X break; X case NE: /* need n lines */ X robrk(); X if ((pg.bottom-pg.lineno+1) < (val*dc.lsval)) { X space(HUGE); X } X break; X case NF: /* no fill */ X robrk(); X dc.fill = NO; X break; X case NJ: /* no justify */ X dc.juval = NO; X break; X case NR: /* set number register */ X p = skipwd(p); X p = skipbl(p); X if (!isalpha(*p)) { X puts("***nro: invalid or missing number register name\n"); X } X else { X index = tolower(*p) - 'a'; X p = skipwd(p); X val = getval(p,&argtyp); X set(&dc.nr[index],val,argtyp,0,-HUGE,HUGE); X } X break; X case OF: /* odd footer */ X gettl(p,pg.ofoot,&pg.oflim[0]); X break; X case OH: /* odd header */ X gettl(p,pg.ohead,&pg.ohlim[0]); X break; X case PC: /* page number character */ X if (argtyp == '\r' || argtyp == '\n') dc.pgchr = EOS; X else dc.pgchr = argtyp; X break; X case PL: /* page length */ X set(&pg.plval,val,argtyp,PAGELEN, X pg.m1val+pg.m2val+pg.m3val+pg.m4val+1,HUGE); X pg.bottom = pg.plval - pg.m3val - pg.m4val; X break; X case PO: /* page offset */ X set(&pg.offset,val,argtyp,0,0,HUGE); X break; X case RM: /* right margin */ X set(&dc.rmval,val,argtyp,PAGEWIDTH,dc.tival+1,HUGE); X break; X case SO: /* source file */ X p = skipwd(p); X p = skipbl(p); X if (getwrd(p,name) == 0) break; X if (dc.flevel+1 >= Nfiles) { X puts("***nro: .so commands nested too deeply\n"); X exit(-1); X } X if ((sofile[dc.flevel+1] = fopen(name,"r")) == NULL) { X printf("***nro: unable to open %s\n",name); X exit(-1); X } X ++dc.flevel; X break; X case SP: /* space */ X set(&spval,val,argtyp,1,0,HUGE); X space(spval); X break; X case TI: /* temporary indent */ X robrk(); X set(&dc.tival,val,argtyp,0,0,dc.rmval); X break; X case UL: /* underline */ X set(&dc.ulval,val,argtyp,0,1,HUGE); X dc.cuval = dc.boval = 0; X break; X } X} X X X X/* X * convert ascii character to decimal. X */ X Xatod(c) Xchar c; X{ X return(((c < '0') || (c > '9')) ? -1 : c-'0'); X} X X X X/* X * end current filled line X */ X Xrobrk() X{ X if(co.outp > 0) { X co.outbuf[co.outp] = '\r'; X co.outbuf[co.outp + 1] = '\n'; X co.outbuf[co.outp + 2] = EOS; X put(co.outbuf); X } X co.outp = 0; X co.outw = 0; X co.outwds = 0; X} X X X/* X * Collect macro definition from input stream X */ X Xcolmac(p,d,i) Xchar *p, d[]; Xint i; X{ X while (*p != EOS) { X if (i >= MXMLEN-1) { X d[i-1] = EOS; X return(ERR); X } X d[i++] = *p++; X } X d[i] = EOS; X return(i); X} X X X X X/* X * decodes nro command and returns its associated X * value. X */ X Xcomtyp(p,m) Xchar *p; Xchar *m; X{ X char c1, c2; X char macnam[MNLEN]; X char *s; X X p++; X /* X * First check to see if the command is a macro. X * If it is, truncate to two characters and return X * expansion in m. Note that upper and lower case X * characters are handled differently. X */ X getwrd(p,macnam); X macnam[2] = EOS; X if ((s = getmac(macnam)) != NULL) { X strcpy(m,s); X return(MACRO); X } X c1 = *p++; X c2 = *p; X if (c1 == 'b' && c2 == 'o') return(BO); X if (c1 == 'b' && c2 == 'p') return(BP); X if (c1 == 'b' && c2 == 'r') return(BR); X if (c1 == 'b' && c2 == 's') return(BS); X if (c1 == 'c' && c2 == 'c') return(CC); X if (c1 == 'c' && c2 == 'e') return(CE); X if (c1 == 'c' && c2 == 'u') return(CU); X if (c1 == 'd' && c2 == 'e') return(DE); X if (c1 == 'e' && c2 == 'f') return(EF); X if (c1 == 'e' && c2 == 'h') return(EH); X if (c1 == '.' ) return(EN); X if (c1 == 'f' && c2 == 'i') return(FI); X if (c1 == 'f' && c2 == 'o') return(FO); X if (c1 == 'h' && c2 == 'e') return(HE); X if (c1 == 'i' && c2 == 'n') return(IN); X if (c1 == 'j' && c2 == 'u') return(JU); X if (c1 == 'l' && c2 == 's') return(LS); X if (c1 == 'm' && c2 == '1') return(M1); X if (c1 == 'm' && c2 == '2') return(M2); X if (c1 == 'm' && c2 == '3') return(M3); X if (c1 == 'm' && c2 == '4') return(M4); X if (c1 == 'n' && c2 == 'e') return(NE); X if (c1 == 'n' && c2 == 'f') return(NF); X if (c1 == 'n' && c2 == 'j') return(NJ); X if (c1 == 'n' && c2 == 'r') return(NR); X if (c1 == 'o' && c2 == 'f') return(OF); X if (c1 == 'o' && c2 == 'h') return(OH); X if (c1 == 'p' && c2 == 'c') return(PC); X if (c1 == 'p' && c2 == 'l') return(PL); X if (c1 == 'p' && c2 == 'o') return(PO); X if (c1 == 'r' && c2 == 'm') return(RM); X if (c1 == 's' && c2 == 'o') return(SO); X if (c1 == 's' && c2 == 'p') return(SP); X if (c1 == 't' && c2 == 'i') return(TI); X if (c1 == 'u' && c2 == 'l') return(UL); X return(UNKNOWN); X} X X X X/* X * convert string to decimal. X * processes only positive values. X */ X Xctod(p) Xchar *p; X{ X int val, d; X X val = 0; X while(*p != EOS) { X d = atod(*p++); X if(d == -1) return(val); X val = 10 * val + d; X } X return(val); X} X X X/* X * Define a macro X */ X Xdefmac(p,infp) Xchar *p; XFILE *infp; X{ X int i; X char name[MNLEN]; X char defn[MXMLEN]; X char *q; X X q = skipwd(p); X q = skipbl(q); X i = getwrd(q,name); X if (!isalpha(*name)) { X puts("***nro: missing or illegal macro definition name\n"); X exit(-1); X } X if (i > 2) name[2] = EOS; X i = 0; X while (getlin(p,infp) != EOF) { X if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n') { X break; X } X if (p[0] == dc.cmdchr && p[1] == dc.cmdchr) { X break; X } X if ((i = colmac(p,defn,i)) == ERR) { X puts("***nro: macro definition too long\n"); X exit(-1); X } X } X if (putmac(name,defn) == ERR) { X puts("***nro: macro definition table full\n"); X exit(-1); X } X} X X X/* X * Expand escape sequences X */ X Xexpesc(p,q) Xchar *p; Xchar *q; X{ X char *s, *t; X X s = p; X t = q; X while (*s != EOS) { X if (*s != '@') { X *t++ = *s++; X } X else if (*(s+1) == '@') { X *t++ = *s++; X ++s; X } X else if (tolower(*(s+1)) == 'n' && isalpha(*(s+2))) { X s += 2; X t += itoda(dc.nr[tolower(*s)-'a'],t,6) - 1; X ++s; X } X else { X *t++ = *s++; X } X } X *t = EOS; X strcpy(p,q); X} X X X X/* X * Get macro definition from table X */ X Xchar *getmac(name) Xchar *name; X{ X int i; X X for (i = mac.lastp; i >= 0; --i) { X if (!strcmp(name,mac.mnames[i])) { X#ifdef DEBUG X puts(mac.mnames[i]); X#endif X return(mac.mnames[i] + 3); X } X } X return(NULL); X} X X X X X/* X * get header or footer title X */ X Xgettl(p,q,limit) Xchar *p; Xchar *q; Xint limit[]; X{ X p = skipwd(p); X p = skipbl(p); X strcpy(q,p); X limit[LEFT] = dc.inval; X limit[RIGHT] = dc.rmval; X} X X X X/* X * retrieves optional argument following nro command. X * returns positive integer value with sign (if any) X * saved in character addressed by p_argt. X */ X Xgetval(p,p_argt) Xchar *p; Xchar *p_argt; X{ X p = skipwd(p); X p = skipbl(p); X *p_argt = *p; X if((*p == '+') || (*p == '-')) ++p; X return(ctod(p)); X} X X X/* X * Evaluate macro expansion X */ X Xmaceval(p,m) Xchar *p; Xchar m[]; X{ X int i, j; X char *argp[10]; X char c; X X *p++ = EOS; /* replace command char with EOS */ X /* X * initialize argp array to substitute command X * string for any undefined argument X */ X for (i=0; i<10; ++i) argp[i] = p; X p = skipwd(p); X *p++ = EOS; X for (i=0; i<10; ++i) { X p = skipbl(p); X if (*p == '\r' || *p == '\n' || *p == EOS) break; X if (*p == '\'' || *p == '"') { X c = *p++; X argp[i] = p; X while (*p != c && *p != '\r' && *p != '\n' && *p != EOS) ++p; X *p++ = EOS; X } X else { X argp[i] = p; X p = skipwd(p); X *p++ = EOS; X } X } X for (i=strlen(m)-1; i>=0; --i) { X if (i > 0 && m[i-1] == '$') { X if (!isdigit(m[i])) { X putbak(m[i]); X } X else { X pbstr(argp[m[i]-'0']); X --i; X } X } X else { X putbak(m[i]); X } X } X} X X X/* X * Push back string into input stream X */ X Xpbstr(p) Xchar p[]; X{ X int i; X X for (i=strlen(p)-1; i>=0; --i) { X putbak(p[i]); X } X} X X X X/* X * Push character back into input stream X */ X Xputbak(c) Xchar c; X{ X if (mac.ppb < &mac.pbb[0]) { X mac.ppb = &mac.pbb[0]; X *mac.ppb = c; X } X else { X if (mac.ppb >= &mac.pbb[MAXLINE-1]) { X puts("***nro: push back buffer overflow\n"); X exit(-1); X } X *++mac.ppb = c; X } X} X X X X X/* X * Put macro definition into table X */ X Xputmac(name,p) Xchar *name; Xchar *p; X{ X if (mac.lastp >= MXMDEF) return(ERR); X if (mac.emb + strlen(name) + strlen(p) + 1 > &mac.mb[MACBUF]) { X return(ERR); X } X ++mac.lastp; X mac.mnames[mac.lastp] = mac.emb; X strcpy(mac.emb,name); X strcpy(mac.emb + strlen(name) + 1,p); X mac.emb += strlen(name) + strlen(p) + 2; X return(OK); X} X X X X X/* X * set parameter and check range X */ X Xset(param,val,type,defval,minval,maxval) Xint *param; Xint val; Xchar type; Xint defval,minval,maxval; X{ X switch(type) { X case '\r': X case '\n': X *param = defval; X break; X case '+': X *param += val; X break; X case '-': X *param -= val; X break; X default: X *param = val; X break; X } X *param = min(*param,maxval); X *param = max(*param,minval); X} X X X X/* X * skip blanks and tabs in character buffer. X * return number of characters skipped. X */ X Xchar *skipbl(p) Xchar *p; X{ X while (*p == ' ' || *p == '\t') ++p; X return(p); X} X X X/* X * skip over word and punctuation X */ X Xchar *skipwd(p) Xchar *p; X{ X while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != EOS) X ++p; X return(p); X} X X X X/* X * space vertically n lines X */ X Xspace(n) Xint n; X{ X robrk(); X if (pg.lineno > pg.bottom) return; X if (pg.lineno == 0) phead(); X skip(min(n,pg.bottom+1-pg.lineno)); X pg.lineno += n; X if (pg.lineno > pg.bottom) pfoot(); X} X + END-OF-FILE nroff2.c chmod 'u=rw,g=r,o=r' 'nroff2.c' set `wc -c 'nroff2.c'` count=$1 case $count in 11429) :;; *) echo 'Bad character count in ''nroff2.c' >&2 echo 'Count should be 11429' >&2 esac echo Extracting 'nroff3.c' sed 's/^X//' > 'nroff3.c' << '+ END-OF-FILE ''nroff3.c' X/* X * Text processing portion of NRO word processor X * X * Stephen L. Browning X * 5723 North Parker Avenue X * Indianapolis, Indiana 46220 X * X * Originally written in BDS C; X * Adapted for standard C by W. N. Paul X */ X#include <stdio.h> X#include "nroff.h" X Xtext(p) Xchar *p; X{ X int i; X char wrdbuf[MAXLINE]; X X if (*p == ' ' || *p == '\n' || *p == '\r') leadbl(p); X expesc(p,wrdbuf); X if (dc.ulval > 0) { X /* X * Because of the way underlining is handled, X * MAXLINE should be declared to be three times X * larger than the longest expected input line X * for underlining. Since many of the character X * buffers use this parameter, a lot of memory X * can be allocated when it may not really be X * needed. A MAXLINE of 180 would allow about X * 60 characters in the output line to be X * underlined (remember that only alphanumerics X * get underlined - no spaces or punctuation). X */ X underl(p,wrdbuf,MAXLINE); X --dc.ulval; X } X if (dc.cuval > 0) { X underl(p,wrdbuf,MAXLINE); X --dc.cuval; X } X if (dc.boval > 0) { X bold(p,wrdbuf,MAXLINE); X --dc.boval; X } X if (dc.ceval > 0) { X center(p); X put(p); X --dc.ceval; X } X else if (*p == '\r' || *p == '\n') put(p); /* all blank line */ X else if (dc.fill == NO) put(p); /* unfilled */ X else { X while ((i = getwrd(p,wrdbuf)) > 0) { X putwrd(wrdbuf); X p += i; X } X } X} X X X/* X * insert bold face text X */ X Xbold(p0,p1,size) Xchar *p0, *p1; Xint size; X{ X int i, j; X X j = 0; X for (i=0; (p0[i] != '\n') && (j < size-1); ++i) { X if (isalpha(p0[i]) || isdigit(p0[i])) { X p1[j++] = p0[i]; X p1[j++] = '\b'; X } X p1[j++] = p0[i]; X } X p1[j++] = '\n'; X p1[j] = EOS; X while (*p1 != EOS) *p0++ = *p1++; X *p0 = EOS; X} X X X X X/* X * center a line by setting tival X */ X Xcenter(p) Xchar *p; X{ X dc.tival = max((dc.rmval + dc.tival - width(p)) >> 1,0); X} X X X/* X * expand title buffer to include character string X */ X Xexpand(p0,c,s) Xchar *p0; Xchar c; Xchar *s; X{ X char tmp[MAXLINE]; X char *p, *q, *r; X X p = p0; X q = tmp; X while (*p != EOS) { X if (*p == c) { X r = s; X while (*r != EOS) *q++ = *r++; X } X else *q++ = *p; X ++p; X } X *q = EOS; X strcpy(p0,tmp); /* copy it back */ X} X X X/* X * get field from title X */ X Xchar *getfield(p,q,delim) Xchar *p, *q; Xchar delim; X{ X while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS) { X *q++ = *p++; X } X *q = EOS; X if (*p == delim) ++p; X return(p); X} X X X X/* X * get non-blank word from p0 into p1. X * return number of characters processed. X */ X Xgetwrd(p0,p1) Xchar *p0,*p1; X{ X int i; X char *p, c; X X i = 0; X while (*p0 == ' ' || *p0 == '\t') { X ++i; X ++p0; X } X p = p0; X while (*p0 != ' ' && *p0 != EOS && *p0 != '\t') { X if (*p0 == '\n' || *p0 == '\r') break; X *p1 = *p0++; X ++p1; X ++i; X } X c = *(p1-1); X if (c == '"') c = *(p1-2); X if (c == '?' || c == '!') { X *p1++ = ' '; X ++i; X } X if (c == '.' && (*p0 == '\n' || *p0 == '\r' || islower(*p))) { X *p1++ = ' '; X ++i; X } X *p1 = EOS; X return(i); X} X X X/* X * convert integer to decimal ascii string X */ X Xitoda(value,p,size) Xint value; Xchar *p; Xint size; X{ X char c[7]; X int i, j, k; X int aval; X X aval = abs(value); X c[0] = EOS; X i = 1; X do { X c[i++] = (aval % 10) + '0'; X aval /= 10; X } while (aval > 0 && i <= size); X if (value < 0 && i <= size) c[i++] = '-'; X for (j=0; j<i; ++j) *p++ = c[i-j-1]; X return(i); X} X X X/* X * center title text into print buffer X */ X Xjustcntr(p,q,limit) Xchar *p, *q; Xint limit[]; X{ X int len; X X len = width(p); X q = &q[(limit[RIGHT] + limit[LEFT] - len) >> 1]; X while (*p != EOS) *q++ = *p++; X} X X X X/* X * left justify title text into print buffer X */ X Xjustleft(p,q,limit) Xchar *p, *q; Xint limit; X{ X q = &q[limit]; X while (*p != EOS) *q++ = *p++; X} X X X/* X * right justify title text into print buffer X */ X Xjustrite(p,q,limit) Xchar *p, *q; Xint limit; X{ X int len; X X len = width(p); X q = &q[limit - len]; X while (*p != EOS) *q++ = *p++; X} X X X X X/* X * delete leading blanks, set tival X */ X Xleadbl(p) Xchar *p; X{ X int i,j; X X robrk(); X for (i=0; p[i] == ' '; ++i) ; X if (p[i] != '\n' && p[i] != '\r') dc.tival = i; X for (j=0; p[i] != EOS; ++j) p[j] = p[i++]; X p[j] = EOS; X} X X X X/* X * find minimum of two integer X */ X Xmin(v1,v2) Xint v1,v2; X{ X return((v1 < v2) ? v1 : v2); X} X X X X/* X * find maximum of two integers X */ X Xmax(v1,v2) Xint v1,v2; X{ X return((v1 > v2) ? v1 : v2); X} X X X X/* X * put out page footer X */ X Xpfoot() X{ X if (dc.prflg == TRUE) { X skip(pg.m3val); X if (pg.m4val > 0) { X if ((pg.curpag % 2) == 0) { X puttl(pg.efoot,pg.eflim,pg.curpag); X } X else { X puttl(pg.ofoot,pg.oflim,pg.curpag); X } X skip(pg.m4val - 1); X } X } X} X X X X/* X * put out page header X */ X Xphead() X{ X pg.curpag = pg.newpag; X if (pg.curpag >= pg.frstpg && pg.curpag <= pg.lastpg) { X dc.prflg = TRUE; X } X else { X dc.prflg = FALSE; X } X ++pg.newpag; X if (dc.prflg == TRUE) { X if (pg.m1val > 0) { X skip(pg.m1val - 1); X if ((pg.curpag % 2) == 0) { X puttl(pg.ehead,pg.ehlim,pg.curpag); X } X else { X puttl(pg.ohead,pg.ohlim,pg.curpag); X } X } X skip(pg.m2val); X } X /* X * initialize lineno for the next page X */ X pg.lineno = pg.m1val + pg.m2val + 1; X} X X X/* X * print character with test for printer X */ X Xprchar(c,fp) Xchar c; XFILE *fp; X{ X putc(c,fp); X} X X X X X/* X * put out line with proper spacing and indenting X */ X Xput(p) Xchar *p; X{ X char os[MAXLINE]; X int j; X X if (pg.lineno == 0 || pg.lineno > pg.bottom) { X phead(); X } X if (dc.prflg == TRUE) { X if (!dc.bsflg) { X if (strkovr(p,os) == TRUE) { X for (j=0; j<pg.offset; ++j) prchar(' ',pout); X for (j=0; j<dc.tival; ++j) prchar(' ',pout); X putlin(os,pout); X } X } X for (j=0; j<pg.offset; ++j) prchar(' ',pout); X for (j=0; j<dc.tival; ++j) prchar(' ',pout); X putlin(p,pout); X } X dc.tival = dc.inval; X skip(min(dc.lsval-1,pg.bottom-pg.lineno)); X pg.lineno = pg.lineno + dc.lsval; X if (pg.lineno > pg.bottom) pfoot(); X} X X X/* X * output a null terminated string to the file X * specified by pbuf. X */ X Xputlin(p,pbuf) Xchar *p; XFILE *pbuf; X{ X while (*p != EOS) prchar(*p++,pbuf); X} X X X X/* X * put out title or footer X */ X Xputtl(p,lim,pgno) Xchar *p; Xint lim[]; Xint pgno; X{ X int i; X char pn[8]; X char t[MAXLINE]; X char h[MAXLINE]; X char delim; X X itoda(pgno,pn,6); X for (i=0; i<MAXLINE; ++i) h[i] = ' '; X delim = *p++; X p = getfield(p,t,delim); X expand(t,dc.pgchr,pn); X justleft(t,h,lim[LEFT]); X p = getfield(p,t,delim); X expand(t,dc.pgchr,pn); X justcntr(t,h,lim); X p = getfield(p,t,delim); X expand(t,dc.pgchr,pn); X justrite(t,h,lim[RIGHT]); X for (i=MAXLINE-4; h[i] == ' '; --i) h[i] = EOS; X h[++i] = '\n'; X h[++i] = '\r'; X h[++i] = EOS; X if (strlen(h) > 2) { X for (i=0; i<pg.offset; ++i) prchar(' ',pout); X } X putlin(h,pout); X} X X X X/* X * put word in output buffer X */ X Xputwrd(wrdbuf) Xchar *wrdbuf; X{ X int w; X int last; X int llval; X char *p0, *p1; X int nextra; X X w = width(wrdbuf); X last = strlen(wrdbuf) + co.outp; X llval = dc.rmval - dc.tival; X if(((co.outp > 0) && ((co.outw + w) > llval)) || (last > MAXLINE)) { X last -= co.outp; X if(dc.juval == YES) { X nextra = llval - co.outw + 1; X /* X * Check whether last word was end of X * sentence and modify counts so that X * it is right justified. X */ X if (co.outbuf[co.outp-2] == ' ') { X --co.outp; X ++nextra; X } X spread(co.outbuf,co.outp-1,nextra,co.outwds); X if((nextra > 0) && (co.outwds > 1)) { X co.outp += (nextra - 1); X } X } X robrk(); X } X p0 = wrdbuf; X p1 = co.outbuf + co.outp; X while(*p0 != EOS) *p1++ = *p0++; X co.outp = last; X co.outbuf[co.outp++] = ' '; X co.outw += w + 1; X ++co.outwds; X} X X X/* X * skips the number of lines specified by n. X */ X Xskip(n) Xint n; X{ X int i; X X if (dc.prflg == TRUE && n > 0) { X for(i=0; i<n; ++i) { X prchar('\n',pout); X } X prchar('\r',pout); X } X} X X X X/* X * spread words to justify right margin X */ X Xspread(p,outp,nextra,outwds) Xchar p[]; Xint outp,nextra,outwds; X{ X int i,j; X int nb,ne,nholes; X X if((nextra <= 0) || (outwds <= 1)) return; X dc.sprdir = ~dc.sprdir; X ne = nextra; X nholes = outwds - 1; /* holes between words */ X i = outp - 1; /* last non-blank character */ X j = min(MAXLINE-3,i+ne); /* leave room for CR, LF, EOS */ X while(i < j) { X p[j] = p[i]; X if(p[i] == ' ') { X if(dc.sprdir == 0) nb = (ne - 1)/nholes + 1; X else nb = ne/nholes; X ne -= nb; X --nholes; X for(; nb>0; --nb) { X --j; X p[j] = ' '; X } X } X --i; X --j; X } X} X X X X/* X * split overstrikes (backspaces) into seperate buffer X */ X Xstrkovr(p,q) Xchar *p, *q; X{ X char *pp; X int bsflg; X X bsflg = FALSE; X pp = p; X while (*p != EOS) { X *q = ' '; X *pp = *p; X ++p; X if (*p == '\b') { X if (*pp >= ' ' && *pp <= '~') { X bsflg = TRUE; X *q = *pp; X ++p; X *pp = *p; X ++p; X } X } X ++q; X ++pp; X } X *q++ = '\r'; X *q = *pp = EOS; X return(bsflg); X} X X X X/* X * underline a line X */ X Xunderl(p0,p1,size) Xchar *p0,*p1; Xint size; X{ X int i,j; X X j = 0; X for (i=0; (p0[i] != '\n') && (j < size-1); ++i) { X if (p0[i] >= ' ' && p0[i] <= '~') { X if (isalpha(p0[i]) || isdigit(p0[i]) || dc.cuval > 0) { X p1[j++] = '_'; X p1[j++] = '\b'; X } X } X p1[j++] = p0[i]; X } X p1[j++] = '\n'; X p1[j] = EOS; X while (*p1 != EOS) *p0++ = *p1++; X *p0 = EOS; X} X X X/* X * compute width of character string X */ X Xwidth(s) Xchar *s; X{ X int w; X X w = 0; X while (*s != EOS) { X if (*s == '\b') --w; X else if (*s != '\n' && *s != '\r') ++w; X ++s; X } X return(w); X} X + END-OF-FILE nroff3.c chmod 'u=rw,g=r,o=r' 'nroff3.c' set `wc -c 'nroff3.c'` count=$1 case $count in 9156) :;; *) echo 'Bad character count in ''nroff3.c' >&2 echo 'Count should be 9156' >&2 esac echo Extracting 'tmac.an' sed 's/^X//' > 'tmac.an' << '+ END-OF-FILE ''tmac.an' X.de TH X.m1 1 X.in 0 X.rm 65 X.he |$0 ($1)|$2|$0 ($1)| X.fo | |-#-| | X.in 5 X.rm 60 X.. X.de PP X.sp 1 X.ti +5 X.. X.de SH X.sp 1 X.ti -5 X.bo X$0 X.br X.. + END-OF-FILE tmac.an chmod 'u=rw,g=r,o=r' 'tmac.an' set `wc -c 'tmac.an'` count=$1 case $count in 138) :;; *) echo 'Bad character count in ''tmac.an' >&2 echo 'Count should be 138' >&2 esac exit 0