: To unbundle, sh this file echo x - Makefile 1>&2 sed 's/^X//' >Makefile <<'@@@End of Makefile' XDEFS=-DCHKINDEX XCFLAGS=-O $(DEFINES) XFILES = README rnotroff.[1c] makefile lint runoffmacros XLINTFLAGS = -ha X Xrunoff: runoff.c X $(CC) $(CFLAGS) $(DEFS) runoff.c -o $@ X Xrnotroff: rnotroff.c X $(CC) $(CFLAGS) rnotroff.c -o $@ X Xlint: rnotroff.c X lint $(LINTFLAGS) $? >$@ X Xdist: $(FILES) X @bundle $(FILES) @@@End of Makefile echo x - README 1>&2 sed 's/^X//' >README <<'@@@End of README' X RUNOFF to troff converter package. X @(#)README 1.2 93/02/01 X XThe program rnotro converts files in the DEC RUNOFF format Xinto nroff/troff format. There is a macro package that performs Xsome of the simulation; you might want to massage the output Xfile to use -ms or -mm later. X XCopyright 1985 by the Governing Council of the University of Toronto. X XPermission to use, copy, modify, distribute, and sell this software and Xits documentation for any purpose is hereby granted without fee, Xprovided that the above copyright notice appear in all copies and that Xboth that copyright notice and this permission notice appear in Xsupporting documentation, and that the name of the University of XToronto not be used in advertising or publicity pertaining to Xdistribution of the software without specific, written prior Xpermission. The University of Toronto makes no representations about Xthe suitability of this software for any purpose. It is provided "as Xis" without express or implied warranty. X XTHE UNIVERSITY OF TORONTO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS XSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS. IN NO EVENT SHALL THE UNIVERSITY OF TORONTO BE LIABLE FOR ANY XSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER XRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF XCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN XCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X XHistorical note, added by Ian Darwin and Geoff Collyer in 1985: XWe found the source code for this program when cleaning up; it was Xoriginally written by Leslie Goldsmith, we think, while a graduate student. X XWe cannot undertake to provide bug fixes or further development, Xbut will gladly accept bug fixes and comments. X XIan F. Darwin (NOT THE PROGRAM AUTHOR) XUniversity of Toronto Computing Services Xutcs!ian X1985-07-24. X X(now ian at sq.com, still NOT THE PROGRAM AUTHOR, 1991-03-03. XNew-style copyright notice added to README.) @@@End of README echo x - rnotroff.1 1>&2 sed 's/^X//' >rnotroff.1 <<'@@@End of rnotroff.1' X.TH RNOTROFF 1 local X.ds ]W Unsupported X.SH NAME Xrnotroff \- convert DEC runoff input to n/troff input X.SH SYNOPSIS X.B rnotroff X.BR \- [ nt8 ] X[ X.B \-fok X] X[ X.BR \-v: var[,var...] X] X.SH DESCRIPTION X.I Runoff Xconverts input intended for Digital Equipment Corporation's runoff Xtext formatter into input for X.I nroff Xor X.IR troff . XThe output on stdout is a file suitable for formatting with X.I nroff Xor X.I troff Xdepending on whether it was invoked with the X.BR \-n Xor X.BR \-t Xoption. XThus X.I rnotroff Xmay be used as part of a pipeline, Xalthough it is probably simpler to convert your files once and for all using X.I rnotroff Xto make new files from old. XThe X.B \-f Xand X.B \-o Xoptions are passed directly on to the text formatter. XThe X.B \-k Xoption kills the formatter on detection of any error. XThe X.B \-v Xoption sets runoff ``variants''. X.SH FILES X/usr/misc/lib/*runoffmacros, -m*runoff troff macro packages needed by runoff output X.SH SEE ALSO Xtroff(1) X.br XThe DEC runoff manuals X.SH HISTORY XA predecessor of this program was written at the University of Toronto Xby Leslie Goldsmith for the Document Preparation Service on \s-2PWB/UNIX\s0. XPorted to Seventh Edition UNIX, and then 4.2BSD, by Geoff Collyer, utcs!geoff. XSimplified into present form by Ian Darwin, utcs!ian. X.SH BUGS XThis program does not handle the \s-2RUNOFF\s0 `indexing capability'; Xwe used to have X.I runoff , Xa program that did the same conversion but also ran the Xformatter and the index post-processor. XIt was very complicated; the post-processing was an integral part of X.IR runoff . XThe use of pipes and processes was, um, quite something to behold. XWe consider it better to convert completely to X.I nroff Xand be done with it. X.PP XThe number of Runoff versions and variations rivals the number Xof UNIX tty drivers; it is not possible for X.I rnotroff Xto handle them all, so it understands the version in use at our site. X.PP XThere remain some places where the code could be modernised Xor cleaned up. @@@End of rnotroff.1 echo x - rnotroff.c 1>&2 sed 's/^X//' >rnotroff.c <<'@@@End of rnotroff.c' X/* X * DEC runoff to troff converter X */ X X#include X#include X#include X X#define STDIN 0 /* standard input file descriptor */ X#define STDOUT 1 /* standard output file descriptor */ X#define STDERR 2 /* standard diagnostic output file descriptor */ X X#define T_NROFF 0 X#define T_TROFF 1 X X/* Sundry defines */ X X#define EOL 0376 /* must fit in a char */ X#define MAXLEN 1000 X#define MAXCMD 256 X#define CMASK 0377 /* for making chars positive */ X#define HIGH_VALUE 2147483647L /* highest value for long integers */ X X#define NROFF "/usr/bin/nroff" X#define TROFF "/usr/bin/troff" X X X/* Flag settings for command table */ X X#define ALIAS 01 /* cmd name is an alias abbreviation */ X#define ENTRY 02 /* full entry for cmd in table */ X#define SIMPLE 04 /* cmd requires simple text substitution */ X#define DIRARG 010 /* cmd requires simple text substitution + X * arg translation; arg position is denoted X * by ^ in the output sequence */ X#define NODELIM 020 /* arg is LETTERS & is not separated from X * the cmd name by any special delimiter */ X#define LASTCMD 040 /* cmd must be last on input line; X * remainder of line is taken as arg */ X#define NUARG 0100 /* cmd takes numeric args, default units to be inserted */ X Xstatic int unstdin; X Xint appendix(); Xint autoparagraph(); Xint autotable(); Xint centre(); Xint chapter(); Xint doindex(); Xint endfooting(); Xint endftnote(); Xint endkeeptogether(); Xint endlist(); Xint endliteral(); Xint endnote(); Xint endsubtitle(); Xint endtitle(); Xint figure(); Xint fill(); Xint flagindex(); Xint footing(); Xint footnote(); Xint headerlevel(); Xint mkindex(); Xint keeptogether(); Xint leftmargin(); Xint list(); Xint listelement(); Xint literal(); Xint nofill(); Xint nopaging(); Xint note(); Xint numberlevel(); Xint numblist(); Xint paging(); Xint paragraph(); Xint pagesize(); Xint printindex(); Xint rightmargin(); Xint right(); Xint skip(); Xint spacing(); Xint subindex(); Xint subtitle(); Xint tabstops(); Xint title(); Xint typeset(); Xint varelse(); Xint varend(); Xint variable(); Xint varif(); Xint varifnot(); X Xstruct command { X char *cmdname; X int flags; X int (*docmd)(); /* used iff ~(SIMPLE|DIRARG|ALIAS) */ X char *outseq; /* used iff SIMPLE|DIRARG|ALIAS */ X} cmdtab[] = { X "AP", ALIAS, NULL, "AUTOPARAGRAPH", X "APPENDIX", NODELIM | ENTRY | LASTCMD, appendix, NULL, X "AT", ALIAS, NULL, "AUTOTABLE", X "AUTOPARAGRAPH", ENTRY, autoparagraph, NULL, X "AUTOTABLE", ENTRY, autotable, NULL, X "AX", ALIAS | NODELIM, NULL, "APPENDIX", X "B", ALIAS, NULL, "BLANK", X "BB", ALIAS, NULL, "BEGIN BAR", X "BEGIN BAR", ENTRY | SIMPLE, NULL, ".if \\n(BA .mc \\(br 1m", X "BLANK", ENTRY | DIRARG | NUARG, NULL, ".sp ^", X "BR", ALIAS, NULL, "BREAK", X "BREAK", ENTRY | SIMPLE, NULL, ".br", X "C", ALIAS, NULL, "CENTRE", X "CENTER", ALIAS, NULL, "CENTRE", X "CENTRE", ENTRY | NUARG, centre, NULL, X "CH", ALIAS | NODELIM, NULL, "CHAPTER", X "CHAPTER", NODELIM | ENTRY | LASTCMD, chapter, NULL, X "DBB", ALIAS, NULL, "DISABLE BAR", X "DISABLE BAR", ENTRY | SIMPLE, NULL, ".nr BA 0", X "DO INDEX", ENTRY, doindex, NULL, X "DX", ALIAS, NULL, "DO INDEX", X "EB", ALIAS, NULL, "END BAR", X "EBB", ALIAS, NULL, "ENABLE BAR", X "EF", ALIAS, NULL, "END FOOTING", X "EI", ALIAS | NODELIM, NULL, "ENDIF", X "EKT", ALIAS, NULL, "END KEEP TOGETHER", X "EL", ALIAS, NULL, "END LITERAL", X "ELS", ALIAS, NULL, "END LIST", X "ELSE", ENTRY | NODELIM, varelse, NULL, X "EN", ALIAS, NULL, "END NOTE", X "ENABLE BAR", ENTRY | SIMPLE, NULL, ".nr BA 1", X "END BAR", ENTRY | SIMPLE, NULL, ".if \\n(BA .mc", X "END FOOTING", ENTRY, endfooting, NULL, X "END FOOTNOTE", ENTRY, endftnote, NULL, X "END KEEP TOGETHER", ENTRY, endkeeptogether, NULL, X "END LIST", ENTRY, endlist, NULL, X "END LITERAL", ENTRY, endliteral, NULL, X "END NOTE", ENTRY, endnote, NULL, X "END SUBTITLE", ENTRY, endsubtitle, NULL, X "END TITLE", ENTRY, endtitle, NULL, X "ENDIF", ENTRY | NODELIM, varend, NULL, X "EST", ALIAS, NULL, "END SUBTITLE", X "ET", ALIAS, NULL, "END TITLE", X "F", ALIAS, NULL, "FILL", X "FG", ALIAS | NODELIM, NULL, "FIGURE", X "FIGURE", ENTRY | NODELIM | NUARG, figure, NULL, X "FILL", ENTRY, fill, NULL, X "FIRST TITLE", ENTRY | SIMPLE, NULL, ".nr FT 1", X "FLAG INDEX", ENTRY, flagindex, NULL, X "FN", ALIAS, NULL, "FOOTNOTE", X "FOOTING", ENTRY | NODELIM | LASTCMD, footing, NULL, X "FOOTNOTE", ENTRY, footnote, NULL, X "FT", ALIAS, NULL, "FIRST TITLE", X "FTG", ALIAS | NODELIM, NULL, "FOOTING", X "HD", ALIAS | NODELIM, NULL, "HEADER", X "HEADER", ENTRY | SIMPLE, NULL, ".nr HD 1\n.ds PA Page\n", X "HEADER LEVEL", ENTRY | LASTCMD, headerlevel, NULL, X "HEADER LOWER", ENTRY | SIMPLE, NULL, ".nr HD 1\n.ds PA page\n", X "HEADER MIXED", ENTRY | SIMPLE, NULL, ".nr HD 1\n.ds PA Page \n", X "HEADER UPPER", ENTRY | SIMPLE, NULL, ".nr HD 1\n.ds PA PAGE\n", X "HL", ALIAS | LASTCMD, NULL, "HEADER LEVEL", X "I", ALIAS, NULL, "INDENT", X "IF", ENTRY | NODELIM, varif, NULL, X "IFNOT", ENTRY | NODELIM, varifnot, NULL, X "IN", ALIAS | NODELIM, NULL, "IFNOT", X "INDENT", ENTRY | DIRARG | NUARG, NULL, ".ti ^", X "INDEX", ENTRY | LASTCMD | NODELIM, mkindex, NULL, X "J", ALIAS, NULL, "JUSTIFY", X "JUSTIFY", ENTRY | SIMPLE, NULL, ".ad", X "KEEP TOGETHER", ENTRY, keeptogether, NULL, X "KT", ALIAS, NULL, "KEEP TOGETHER", X "L", ALIAS, NULL, "LEFT", X "LE", ALIAS, NULL, "LIST ELEMENT", X "LEFT", ENTRY | DIRARG | NUARG, NULL, ".ti ^", X "LEFT MARGIN", ENTRY | NUARG, leftmargin, NULL, X "LIST", ENTRY | NUARG, list, NULL, X "LIST ELEMENT", ENTRY, listelement, NULL, X "LITERAL", ENTRY, literal, NULL, X "LM", ALIAS, NULL, "LEFT MARGIN", X "LS", ALIAS, NULL, "LIST", X "LT", ALIAS, NULL, "LITERAL", X "NAP", ALIAS, NULL, "NO AUTOPARAGRAPH", X "NAT", ALIAS, NULL, "NO AUTOTABLE", X "NF", ALIAS, NULL, "NOFILL", X "NHD", ALIAS, NULL, "NO HEADER", X "NJ", ALIAS, NULL, "NOJUSTIFY", X "NM", ALIAS, NULL, "NUMBER PAGE", X "NNM", ALIAS, NULL, "NO NUMBER", X "NO AUTOPARAGRAPH", ENTRY, autoparagraph, NULL, X "NO AUTOTABLE", ENTRY, autotable, NULL, X "NO FILL", ALIAS, NULL, "NOFILL", X "NO FOOTINGS", ENTRY | SIMPLE, NULL, ".NF 0 0", X "NO FOOTINGS EVEN", ENTRY | SIMPLE, NULL, ".NF 1 0", X "NO FOOTINGS ODD", ENTRY | SIMPLE, NULL, ".NF 0 1", X "NO HEADER", ENTRY | SIMPLE, NULL, ".nr HD 0", X "NO JUSTIFY", ALIAS, NULL, "NOJUSTIFY", X "NO NUMBER", ENTRY | SIMPLE, NULL, ".PN 0", X "NO PAGING", ENTRY, nopaging, NULL, X "NO SUBTITLES", ENTRY | SIMPLE, NULL, ".NS 0 0", X "NO SUBTITLES EVEN", ENTRY | SIMPLE, NULL, ".NS 1 0", X "NO SUBTITLES ODD", ENTRY | SIMPLE, NULL, ".NS 0 1", X "NO TITLES", ENTRY | SIMPLE, NULL, ".NT 0 0", X "NO TITLES EVEN", ENTRY | SIMPLE, NULL, ".NT 1 0", X "NO TITLES ODD", ENTRY | SIMPLE, NULL, ".NT 0 1", X "NOFILL", ENTRY, nofill, NULL, X "NOJUSTIFY", ENTRY | SIMPLE, NULL, ".na", X "NONUMBER", ALIAS, NULL, "NO NUMBER", X "NOTE", ENTRY | NODELIM | LASTCMD, note, NULL, X "NPA", ALIAS, NULL, "NO PAGING", X "NST", ALIAS, NULL, "NO SUBTITLES", X "NSTE", ALIAS, NULL, "NO SUBTITLES EVEN", X "NSTO", ALIAS, NULL, "NO SUBTITLES ODD", X "NT", ALIAS | NODELIM, NULL, "NOTE", X "NTL", ALIAS, NULL, "NO TITLES", X "NTLE", ALIAS, NULL, "NO TITLES EVEN", X "NTLO", ALIAS, NULL, "NO TITLES ODD", X "NUMBER", ALIAS, NULL, "NUMBER PAGE", X "NUMBER APPENDIX", ENTRY | DIRARG, NULL, ".nr ap ^", X "NUMBER CHAPTER", ENTRY | DIRARG, NULL, ".nr cn ^", X "NUMBER LEVEL", ENTRY, numberlevel, NULL, X "NUMBER LIST", ENTRY, numblist, NULL, X "NUMBER PAGE", ENTRY | DIRARG, NULL, ".PN ^", X "P", ALIAS, NULL, "PARAGRAPH", X "PA", ALIAS, NULL, "PAGING", X "PAGE", ENTRY | SIMPLE, NULL, ".sp \\n(.tu", X "PAGE SIZE", ENTRY | NUARG, pagesize, NULL, X "PAGING", ENTRY, paging, NULL, X "PAPER SIZE", ALIAS, NULL, "PAGE SIZE", X "PARAGRAPH", ENTRY | NUARG, paragraph, NULL, X "PG", ALIAS, NULL, "PAGE", X "PRINT INDEX", ENTRY, printindex, NULL, X "PS", ALIAS, NULL, "PAGE SIZE", X "PX", ALIAS, NULL, "PRINT INDEX", X "R", ALIAS, NULL, "RIGHT", X "RIGHT", ENTRY | NUARG, right, NULL, X "RIGHT MARGIN", ENTRY | NUARG, rightmargin, NULL, X "RM", ALIAS, NULL, "RIGHT MARGIN", X "S", ALIAS, NULL, "SKIP", X "SK", ALIAS, NULL, "SKIP", X "SKIP", ENTRY, skip, NULL, X "SP", ALIAS, NULL, "SPACING", X "SPACING", ENTRY, spacing, NULL, X "ST", ALIAS | NODELIM, NULL, "SUBTITLE", X "SUBINDEX", ENTRY | NODELIM | LASTCMD, subindex, NULL, X "SUBTITLE", ENTRY | NODELIM | LASTCMD, subtitle, NULL, X "T", ALIAS | NODELIM, NULL, "TITLE", X "TAB STOPS", ENTRY | NUARG, tabstops, NULL, X "TEST PAGE", ENTRY | DIRARG | NUARG, NULL, ".br\n.ne ^", X "TITLE", ENTRY | NODELIM | LASTCMD, title, NULL, X "TP", ALIAS, NULL, "TEST PAGE", X "TS", ALIAS, NULL, "TAB STOPS", X "TY", ALIAS | NODELIM, NULL, "TYPESET", X "TYPESET", ENTRY | NODELIM, typeset, NULL, X "VARIABLE", ENTRY | NODELIM, variable, NULL, X "VR", ALIAS | NODELIM, NULL, "VARIABLE", X "X", ALIAS | NODELIM, NULL, "SUBINDEX", X}; X X#define CMDCNT (sizeof cmdtab/sizeof cmdtab[0]) X Xchar *progname; Xint tproc = T_NROFF; /* text processor */ Xint ipmp[2]; /* file descriptors for pipes */ Xint nvar = 0; /* number of variants encountered */ Xint debug = 0; /* TRACE flag */ Xint killer = 0; /* flag to indicate no output on error */ Xint tprocid = 0; /* process is'd used ... */ Xint iprocid = 0; /* ... for killing tasks */ Xint subtproc(); Xchar *varlist[30]; /* array of pointers to variant names */ X Xmain(argc, argv) /* runoff converter -- main program */ Xint argc; Xchar *argv[]; X{ X char *w; X int c, errflg = 0; X extern char *optarg; X extern int optind; X X nvar = 0; X progname = argv[0]; X while ((c = getopt(argc, argv, "dntv:")) != EOF) X switch (c) { X case 'd': /* debug flag */ X ++debug; X break; X case 'n': /* text processor is nroff */ X tproc = T_NROFF; X break; X case 't': /* text processor is troff */ X tproc = T_TROFF; X break; X case 'v': /* variant selection specification */ X if (nvar == 0) { X w = optarg; X if (*w != ':') X fprintf(stderr, X "command line: ':' expected but %c found\n", X *w); X varlist[nvar++] = w+1; X while (*++w != '\0') X if (*w == ',') { X *w = '\0'; X varlist[nvar++] = w+1; X } X } X break; X default: X errflg++; X break; X } X if (optind < argc || errflg) X error("usage: %s -[nt] [-v:v1,v2...]\n", progname); X /* X arguments now validated. X */ X mainproc(); /* off we go... */ X exit(0); X} X X#define SAMEENT 1 X#define DIFFENT 0 X#define SUBIND 1 X#define IND 2 X#define MAXENT 500 X Xstatic char *startsig = "*|->"; Xstatic char *sortfile; X X X X X/* Settings for */ X X#define MIXED 0 X#define LOWER 1 X#define UPPER 2 X X X/* Settings for */ X X/* 1 */ X#define HDTITLE 2 X#define KEEPTOGETHER 3 X#define TITLE 4 X#define FOOTNOTE 5 X#define FOOTING 6 X#define SUBTITLE 7 X#define LITERAL 8 X X X/* Surrogate characters in input text */ X X#define UNDERSCORE '_' X#define POUNDSIGN '#' X#define AMPERSAND '&' X#define BACKSLASH '\\' X#define QUOTE '\'' X#define INDEXFLAG '>' X#define CAP '^' X#define COMMAND '.' X#define ENDFTNOTE '!' X X X/* Settings for */ X X#define NOTRAP 0 X#define CENTRE 1 X Xstatic char buf[MAXLEN]; Xstatic char curcmd[MAXCMD], curarg[MAXCMD]; Xstatic char vstack[50][15]; /* stores the variant stack in IF, IFNOT, ELSE cmds */ Xstatic int stackptr = 0; Xstatic int ELstack[50]; /* flags to indicate whether an .el is needed at ENDIF */ Xstatic int bufptr; Xstatic int chapnum = 0; /* flag chapter number */ Xstatic int inlines = 0; /* input line counter for diagnostic output */ Xint iscmd; /* current input line is a command */ Xint lastcase; Xint case_lock = MIXED; /* default typefont case */ Xint trap_lines = -1; /* input line counter for conversion trap, triggered when 0 */ Xint trap_type = 0; /* type of trap triggered when becomes 0 */ Xint format_trap = 0; /* trap for text formating commands */ Xint auto_flag = 0; /* default flag for AUTOPARAGRAPH and AUTOTABLE */ Xint last_flag = 0; /* memory flag when auto mode is temporarily turned off */ Xint kauto = 0; /* memory flag when going into keeptogether mode */ Xint klast = 0; /* memory flag when going into keeptogether mode */ Xint kmode = 0; /* memory flag when going into keeptogether mode */ Xdouble auto_indent = 5; /* default indent for AUTOPARAGRAPH and AUTOTABLE */ Xdouble auto_spacing = 1; /* default spacing for same */ Xdouble auto_testpage = 0; /* default test page parameter for same */ Xchar auto_tu = 'P'; /* units for auto_testpage */ Xchar auto_su = 'P'; /* unit for auto_spacing */ Xchar auto_iu = 'P'; /* unit for auto_indent */ Xint notenest = 0; /* indicate nesting level of NOTE */ Xint listnest = 0; /* indicate nesting level of LISTS */ Xint contdoline = 1; /* indicate continuing of doline routine */ Xint level[5] = { 0, 0, 0, 0, 0 }; /* counters for header levels */ Xint LEcount[5] = { 1, 1, 1, 1, 1 }; /* counters for list elements */ Xdouble listspacing[5] = { 1., 1., 1., 1., 1. }; /* Spacing for lists */ Xchar list_su[5] = { 'i', 'i', 'i', 'i', 'i' }; /* List spacing units */ Xint fillmode = 1; /* indicate fill mode */ Xint indexflag = 0; /* indicate if index is to be kept */ Xint altarg = 0; /* indicate if alternate measurement unit is user supplied */ Xdouble convert(); Xdouble cfactor = 240; /* conversion factor to basic units */ Xdouble Csize = 20; /* conversion factor C to basic units */ Xdouble Psize = 10; /* default point size */ Xdouble Vsize = 12; /* default vertical line space */ Xdouble height = 5.8; /* default, in inches */ Xdouble width = 6.0; /* default, in inches */ Xchar hu = 'i'; /* default units for height */ Xchar wu = 'i'; /* default units for width */ X X/* NOTE: If you change the page size defaults, X * remember to change macro initialisation as well! */ X Xmainproc() /* main conversion processor */ X{ X#ifdef LOCAL X kprintf(".so runoffmacros\n"); X#else X /* initialisation and conversion macros */ X#ifdef DEFAULTVERSION X kprintf(".so /usr/misc/lib/runoffmacros\n"); X#else X kprintf(".so /usr/misc/lib/nrunoffmacros\n"); X#endif X#endif /* LOCAL */ X unstdin = ipmp[0]; /* pipe input becomes unstdin */ X if (tproc != T_NROFF) X cfactor = 432; X while (getline(buf, MAXLEN) > 0) X doline(buf, iscmd); X} X X/* X * Convert a single line of input text. X * If is negative, then this is a special call from a command conversion X * routine. In particular, the buffer for such calls is terminated by a '\0' X * rather than by EOL. X */ Xdoline(bufp, arg) Xregister char bufp[MAXLEN]; Xint arg; X{ X register int c, ch; X int bufpsave; X int eol; X int eolok = 1; X int newline; /* on if next char is start of a logical line */ X int newlflag; /* next setting of */ X int index; X char *dirarg; X char indexbuf[MAXLEN], *xptr; X X if (debug) X fprintf(stderr, "entering doline\n"); /* TRACE */ X bufptr = 0; /*** reset bufptr, for command conversion subroutines ***/ X newline = trap_type != LITERAL; /* never on if LITERAL mode */ X if (arg < 0) { X eol = '\0'; X iscmd = 0; X while ((c = getch(bufp, 0)) == ' ' || c == '\t') X ; /* get rid of leading blanks */ X --bufptr; /* save the non-blank character */ X } X else { X eol = EOL; X if (bufp[bufptr] == ENDFTNOTE && trap_type == FOOTNOTE) { X endftnote(); X getarg(0, 0, curarg); X } X } X while ((c = getch(bufp, 0)) != eol && eolok && contdoline) { X newlflag = 0; X switch (c) { X case UNDERSCORE: /* treat next character as text */ X if (eolok = (ch = getch(bufp, 0)) != eol) X if (ch == '\\') X kprintf("\\&\\\\\\&"); X else X kprintf("\\&%c", ch); X break; X case POUNDSIGN: /* unexpandable space */ X kprintf("\\ "); X break; X case AMPERSAND: /* underline next character */ X if (eolok = (ch = getch(bufp, 0)) != eol) { X kprintf("\\fI"); X kprintf("%c", ch); X kprintf("\\fR"); X } X break; X case CAP: /* ^ next character upper case X ^^ upper case lock X ^\ mixed case lock X ^& underline lock */ X if (eolok = (ch = getch(bufp, 0)) != eol) X switch (ch) { X case CAP: /* upper case lock */ X case_lock = UPPER; X break; X case BACKSLASH: /* mixed case lock */ X case_lock = MIXED; X break; X case AMPERSAND: /* underline lock */ X kprintf("\\fI"); X break; X default: /* next character upper case */ X kprintf("%c", upper(ch)); X break; X } X break; X case BACKSLASH: /* \ next character lower case X \\ lower case lock X \^ mixed case lock X \& underline lock off */ X if (eolok = (ch = getch(bufp, 0)) != eol) X switch (ch) { X case BACKSLASH: /* lower case lock */ X case_lock = LOWER; X break; X case CAP: /* mixed case lock */ X case_lock = MIXED; X break; X case AMPERSAND: /* underline lock off */ X kprintf("\\fR"); X break; X default: /* next character lower case */ X kprintf("%c", lower(ch)); X break; X } X break; X case QUOTE: /* single quote mark */ X /* escape it in case it is at the start of a line */ X kprintf("\\&'"); X break; X case INDEXFLAG: /* next char index entry */ X if (indexflag) { X for (xptr = indexbuf; *xptr = getch(bufp, 0), X (!isascii(*xptr) || !isspace(*xptr)) && X *xptr != '\n'; xptr++) X kprintf("%c", *xptr); X *xptr = '\0'; X kprintf("\n.ds IE ~%s\n.IN\n", indexbuf); X } X else X /* flag not enabled; treat character as text */ X kprintf("%c", c); X break; X case COMMAND: /* format command line */ X if (iscmd) { X /* save in case command is suppressed */ X bufpsave = bufptr; X index = getcmd(curcmd); /* get current command */ X if (trap_type == LITERAL) X if ( X#ifdef CHKINDEX X /* Although this makes sense, it breaks error printing. */ X index >= 0 && X#endif X strlcmp(-1, cmdtab[index].cmdname, X "END LITERAL") != 0) { X iscmd = 0; /* ignore this cmd */ X /* and restore bufptr */ X bufptr = bufpsave; X } X if (iscmd) { X#ifdef CHKINDEX X /* Although this makes sense, it breaks error printing. */ X if (index >= 0) X#endif X getarg(cmdtab[index].flags&LASTCMD, X cmdtab[index].flags&NUARG, X curarg); /* and any arg */ X if (debug) X fprintf(stderr, X "command: %s^argument: %s^", X curcmd, curarg); /* TRACE */ X if (index < 0) { X diagnosline(); X fprintf(stderr, X "command not recognized: %s %s\n" X , curcmd, curarg); X } X else if (cmdtab[index].flags&SIMPLE) { X kprintf(cmdtab[index].outseq); X kprintf("\n"); X } X else if (cmdtab[index].flags&DIRARG) { X dirarg = cmdtab[index].outseq; X while ((c = *dirarg++) != '^') X /* this char precedes the arg. */ X kprintf("%c", c); X kprintf("%s%s\n", curarg, dirarg); X } X else /* call command function */ X (*cmdtab[index].docmd)(); X /* more input may follow command */ X newlflag = 1; X break; X } X } X /* else it's just an ordinary period; treat it as default */ X kprintf("\\&"); /* deactivate the period */ X default: X if (newline) X if (auto_flag == (isascii(c) && isspace(c)? 1: -1) && X trap_type < 4) { X if (auto_flag == -1) /*Autotable */ X --bufptr; X emitauto(); /* AUTOPARAGRAPH and AUTOTABLE */ X /* get 1st real (non-blank) char */ X break; X } X if (case_lock == LOWER) X c = lower(c); X else if (case_lock == UPPER) X c = upper(c); X kprintf("%c", c); X break; X } X newline = newlflag; /* isn't this just great? */ X } X checktrap(); /* check for possible input trap after this line */ X if (eolok != 1) { X diagnosline(); X fprintf(stderr, "unexpected end-of-line, continuing\n"); X } X contdoline = 1; X} X X X X/* check the variant list to see if var is in selected list */ Xvcheck(var) Xchar *var; X{ X int i = 0; X X while (i < nvar) X if (strlcmp(-1, varlist[i++], var) == 0) X return 1; X return 0; X} X Xlower(c) /* convert to lower case if it was upper case; ASCII only */ Xregister int c; X{ X return (isascii(c) && isupper(c))? tolower(c): c; X} X Xupper(c) /* convert to upper case if it was lower case; ASCII only */ Xregister int c; X{ X return (isascii(c) && islower(c))? toupper(c): c; X} X Xstrlcmp(len, i, j) /* logical comparison of string i vs. string j for len chars X (or all chars if len is -1) */ Xchar *i, *j; Xint len; X{ X for (; *i == *j; i++, j++) X if (--len == 0 || *i == '\0') X return 0; X return *i - *j; X} X Xdouble Xconvert(arg, unit) /* convert argument in some unit to basic units */ Xdouble arg; Xchar unit; X{ X switch (unit) { X case 'i': /* inches */ X return arg*cfactor; X case 'c': /* centimetres */ X return arg*cfactor*0.39; X case 'P': /* Picas */ X return arg*cfactor/6; X case 'm': /* ems */ X if (tproc != T_NROFF) X return arg*6*Psize; X else X return arg*Csize; X case 'n': /* ens */ X if (tproc != T_NROFF) X return arg*3*Vsize; X else X return arg*Csize; X case 'p': /* points */ X if (tproc != T_NROFF) X return 6*arg; X else X return 3.4*arg; X case 'v': /* Vs */ X return arg*Vsize; X case 'u': /* basic units */ X return arg; X default: /* unrecognized unit character */ X diagnosline(); X fprintf(stderr, "unrecognized units, use: i,c,P,m,n,p,u,v\n"); X return HIGH_VALUE; X } X} X X/* X * Lookup command name in table; return index of row or -1 if no match. X * If is -1, the command name is assumed to be terminated by a '\0'; X * otherwise, the search terminates after the first characters X * and only commands with the NODELIM bit set are considered. X */ Xlookup(len, cmd) Xint len; Xchar *cmd; X{ X int low, high, mid, comp; X int cmdlen; X X low = 0; X high = CMDCNT-1; X while (low <= high) { X mid = (low+high)/2; X if ((comp = strlcmp(len, cmd, cmdtab[mid].cmdname)) < 0) X high = mid-1; X else if (comp > 0) X low = mid+1; X else { X if (len == -1 || cmdtab[mid].flags&NODELIM && X (cmdlen = strlen(cmdtab[mid].cmdname)) == len) { X /* found it; find full entry in command table */ X if (cmdtab[mid].flags&ALIAS) X if ((mid = lookup(-1, X cmdtab[mid].outseq)) < 0) X error( X "fatal error in command table\n", X (char *) 0); X return mid; X } X else if (cmdlen > len) X high = mid-1; X else { X /* lengths must be equal but NODELIM was off. */ X if (cmdtab[mid].flags&NODELIM) X /* should never get here */ X fprintf(stderr, X "internal error in command table\n"); X else X return -1; X } X } X } X return -1; /* command not found */ X} X Xerror(s1, s2) /* print error message and terminate */ Xchar *s1, *s2; X{ X diagnosline(); X if (s2 == 0) X fprintf(stderr, s1); X else X fprintf(stderr, s1, s2); X exit(1); /* signal abnormal exit */ X} X X/* move arg. to current cmd in to desired location for processing */ Xgetarg(last, nuarg, w) Xchar *w; Xint last, nuarg; X{ X char *p; X int c; X int numflag = 0; /* flag numeric character presence in argument */ X int lim = MAXCMD; X int parity = 0; /* cumulative parity of quotes on the line */ X X altarg = 0; X /* X * The end of a command is generally designated by the first X * occurrence of ! . ; that is not within quotes, or a newline. X * If is set, however, then this is the last command X * on the line, and the only possible argument terminator is newline. X */ X p = w; X while (--lim > 0) { X /* i.e. modulo 2 addition */ X parity = parity != ((c = getch(buf, 0)) == '"'); X if (nuarg) { X if (isascii(c) && isdigit(c)) { X /* X * once a digit is scanned numflag is set X * so that at the end of the number, X * a unit can be added. X */ X numflag = 1; X *p++ = c; X } X else { X if (numflag) { X /* default units are inches/10 */ X (void) sprintf(p-1, ".%ci%c", *(p-1), c); X p += 3; X numflag = 0; X } X else X *p++ = c; X } X } X else if (c == UNDERSCORE) /* next character is escaped */ X /* ignore escape character and get following one */ X *p++ = getch(buf, 0); X else X *p++ = c; X if (!((parity || last || c != '!' && c != '.' && c != ';') && X c != '\n')) X break; X } X if (c == '.') X --bufptr; /* restore indication of subsequent command */ X if (c == '!') { /* comment follows current command argument */ X /* check for alternate unit measurements */ X if ((c = getch(buf, 0)) == '<') { X altarg = 1; X p = w; /* reassign curarg */ X while (--lim > 0 && (c = *p++ = getch(buf, 0)) != '>' && X c != '\n' && c != ';') X ; X if (getch(buf, 0) != '\n') X --bufptr; /* remove CR if it is there */ X } X else { X --bufptr; X while (--lim > 0 && (c = getch(buf, 0)) != ';' && c != '\n') X ; X } X } X if (lim <= 0) { /* line was too long and was truncated */ X diagnosline(); X fprintf(stderr, "command line too long, truncated\n"); X } X if (c == ';') X if ((c = buf[bufptr]) != COMMAND) X iscmd = 0; /* text follows */ X *(p-1) = '\0'; X} X X/* X * is 1 if we are treating text sequentially, so that the occurrence X * of a newline character causes us to fetch the next line of text. otherwise, X * the flag is 0. X */ Xgetch(bufp, eolflag) Xregister char bufp[MAXLEN]; Xint eolflag; X{ X register int c; X X while ((c = bufp[bufptr++]&CMASK) == EOL && eolflag) X (void) getline(bufp, MAXLEN); X return c == (EOF&CMASK)? EOL: c; X} X Xgetline(bufp, lim) /* get next line of input and reset cursor position */ Xregister char *bufp; Xint lim; X{ X int c, i, len; X X do { X for (len = 0; --lim > 0 && (c = getchar()) != EOF && c != '\n'; X len++) X bufp[len] = c; X if (c == '\n') X bufp[len++] = c; /* preserve carriage returns */ X bufp[len] = (c == EOF? EOF: EOL); X ++inlines; X /* ignore blank lines if not LITERAL */ X } while (bufp[0] == '\n' && trap_type != LITERAL); X iscmd = bufp[bufptr = 0] == COMMAND && X (trap_type != LITERAL || trap_lines < 0); X if (iscmd == 0) X --trap_lines; /* decrement input line counter if not a command */ X if (debug) { X fprintf(stderr, "getline: "); X for (i = 0; i < len; i++) X fprintf(stderr, "%c", bufp[i]); X fprintf(stderr, "^ len=%d\n", len); X } /* TRACE */ X return len; /* return current length of buffer as result */ X} X X/* X * Move command in to argument for processing, X * and find its index in the table. X * The command name is terminated by the first non-blank non-letter character. X * Multiple blanks separating multi-word command names are squeezed out. X */ Xgetcmd(w) Xchar *w; X{ X char *cmd = w; X int c, index = -1; X int lim = MAXCMD; X X while (--lim > 0) { X if (0 == isalpha(c = *w++ = getch(buf, 0))) { X if (c == ' ') { X if ((index = lookup(w-cmd-1, cmd)) >= 0) X /* command found; rest of line is argument */ X break; X if (*(w-2) == ' ') X --w; /* ignore consecutive blanks in input*/ X } X else { X --bufptr; X break; X } X } X else X *(w-1) = upper(c); X } X if (*(w-2) == ' ') X --w; X *(w-1) = '\0'; X if (index < 0) X index = lookup(-1, cmd); X X /* If NODELIM type commands are followed by a ';', it should be X * ignored. X */ X X if (index >= 0) X if ((cmdtab[index].flags&NODELIM) && buf[bufptr] == ';') X (void) getch(buf, 0); X return index; X} X X/* Killable printf */ X/* VARARGS1 */ Xkprintf(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) Xchar *fmt, *a0, *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10, *a11, *a12; X{ X if (killer != -1) X printf(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, X a10, a11, a12); X} X Xtransfer(fd1, fd2) /* direct transfer from file descriptor 1 to fd2 */ Xregister int fd1, fd2; X{ X char tbuf[BUFSIZ]; X register int n; X X (void) fflush(stderr); X while ((n = read(fd1, tbuf, BUFSIZ)) > 0) X (void) write(fd2, tbuf, n); X} X Xchecktrap() /* check for possible conversion trap on this input line */ X{ X if (trap_lines == 0) { /* if zero, there is something to do */ X switch (trap_type) { X case HDTITLE: /* complete header title format */ X kprintf("\n.sp\n"); X break; X case LITERAL: /* clean up after LITERAL command */ X kprintf(".RL\n"); /* invoke cleanup macro */ X break; X default: X error("fatal error -- no input trap found", (char *)NULL); X } X --trap_lines; /* make sure it's negative */ X trap_type = 0; /* and clear the trap type */ X } X X switch (format_trap) { X case NOTRAP: /* nothing to do */ X break; X case CENTRE: /* clean up, reset line length */ X kprintf(".ll\n"); X break; X default: X diagnosline(); X error("fatal error -- improper format trap found", (char *)NULL); X break; X } X format_trap = NOTRAP; X if (fillmode == 0 || trap_type >= 4) X /* RUNOFF NOFILL mode requires break after each line */ X kprintf(".br\n"); X} X Xcmdbad() /* print a message indicating the current command is invalid */ X{ X diagnosline(); X /* couldn't be much easier */ X fprintf(stderr, "invalid command: %s %s\n", curcmd, curarg); X} X X/* Command conversion subroutines. */ X/* These are invoked implicitly via command table references. */ X Xappendix() /* sets up new appendix */ X{ X case_lock = MIXED; X chapnum = 0; X if (*curarg != '\0') { /* title argument present */ X kprintf(".TT 0 1 1\n"); X doline(curarg, -1); X contdoline = 0; X kprintf("\n.RT\n"); X } X else X kprintf(".NT 0 0\n"); X kprintf(".NS 0 0 \n"); X kprintf(".AP\n"); /* set up appendix macro */ X} X X X Xautoparagraph() /* set flag for AUTOPARAGRAPH and NO AUTOPARAGRAPH */ X{ X auto_flag = curcmd[0] == 'A'; X} X X X Xautotable() /* set flag for AUTOTABLE and NO AUTOTABLE */ X{ X auto_flag = -(curcmd[0] == 'A'); X} X Xcentre() /* centre text string on this or subsequent line */ X{ X setlinelength(); X kprintf(".ce\n"); X format_trap = CENTRE; X if ((buf[bufptr]&CMASK) == EOL) /* no arg. text; text is next line */ X (void) getline(buf, MAXLEN); X iscmd = 0; X} X Xchapter() /* sets up new chapter */ X{ X case_lock = MIXED; X chapnum = 1; X if (*curarg != '\0') { /* title argument present */ X kprintf(".TT 0 1 1\n"); X doline(curarg, -1); X contdoline = 0; X kprintf("\n.RT\n"); X } X else X kprintf(".NT 0 0\n"); X kprintf(".NS 0 0\n"); X kprintf(".PN 2\n"); X kprintf(".CH \n"); X} X Xdiagnosline() /* puts out the current buf content during diagnostic output */ X{ X register int c; X int i; X X i = 0; X fprintf(stderr, "line %d: ", inlines); X while ((c = buf[i++]) != '\n' && c != '\0') X putc(c, stderr); X fprintf(stderr, ":***-> "); X if (killer) { /* -k option set and we just detected the first error X * so we kill child processes sob, sob..... X * and stop output to stdout */ X (void) fflush(stdout); X (void) close(STDOUT); X if (tprocid != 0) { /* avoid wiping us out if this is an early error */ X (void) kill(tprocid, SIGTERM); X (void) kill(iprocid, SIGTERM); X } X (void) unlink(sortfile); X killer = -1; X } X} X Xdoindex() /* puts out paginated index */ X{ X if (killer != -1) { X kprintf(".tm %s\n", startsig); X kprintf(".DX"); X (void) fflush(stdout); X transfer(unstdin, STDOUT); X kprintf(".RX\n"); /* reset formatting in effect before calling index */ X } X} X Xemitauto() /* emits a command sequence for paragraphing or tabling */ X{ X kprintf(".br\n.ti \\n(.iu+%.1f%c\n.sp %.1f%c\n", auto_indent, auto_iu, X auto_spacing, auto_su); X if (auto_testpage) /* optional third parameter */ X kprintf(".ne %.1f%c\n", auto_testpage, auto_tu); X while (isspace(getch(buf, 0))) X ; /* remove leading white space */ X --bufptr; X} X X X Xendfooting() /* end block of footing text */ X{ X if (trap_type == FOOTING) { X trap_type = 0; /*clear it */ X kprintf(".RF\n"); X } X else { X diagnosline(); X fprintf(stderr, "END FOOTING not preceded by FOOTING command\n"); X } X} X Xendftnote() /* end block of footnote */ X{ X if (trap_type != FOOTNOTE) { X diagnosline(); X fprintf(stderr, "END FOOTNOTE not preceded by FOOTNOTE command\n"); X } X else { X trap_type = 0; X case_lock = lastcase; X kprintf(".EF\n"); X } X} X X X Xendkeeptogether() /* reset mode at end of keeptogether text */ X{ X if (trap_type == KEEPTOGETHER) { X trap_type = 0; X kprintf(".EK\n"); X fillmode = kmode; X auto_flag = kauto; X last_flag = klast; X } X else { X diagnosline(); X fprintf(stderr, "END KEEP TOGETHER not preceded by KEEP TOGETHER\n"); X } X} X X X Xendlist() /* reset mode at end of list */ X{ X if (--listnest < 0) { X diagnosline(); X fprintf(stderr, "END LIST command not preceded by LIST command\n"); X listnest = 0; X } X else { X kprintf(".sp %.1f%c\n", listspacing[listnest], list_su[listnest]); X if (listnest == 0) X kprintf(".br\n.RD\n"); X else X kprintf(".in %dP+\\nIu\n", listnest*4 + 1); X } X} X X X Xendliteral() /* end block of literal text */ X{ X if (trap_type == LITERAL) { X trap_type = 0; /* clear trap type */ X kprintf(".RL\n"); /* invoke cleanup macro */ X } X else { X diagnosline(); X fprintf(stderr, "END LITERAL not preceded by LITERAL command\n"); X } X} X X X Xendnote() /* end note section */ X{ X if (--notenest < 0) { X diagnosline(); X fprintf(stderr, "END NOTE not preceded by NOTE command\n"); X notenest = 0; X } X else { X kprintf(".sp 2P\n.ll +15\n.in -15\n"); X if (notenest == 0) /* no more notes */ X kprintf(".nr -D 0\n"); X X } X} X X X Xendsubtitle() /* end block of subtitle text */ X{ X if (trap_type == SUBTITLE) { X trap_type = 0; /* clear trap*/ X kprintf(".RS\n"); /*clean up macro */ X } X else { X diagnosline(); X fprintf(stderr, "ENDSUBTITLE not preceded by SUBTITLE command"); X } X} X X X Xendtitle() /* end block of title text */ X{ X if (trap_type == TITLE) { X trap_type = 0; /* clear trap type */ X kprintf(".RT\n"); /* invoke cleanup macro */ X } X else { X diagnosline(); X fprintf(stderr, "END TITLE not preceded by TITLE command\n"); X } X} X X X Xfigure() /* convert figure command */ X{ X char c, *w; X X w = curarg; X while ((c = *w++) != '\0') X if (isdigit(c) || c == '.') /* check for digit or decimal point */ X break; X --w; X switch (upper(*curarg)) { X case 'T': /* put figure at top of next page */ X kprintf(".nr FG %s\n", w); X break; X case 'B': /* put figure at bottom of next page */ X kprintf(".ch TF -\\nBu-%s\n", w); X break; X case 'A': /* put figure at first available top or bottom */ X kprintf(".ie \\n(.tu<%s .nr FG %s\n.el .ch TF -(%s+\\nBu)\n", w, w, X w); X break; X default: /* include the case when arg is not specified */ X kprintf(".ie \\n(.tu<%s .nr FG %s\n.el .sp %s\n", w, w, w); X break; X } X} X X X Xfill() /* set mode for fill text */ X{ X if (fillmode == 0 && trap_type < 4) { X /* reset last mode before nofill mode was on */ X auto_flag = last_flag; X fillmode = 1; X } X kprintf(".ad b\n.ev 1\n.ad b\n.ev\n"); X} X Xflagindex() /* set mode for receiving index entries to be sorted in sortfile */ X{ X indexflag = 1; X} X X X Xfooting() /* set mode for footing text input */ X{ X char *w; X int even, odd; X X even = odd = 1; /*default footing on all pages */ X w = curarg; X if (0 == strlcmp(4, w, "EVEN")*strlcmp(4, w, "even")) { X odd = 0; X w += 4; X X } X else if (0 == strlcmp(3, w, "ODD")*strlcmp(3, w, "odd")) { X even = 0; X w += 3; X } X kprintf(".FF %d %d \n", odd, even); X if (*w == ' ' || *w == ';') X ++w; X setfooting(w); X} X X Xfootnote() /* set mode for footnotes */ X{ X if (trap_type == FOOTNOTE) { X diagnosline(); X fprintf(stderr, "footnote nesting not allowed, command ignored\n"); X } X else { X trap_type = FOOTNOTE; X lastcase = case_lock; X case_lock = MIXED; X kprintf(".SF\n"); X } X} X X X Xheaderlevel() /* set mode for specified header level */ X{ X char *w, c; X int i, j; X X w = curarg; X for (; ; ) { X if (*w++ != ' ') { X if (((c = *(w-1)) <= '5') && (c >= '1')) X i = c-'1'; X else { X diagnosline(); X fprintf(stderr, "header level not in range 1-5\n"); X } X break; X } X } X kprintf(".sp3\n.ne 3P\n"); X j = 0; X if (chapnum) X kprintf("\\n(CN."); X while (j < i) X kprintf("%d.", level[j++]); X kprintf("%d", ++level[i]); X if (i == 0 && chapnum == 0) /* if there is only 1 number, add .0 */ X kprintf(".0"); X kprintf(" "); X while (++i <= 4) X level[i] = 0; X /* return to doline to format header title */ X trap_type = HDTITLE; X trap_lines = 0; X doline(w, -1); X contdoline = 0; X} X Xmkindex() /* enter rest of command line into index entry */ X{ X kprintf(".ds IE ~%s\n.IN\n", curarg); X} X X X Xkeeptogether() /* set mode for keep together text */ X{ X if (trap_type) { X diagnosline(); X fprintf(stderr, X ".KT not allowed within text diverting commands, trap type: %d\n" X , trap_type); X } X else { X klast = last_flag; X kauto = auto_flag; X kmode = fillmode; X trap_type = KEEPTOGETHER; X kprintf(".br\n.DI\n.di KT\n"); X } X} X X X Xleftmargin() /* set left margin for all environments of the text processor */ X{ X kprintf(".in %s\n.ev 1\n.in %s\n.ev\n", curarg, curarg); X} X X X Xlist() /* set mode for start of list */ X{ X double listspc; X char su; /* units for listspc */ X X if (++listnest > 5) { X diagnosline(); X fprintf(stderr, X "listnesting too deep, only 5 levels allowed -- command ignored\n" X ); X --listnest; X } X else { X if (listnest == 1) X kprintf(".br\n.DI\n"); X kprintf(".in %dP+\\nIu\n", listnest*4 + 1); X if (sscanf(curarg, "%f%c", &listspc, &su) != EOF) { X listspacing[listnest-1] = listspc; X list_su[listnest-1] = su; X } X else { X listspacing[listnest-1] = auto_spacing; X list_su[listnest-1] = auto_su; X } X } X LEcount[listnest-1] = 1; X} X X X Xlistelement() /* format start of list element */ X{ X kprintf(".sp %.1f%c\n.ti -2P\n%d.\\h'|2P'\\c\n", listspacing[listnest-1], X list_su[listnest-1], LEcount[listnest-1]++); X} X X X Xliteral() /* set "leave-as-is" mode for LITERAL command */ X{ X int lines; X X if (trap_type) { X diagnosline(); X fprintf(stderr, "nested commands, LITERAL ignored\n"); X } X else { X trap_type = LITERAL; X if (sscanf(curarg, "%d", &lines) == 1) X trap_lines = lines; /* set trap line counter to arg */ X else X trap_lines = -1; X kprintf(".LT\n"); /* set proper mode */ X } X} X Xnofill() /* set proper mode for nofill output */ X{ X if (fillmode == 1 && trap_type < 4) { X fillmode = 0; X last_flag = auto_flag; X auto_flag = 0; X } X kprintf(".ad l\n.ev 1\n.ad l\n.ev\n"); X} X Xnopaging() /* stop pagination of output */ X{ X kprintf(".ch HD \\n(.p+10P\n.ch FO \\n(.p+10P\n.ch FB \\n(.p+10P\n"); X} X X X Xnote() /* set mode for printing note sections */ X{ X kprintf(".sp 2P\n"); X if (*curarg == '\0') /* no argument, use NOTE */ X kprintf(".ce\nNOTE\n"); X else X kprintf(".ce\n%s\n", curarg); X kprintf(".sp 1P\n.nr -D 1\n.ll -15\n.in +15\n"); X ++notenest; X} X X X X Xnumberlevel() /* change section numbers of header levels */ X{ X int argnum, temp[5]; X X argnum = sscanf(curarg, "%d ,%d ,%d ,%d ,%d", X &temp[0], &temp[1], &temp[2], &temp[3], &temp[4]); X while (--argnum >= 0) X level[argnum] = temp[argnum]-1; X} X Xnumblist() /* set list element counter as specified */ X{ X int lvl = listnest; X int count = -1; X X if (sscanf(curarg, "%d, %d", &lvl, &count) == EOF || count < 0) X cmdbad(); X else if (lvl <= 5 && lvl >= 1) X /* X * I know this looks wrong, but the DEC10 does it X * this way. The first parameter is ignored. X * Number list affects the current list only. X */ X LEcount[listnest-1] = count; X else { X diagnosline(); X fprintf(stderr, X "level of list element specified is out of range, ignored\n"); X } X} X X X Xpaging() /* set pagination of output into effect */ X{ X kprintf(".rm FN\n.nr FC 0\n.ch HD 0\n.ch FO \\nBu\n.ch FBu\\nBu\n"); X kprintf(".PN 1\n"); X} X X X Xpagesize() /* set PAGE SIZE parameters */ X{ X if (sscanf(curarg, "%f%c, %f%c", &height, &hu, &width, &wu) == EOF) X cmdbad(); X else if (convert(width, wu) > (tproc != T_NROFF? 3024: 4800) || X convert(height, hu) > (tproc != T_NROFF? 32400: 32640)) { X diagnosline(); X fprintf(stderr, X"oversized page size request: 75i x 7i in troff \n\t\t\t\t136i x 20i in nroff\n" X ); X } X else { X kprintf(".pl %.1f%c+11P\n.ll %.1f%c\n.lt \\n(.lu\n", X height, hu, width, wu); X kprintf(".ev 1\n.ll %.1f%c\n.lt %.1f%c\n.ev\n", X width, wu, width, wu); X } X} X Xparagraph() /* scan argument list for PARAGRAPH command */ X{ X double indent, paraspc, testpage; X char iu; /* units for indent */ X char su; /* units for paraspc */ X char tu; /* units for testpage */ X X testpage = auto_testpage; X paraspc = auto_spacing; X indent = auto_indent; X iu = auto_iu; X su = auto_su; X tu = auto_tu; X if (curarg[0] != '\0') /* command has arguments */ X if (sscanf(curarg, "%f%c, %f%c, %f%c", &indent, &iu, X ¶spc, &su, &testpage, &tu) != EOF) { X auto_indent = indent; X auto_spacing = paraspc; X auto_testpage = testpage; X auto_iu = iu; X auto_su = su; X auto_tu = tu; X } X emitauto(); X} X X X Xprintindex() /* put out continuous index, not paginated */ X{ X if (killer != -1) { X nopaging(); X kprintf(".tm %s\n", startsig); X kprintf(".DX"); X (void) fflush(stdout); X transfer(unstdin, STDOUT); X /** reset formatting in effect before index printout **/ X kprintf(".in \\nNu\n.nr X 0\n"); X kprintf(".if !(\\n(FU) .nf\n.nr FU 1\n"); X paging(); X } X} X X X Xright() /* set line length and adjustment mode for RIGHT command */ X{ X setlinelength(); X kprintf(".RI\n"); /* invoke macro to set adjustment mode */ X} X X X Xrightmargin() /* set right margins for all the environments of the text processor */ X{ X kprintf(".br\n.ll %s\n.lt %s\n.ev 1\n.ll %s\n.lt %s\n.ev\n", curarg, curarg, X curarg, curarg); X} X X Xsetfooting(w) /* input text for footing */ Xchar *w; X{ X if (*w != '\0') { /*text for footing on same line */ X doline(w, -1); X contdoline = 0; X kprintf("\n.RF\n"); X } X else X trap_type = FOOTING; X} X Xsetlinelength() /* set line length for CENTRE and RIGHT commands */ X{ X if (curarg[0] == '+' || curarg[0] == '-' || curarg[0] == '\0') X /* increment, decrement, or no argument */ X kprintf(".ll \\n(.lu%s\n", curarg); X else X kprintf(".ll %s\n", curarg); /* simple parameter argument */ X} X Xsetsubtitle(w) /* set text for SUBTITLE variants */ Xchar *w; X{ X if (*w != '\0') { /* text for subtitle on same line */ X doline(w, -1); X contdoline = 0; X kprintf("\n.RS\n"); X } X else X trap_type = SUBTITLE; X} X Xsettitle(w) /* set text for TITLE variants */ Xchar *w; X{ X if (*w != '\0') { /* text follows on this line */ X doline(w, -1); X contdoline = 0; X kprintf("\n.RT\n"); /* reset TITLE text collection */ X } X else X trap_type = TITLE; /* trap is triggered by END TITLE */ X} X Xskip() /* SKIP number of lines times vertical line spacing */ X{ X /* select absolute or relative form */ X kprintf((curarg[0] == '+' || curarg[0] == '-')? ".sp |": ".sp "); X kprintf("\\n(.vu*%su\n", curarg); X} X X X Xspacing() /* set line spacing */ X{ X kprintf(".br\n.sp %sv-1v\n.ls %s\n", curarg, curarg); X} X X X Xsubindex() /* put subindex entry into index process */ X{ X register char *cptr, *cptr2; X X /* Make sure there is a '>' in the argument */ X X for (cptr = curarg; *cptr && *cptr != '>'; cptr++) X ; X if (*cptr != '>') X cmdbad(); X else { X /* Remove any trailing blanks on the main index */ X /* and any leading blanks on the sub index */ X X for (cptr2 = cptr-1; isspace(*cptr2) && cptr2 >= curarg; --cptr2) X ; X while (isspace(*++cptr) && *cptr) X ; X *++cptr2 = '>'; X if (cptr != ++cptr2) X while (*cptr2++ = *cptr++) X ; X X kprintf(".ds IE ~\t%s\n.IN\n", curarg); X } X} X X X Xsubtitle() /* set subtitle for even, odd or all pages after FIRST*/ X/* This routine is equivalent to title() */ X{ X char *w; X int even, odd; X X even = odd = 1; /* default subtitle on all pages */ X w = curarg; X if (0 == strlcmp(4, w, "EVEN")*strlcmp(4, w, "even")) { X odd = 0; X w += 4; X } X else if (0 == strlcmp(3, w, "ODD")*strlcmp(3, w, "odd")) { X even = 0; X w += 3; X } X kprintf(".ST %d %d \n", odd, even); X while (*w == ' ') X ++w; X setsubtitle(w); X} X X X Xtabstops() /* set absolute positions for the TAB STOPS command */ X{ X char c, *w; X X w = curarg; X kprintf(".ds TA "); /* store the tab command in a troff string */ X while ((c = *w++) != '\0') X if (c == ',') X kprintf(" "); X else X kprintf("%c", c); X /* set tabstops for both environments */ X kprintf("\n.ta \\*(TA\n.ev 1\n.ta \\*(TA\n.ev\n"); X} X X X Xtitle() /* set TITLE for even, odd, or all pages after the first */ X{ X char *w; X int even, odd; X X even = odd = 1; /* assume titling on all pages initially */ X w = curarg; X if (0 == strlcmp(4, w, "EVEN")*strlcmp(4, w, "even")) { X odd = 0; X w += 4; X } X else if (0 == strlcmp(3, w, "ODD")*strlcmp(3, w, "odd")) { X even = 0; X w += 3; X } X kprintf(".TT 0 %d %d\n", odd, even); /* set titling on desired pages */ X while (*w == ' ') X ++w; /* skip space if EVEN or ODD is followed by text on same line */ X settitle(w); /* and set up actual text */ X} X X X Xtypeset() /* perform action designated in TYPESET command */ X{ X char c, *w; X int ptsize, vtsize; X X w = curarg; X switch (upper(*w)) { X case '"': /*pass text in quotes through directly */ X while ((c = *++w) != '"' && c != '\0') X kprintf("%c", c); X kprintf("\n"); /* follow typeset commands with a new-line */ X while (*++w == ' ') X ; X if (c == '\0' || *w != '\0') { X diagnosline(); X fprintf(stderr, X ".TYPESET command not properly terminated\n"); X } X break; X case 'R': /* Roman font set */ X switch (c = upper(*++w)) { X case '\0': X c = 'R'; X case 'I': X case 'B': X kprintf(".ft %c\n", c); X break; X default: X cmdbad(); X break; X } X break; X case 'P': /* Previous font*/ X X kprintf(".ft P\n"); X break; X case '*': /* special characters */ X c = *++w; X kprintf("\\(%c%c", c, (*++w)); X break; X default: /* check for pointsize / leading command*/ X if (sscanf(curarg, "%d", &ptsize) > 0) { X if (ptsize <= 5) X vtsize = ptsize; X else if (ptsize <= 8) X vtsize = ptsize+1; X else if (ptsize <= 14) X vtsize = ptsize+2; X else if (ptsize <= 36) X vtsize = ptsize+3; X else { X ptsize = 36; X vtsize = 39; X } X Vsize = vtsize; /* used for unit conversions*/ X Psize = ptsize; X kprintf(".ps %d\n.vs %d\n", ptsize, vtsize); X } X else /* anything else is not recognized */ X cmdbad(); X break; X } X} X X X Xvarelse() /* command conversion for ELSE */ X{ X if (strlcmp(-1, vstack[stackptr], curarg) == 0) { X kprintf(".NO\\}\n.el \\{\\\n"); X ELstack[stackptr] = 0; X } X else { X diagnosline(); X fprintf(stderr, "error in variant nesting, expected variant:%s\n", X vstack[stackptr]); X } X} X X X Xvarend() /* ENDIF command conversion */ X{ X if (strlcmp(-1, vstack[stackptr], curarg) == 0) { X kprintf(".NO\\}\n"); X if (ELstack[stackptr]) { X kprintf(".el .NO\n"); X } X --stackptr; X } X else { X diagnosline(); X fprintf(stderr, "variant nesting error, expected variant:%s\n", X vstack[stackptr]); X } X} X X/* dummy function for the current version there is no need to check variables */ Xvariable() X{ X} X Xvarif() /* IF command conversion */ X{ X (void) strcpy(vstack[++stackptr], curarg); X ELstack[stackptr] = 1; X kprintf(".ie %d \\{\\\n", vcheck(curarg)); X} X Xvarifnot() /* IFNOT command conversion */ X{ X (void) strcpy(vstack[++stackptr], curarg); X ELstack[stackptr] = 1; X kprintf(".ie %d \\{\\\n", vcheck(curarg)?0:1); X} @@@End of rnotroff.c echo x - runoffmacros 1>&2 sed 's/^X//' >runoffmacros <<'@@@End of runoffmacros' X.\" @(#)runoffmacros 1.15 of 3/7/80 X.\" Macros used by /usr/bin/runoff X.nh X.po 3P X.ll 6.0i X.lt 6.0i X.hy0 \"deactivate hyphenation X.ev1 X.ll 6.0i X.lt 6.0i X.hy0 \"deactivate hyphenation X.ev X.ev2 X'in 0 \"set default mode for rereading diversion. X'nf X.if t .ll 7.5i X.if n .ll 20i X.ev X.ds PA Page X.\" XX is the point size of the page number X.ds XX 10 X.\" XY is the font of the page number X.ds XY R X.nr -D 0 \" special mode indicator to heading and footings X.nr .L 1 \"line spacing, default X.nr C 0 X.nr A 0 X.nr X 0 \"flag for index number X.nr cn 1 \" next chapter number register X.nr ap 1 1 X.nr AP 1 X.af AP A X.pl 5.8i X.ta 5P 10P 15P 20P 25P 30P 35P 40P X. AP APPENDIX setup X.de AP X.nr TH \\n(HD X.nr HD 0 \" deactivate header X.if \\n(nl>0 .sp \\n(.tu X.sp 3 P X.ps 13 X.ft B X.nr AP \\n(ap X.nr ap +1 X.ce XAPPENDIX \\n(AP X.ft X.ps X.if \\n(TO \{\ X.ce X.OT X.sp 3 P\} X.pn 2 \" reset page number to 2 X.nr C 0 \" deactivate chapter numbering X.nr X 0 \" deactivate index numbering X.nr A 1 \" flag appendix page numbering X.fi \" reset default mode X.ad \" X.nr HD \\n(TH X.nr % 1 X.ds PG \\n(AP - \\n% X.. X. CH \" Chapter start macro X.de CH X.nr TH \\n(HD X.nr HD 0 \" deactivate header X.if \\n(nl>0 .sp \\n(.tu X.sp 3 P X.ps 13 X.ft B X.nr CN \\n(cn X.ce XCHAPTER \\n(CN X.nr cn +1 X.ft X.ps X.if \\n(TO \{\ X.ce X.OT\} X.sp 3 P X.pn 2 \" reset page number to 2 X.nr C 1 \"activate chapter numbering X.nr A 0 \"deactivate appendix numbering X.nr X 0 \"deactivate index numbering X.fi \" reset default mode X.ad \" X.nr HD \\n(TH X.nr % 1 X.ds PG \\n(CN - \\n% X.. X. DI \" diversion macro X.de DI X.ev1 X.nr S \\n(.s \" save current point size, X.nr V \\n(.v \" vert size X.nr F \\n(.f \" font posn, X.nr I \\n(.i \" indent X.nr L \\n(.l \" line length X.nr U \\n(.u \" fill mode indicator X.. X. DX start index output X.de DX X.pn 1 X.nr C 0 X.nr A 0 X.nr X 1 X.if \\n(nl>0 .sp \\n(.tu X.sp 3P X.ce XINDEX X.sp 3P X.nr .M \\n(.l/3u*2u X.nr N \\n(.iu X.nr LL \\n(.l \" line length store X.nr FU \\n(.u \" store fill mode X.fi X.. X. EF end footnotes X.de EF X.br X.nr VS \\n(.v \"save current vert spacing X.RD X.di X.nr FP -\\n(dn \"new footer position X.if \\n(FC=1 .nr FP -(\\n(.v-\\n(VS+1P) \"uncertainty correction X.ch FO \\n(FPu \"FP is negative X.if (\\n(nl+1v)>(\\n(.p+\\n(FP)\ X.ch FO \\n(nlu+1v \"it didn't fit X.. X. EK at end of keeptogther decide where to place text X.de EK X.br X.di X.RD X.if \\n(dn<(\\n(.p-8P) \{\ X.if \\n(.t<\\n(dn .sp \\n(.tu \} X.ev2 X.KT X.ev X.. X. FB process leftover footnotes X.de FB X.if \\n(FC \{ .di OF \"overflowed footnote X.nr LF 1\} \"flag footnote overflow X.. X. FF start footing X.de FF X.nr FD (\\n(FD:\\$1) \" odd footing flag X.nr FE (\\n(FE:\\$2) \" even footing flag X.if (\\$1*\\$2) .nr AF 1 X.ie \\$1 .di DF X.el .di VF X.DI X.. X. SF start footnote X.de SF X.DI X.da FN X.if \\n+(FC=1 .SP \"include separator X.. X. FO footer, trap invoked X.de FO X.nr LF 0 X.if \\n(FC \{\ X.ev2 X.FN X.rm FN X.if "\\n(.z"OF" .di \"terminate overflow diversion X.nr FC 0 \"disable FB X.ev \} X'sp 3P X.ev2 X.ie o .DF X.el .VF X.br X.ev X'bp X.. X. IN pass index entries to indexproc X.de IN X.tm \\*(IE >\\*(PG X.. X. LF get leftover footnote X.de LF X.SF X'nf X'in 0 X.OF \"overflow footnote X.fi X.in X.EF X.. X. NS NO SUBTITLE variants X.de NS X.if !\\$2 .nr SE 0 X.if !\\$1 .nr SO 0 X.. X. RF reset footing text input mode X.de RF X.br X.di X.RD X.if \\n(AF \{\ X.ev 2 X.di VF X.DF X.di X.ev X.nr AF 0\} X.nr B 6P+\\n(dnu X.nr FP -\\n(dn X.if ((\\n(.p-\\nB)>\\n(nl) \{\ X.ch FB -\\nBu X.ie (\\n(nlu+1v)<(\\n(.p+\\n(FP)\ X.ch FO \\n(FPu X.el .ch FO \\n(nlu+1v \} X.. X. RS Reset SUBTITLE X.de RS X.br X.di X.RD X.if \\n(AS \{\ X.ev 2 X.di ES X.OS X.di X.ev X.nr AS 0 \} \" remove AS flag X.. X. SP separator for footnotes X.de SP X'sp X\l'1.2i' X.br X.. X. ST set SUBTITLE X.de ST X.nr SO (\\n(SO:\\$1) \" odd subtitle flag X.nr SE (\\n(SE:\\$2) \" even subtitle flag X.if (\\$1*\\$2) .nr AS 1 \" case when title is for even and odd pages X.ie \\$1 .di OS X.el .di ES X.DI X.. X. RI Set adjustment mode for .RIGHT command X.de RI X.br X.nr AD \\n(.j \" Save current adjustment mode X.ad r X.it 1 RR \" Invoke reset macro after one line X.. X. RR Reset .RIGHT command X.de RR X.br X.ll X.ad \\n(AD X.. X. PN Page numbering X.de PN X.ie !\\n(.$ .nr PN 1 \" if no arg, turn page numbering on X.el \{\ X.nr PN \\$1 \" else set as given X.if \\$1 .pn \\$1 \} X.. X. PE put index entry in proper mode X.de PE X.ie (\\w'\\*(IX'+\\n(.i)<\\n(.M \{\ X\\*(IX\\l'(|\\n(.Mu-\\n(.iu).'\} X.el \{\ X.ll \\n(.Mu X\\*(IX X.br X.ll \\n(LLu X\\&\\l'(|\\n(.Mu).'\} X.. X. UX unnumbered index - same as PE, without dots and page number X.de UX X.ie (\\w'\\*(IX'+\\n(.i)<\\n(.M \{\ X\\*(IX\} X.el \{\ X.ll \\n(.Mu X\\*(IX X.br X.ll \\n(LLu\} X.. X. HD Header macro X.de HD X.if t .tl '\(rn''\(rn' X.cp \" Mark cut point for phototypesetter X.if \\n(HD \{\ X.ev1 X'sp 2P X.mk X.ft \\*(XY X.ps \\*(XX X.if \\n(PN \{\ X.ie (\\nA+\\nC+\\nX) \{\ X.if \\nA .ds PG \\n(AP - \\n% X.if \\nC .ds PG \\n(CN - \\n% X.if \\nX .ds PG index - \\n%\} X.el .ds PG \\n% X.ie \\n%>1 .tl '''\\*(PA \\*(PG' X.el .ie \\n(FT .tl '''\\*(PA \\*(PG' X.el .if \\nX .tl '''\\*(PA \\*(PG'\} \" The index has a page number 1. X.ft X.ps X.rt X.ev X.ev 2 X.if o .if \\n(TO \{\ X.ie \\n%>1 .OT X.el .if \\n(FT .OT \} X.if o .if \\n(SO \{\ X.if (\\n(FT:(\\n%>1)) .sp \\n(.Lu X.ie \\n%>1 .OS X.el .if \\n(FT .OS \} X.if e \{\ X.if \\n(TE .ET X.if \\n(SE .sp \\n(.Lu X.if \\n(SE .ES\} X.ev X'sp 2*\\n(.Lu \} X.nr FC 0 1 \"init footnote count X.nr FP 0-\\nB \"footer trap position X.ch FO -\\nBu \"reset footer trap X.if \\n(LF .LF \"footnote overflowed X.if \\n(FG \{\ X'sp \\n(FGu \" put out figure space X.nr FG 0 \} X.. X. LT Set .LITERAL mode X.de LT X.br X.nr FI \\n(.u \" save setting of fill mode X.nf X.. X. RL Reset .LITERAL mode X.de RL X.br X.if \\n(FI .fi \" restore fill mode if set X.. X. RD \" reset diversion X.de RD X.ps \\nSu X.vs \\nVu X.ft \\nF X'in \\nIu X'll \\nLu X.ie \\nU 'fi X.el 'nf X.ev X.. X. RX Reset index X.de RX X.in \\nNu X.nr X 0 X.if !(\\n(FU) .nf X.nr FU 1 X.ch FO 18i \" disable footer X.sp \\(n.tu X.ch FO \\n(FP \" restore footer X.. X. TF trap for figure space X.de TF X'sp \\n(.tu X.ch TF \\n(.pu+20P X.. X. TT Set title for .TITLE variants X.de TT X.nr FT (\\n(FT:\\$1) \" first title flag X.nr TO (\\n(TO:\\$2) \" odd title flag X.nr TE (\\n(TE:\\$3) \" even title flag X.if (\\$2*\\$3) .nr AT 1 \" case when title for even & odd pages X.DI X.ie \\$2 .di OT X.el .di ET X.. X. RT Reset title X.de RT X.br X.di X.RD X.if \\n(AT \{\ X.ev 2 X.di ET X.OT X.di X.ev X.nr AT 0 \} \" reset flag X.. X. NO No operation X.de NO X.. X. NT NO TITLE variants X.de NT X.nr TO \\$1*\\n(TO X.nr TE \\$2*\\n(TE X.. X.nr HD 1 \" set headers X.wh 0 HD X.PN 1 X.nr TO 0 \" no odd-page titles X.nr TE 0 \" no even-page titles X.nr FT 0 X.nr B 6P \" bottom margin size X.nr FP 0-\nBu X.wh 20P FO \" temporary posn X.wh -\nBu FB \" to process overflows X.ch FO -\nBu \" conceal FB with FO X.wh 200P TF \" temporary position for TF X.nr FC 0 1 X.ds PG 1 @@@End of runoffmacros