[comp.os.minix] need nroff or equivalent!

ast@cs.vu.nl (Andy Tanenbaum) (09/09/89)

In article <23429@louie.udel.EDU> XBR1YD3E%DDATHD21.BITNET@cunyvm.cuny.edu writes:
>By the way, does anybody know about a port of the nroff-formatter to minix,

Here is one that doesn't quite work.  If you can make it work, by all means
please post it.
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 'nro.1'
sed 's/^X//' > 'nro.1' << '+ END-OF-FILE ''nro.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 nro.1
chmod 'u=rw,g=r,o=r' 'nro.1'
set `wc -c 'nro.1'`
count=$1
case $count in
10271)	:;;
*)	echo 'Bad character count in ''nro.1' >&2
		echo 'Count should be 10271' >&2
esac
echo Extracting 'nro.c'
sed 's/^X//' > 'nro.c' << '+ END-OF-FILE ''nro.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#include "nro.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: nro [-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 nro.c
chmod 'u=rw,g=r,o=r' 'nro.c'
set `wc -c 'nro.c'`
count=$1
case $count in
4144)	:;;
*)	echo 'Bad character count in ''nro.c' >&2
		echo 'Count should be 4144' >&2
esac
echo Extracting 'nro.h'
sed 's/^X//' > 'nro.h' << '+ END-OF-FILE ''nro.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
Xstruct docctl dc;
Xstruct page pg;
Xstruct cout co;
Xstruct macros mac;
XFILE *pout, *sofile[Nfiles+1];
+ END-OF-FILE nro.h
chmod 'u=rw,g=r,o=r' 'nro.h'
set `wc -c 'nro.h'`
count=$1
case $count in
5931)	:;;
*)	echo 'Bad character count in ''nro.h' >&2
		echo 'Count should be 5931' >&2
esac
echo Extracting 'nro2.c'
sed 's/^X//' > 'nro2.c' << '+ END-OF-FILE ''nro2.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
X#include "nro.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 nro2.c
chmod 'u=rw,g=r,o=r' 'nro2.c'
set `wc -c 'nro2.c'`
count=$1
case $count in
11409)	:;;
*)	echo 'Bad character count in ''nro2.c' >&2
		echo 'Count should be 11409' >&2
esac
echo Extracting 'nro3.c'
sed 's/^X//' > 'nro3.c' << '+ END-OF-FILE ''nro3.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
X#include "nro.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 nro3.c
chmod 'u=rw,g=r,o=r' 'nro3.c'
set `wc -c 'nro3.c'`
count=$1
case $count in
9136)	:;;
*)	echo 'Bad character count in ''nro3.c' >&2
		echo 'Count should be 9136' >&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