diff --git a/usr.bin/nroff/ChangeLog b/usr.bin/nroff/ChangeLog new file mode 100644 index 0000000..f74edfe --- /dev/null +++ b/usr.bin/nroff/ChangeLog @@ -0,0 +1,39 @@ +CHANGES +------- + +2.0 + - Maintenance of nroff has been taken over by Devin Reade, + + - Fixed a significant number of memory trashing bugs with the + help of Insight. + - Optimized for speed, mainly by translating some functions + into inline code via macros. + - Prototyped, indented and otherwise cleaned up code. Made use + of some GNO v2.0.6 libc routines to reduce source code size. + - Indented source. + +=== The remaining versions listed below were by Mike Horwath, === +=== and Jawaid Bazyar === + +1.1p3.4 + Well, guess what? I caused a hell of an error in the last + version of this, and now it is fixed. The problem stemmed + from a library error and has been fixed. All thanks to Jawaid + for creating and fixing the error all by himself. (no flame + to ya Jawaid...heh) + +1.1p3.3 + Fixed the problem with nroffing the LESS manpage. I don't + really know how the hell I fixed it, but that bug is now gone. + I also optimized the source to a great extent. There is no real + speed increase in output, but the executable is MUCH smaller + than the original posted version. Enjoy. + +4/21/92 jb + Fixed double-line problem when redirecting and piping the output + of nroff. (It sticks \r's in the output text all over the place. + I simply filter them out in prchar.) + +[previous versions] + Well, first release. The versions suck for now till I can + figure out a better way to do it. It worked, but had bugs. diff --git a/usr.bin/nroff/README b/usr.bin/nroff/README new file mode 100644 index 0000000..c2c51b3 --- /dev/null +++ b/usr.bin/nroff/README @@ -0,0 +1,38 @@ +nroff - Text Processing Typesetter +---------------------------------- + + This is 'nroff 1.2' for GNO/ME 1.0. This is fairly close to + the real Unix nroff, although there are still some things that + this one doesn't do that it should. + + This software was ported by Mike Horwath and Jawaid Bazyar for + the GNO Multitasking Environment. Various bug fixes were applied + by Devin Reade. + +Installation +------------ + + Type 'dmake install' in this directory, or copy the following + files: + + nroff --> /usr/bin/nroff + tmac.an --> /usr/lib/tmac/tmac.an + tmac.s --> /usr/lib/tmac/tmac.s + nroff.1 --> /usr/man/man1/nroff.1 + man.7 --> /usr/man/man7/man.7 + ms.7 --> /usr/man/man7/ms.7 + + If you want to put the macro files somewhere other than in + /usr/lib/tmac, then set your TMACDIR environment variable to + point to the directory in which they reside. + +Compatibility +------------- + This software works with any GNO-compatible shell (Orca suffices, + but pipes don't work very well under Orca, and according to + dozens of GNO users, GNO is "simply superior".) + +Bugs +---- + This program uses recursion, Not A Good Thing on the IIgs. + It really needs a rewrite. diff --git a/usr.bin/nroff/command.c b/usr.bin/nroff/command.c new file mode 100644 index 0000000..db052f2 --- /dev/null +++ b/usr.bin/nroff/command.c @@ -0,0 +1,1672 @@ +/* + * command.c - command input parser/processor for nroff text processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: command.c,v 1.1 1997/03/14 06:22:26 gdr Exp $ + */ + + +#ifdef __ORCAC__ +segment "command___"; +#endif + +#include +#include +#include +#ifdef __GNO__ +#include +#else +#include "err.h" +#endif + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" +#include "escape.h" +#include "macros.h" +#include "io.h" + +#define iscond(x) ((x)=='>'||(x)=='<'||(x)=='=') +#define isoper(x) ((x)=='+'||(x)=='-'||(x)=='*'||(x)=='/'||(x)=='%') + +static int comtyp (char *p, char *m); +static void read_if (void); +static void gettl (char *p, char *q, int *limit); +static int getval (char *p, char *p_argtyp); +static int getnumeric (char *p); +static int do_oper (int first, int oper, int second); + +/* + * comand + * main command processor + */ +void +comand (char *p) { + register int i; + register int ct; + register int val; + register int indx; + int spval; + int not_cond; + char argtyp; + char name[MAXLINE]; + char macexp[MXMLEN]; + int tmp; + char *pfs; + char fs[20]; + char c; + char *ps1; + char *ps2; + + DEBUGGING(("comand: enter, p=|%s|",p)); + + /* + * get command code + */ + ct = comtyp (p, macexp); + + /* + * error? + */ + if (ct == UNKNOWN) { + warnx("unrecognized command %s", p); + return; /* gdr: added in this return */ + } + + /* + * ignore comments + */ + if (ct == COMMENT) { + return; + } + + /* + * do escape expansion on command line args from p into name + */ + expesc (p, name, MAXLINE); + + + /* + * get value of command + */ +#if 0 + val = getval (p, &argtyp); +#endif + + + /* + * do the command + */ + switch (ct) { + /* set (¶m, val, type, defval, minval, maxval) */ + case FC: + /* + * field delim/pad chars + * + * .fc [delim] [pad] + */ + warnx(".fc not available"); + break; + + case TR: + /* + * translate + * + * .tr ab... + */ + warnx(".tr not available"); + break; + + case AD: + /* + * adjust + * + * .ad [mode] + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + + switch (*p) { + case 'l': + dc.adjval = ADJ_LEFT; + dc.juval = YES; + break; + case 'r': + dc.adjval = ADJ_RIGHT; + dc.juval = YES; + break; + case 'c': + dc.adjval = ADJ_CENTER; + dc.juval = YES; + break; + case 'b': + case 'n': + dc.adjval = ADJ_BOTH; + dc.juval = YES; + break; + default: + break; + } + break; + + case AF: + /* + * assign format to number reg + * + * .af R {1,a,A,i,I,0...1} + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + if (!isalpha (*p)) { + warn("invalid or missing number register name"); + } else { + /* + * number register format is 1,a,A,i,I,0...1 + * default is 1. for 0001 format, store num dig + * or'ed with 0x80, up to 8 digits. + */ + indx = tolower (*p) - 'a'; + p = skipwd (p); + p = skipbl (p); + if (*p == '1') dc.nrfmt[indx] = '1'; + else if (*p == 'a') dc.nrfmt[indx] = 'a'; + else if (*p == 'A') dc.nrfmt[indx] = 'A'; + else if (*p == 'i') dc.nrfmt[indx] = 'i'; + else if (*p == 'I') dc.nrfmt[indx] = 'I'; + else if (*p == '0') { + for (i = 0; isdigit (p[i]); i++) + ; + dc.nrfmt[indx] = (char) (i); + if (dc.nrfmt[indx] <= 0) + dc.nrfmt[indx] = '1'; + else if (dc.nrfmt[indx] > 8) + { + dc.nrfmt[indx] = 8; + dc.nrfmt[indx] |= 0x80; + } + else + dc.nrfmt[indx] |= 0x80; + + } + else + dc.nrfmt[indx] = '1'; + } + break; + case BD: + /* + * embolden font (IGNORED) + * + * .bd [S] F N + */ + break; + case BO: + /* + * bold face + * + * .bo [N] + */ + val = getval (p, &argtyp); + set (&dc.boval, val, argtyp, 1, 0, HUGE); + dc.cuval = dc.ulval = 0; + break; + case BP: + /* + * begin page + * + * .bp [+/-N] + */ + val = getval (p, &argtyp); + if (pg.lineno > 0) + nroffSpace (HUGE); + set (&pg.curpag, val, argtyp, pg.curpag + 1, -HUGE, HUGE); + pg.newpag = pg.curpag; + set_ireg ("%", pg.newpag, 0); + break; + case BR: + /* + * break (page) + * + * .br + */ + robrk (); + break; + case BS: + /* + * backspc in output + * + * .bs [N] + */ + val = getval (p, &argtyp); + set (&dc.bsflg, val, argtyp, 1, 0, 1); + break; + case C2: + /* + * nobreak char + * + * .c2 [c='] + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + dc.nobrchr = '\''; + } else { + dc.nobrchr = argtyp; + } + break; + case CC: + /* + * command character + * + * .cc [c=.] + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + dc.cmdchr = '.'; + } else { + dc.cmdchr = argtyp; + } + break; + case CE: + /* + * center + * + * .ce [N] + */ + val = getval (p, &argtyp); + robrk (); + set (&dc.ceval, val, argtyp, 1, 0, HUGE); + break; + case CS: + /* + * constant space char (IGNORED) + * + * .cs F N M + */ + break; + case CU: + /* + * continuous underline + * + * .cu [N] + */ + val = getval (p, &argtyp); + set (&dc.cuval, val, argtyp, 1, 0, HUGE); + dc.ulval = dc.boval = 0; + break; + case DE: + /* + * define macro + * + * .de name [end] + */ + val = getval (p, &argtyp); + ignoring = FALSE; + defmac (p, sofile[dc.flevel]); + break; + case DS: + /* + * define string + * + * .ds name string + */ + val = getval (p, &argtyp); + defstr (p); + break; + case EC: + /* + * escape char + * + * .ec [c=\] + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + dc.escchr = '\\'; + } else { + dc.escchr = argtyp; + } + dc.escon = YES; + break; + case EF: + /* + * even footer + * + * .ef "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.efoot, &pg.eflim[0]); + break; + case EH: + /* + * even header + * + * .eh "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.ehead, &pg.ehlim[0]); + break; + case EN: + /* + * end macro def (should not get one here...) + * + * .en or .. + */ + warnx("missing .de command"); + break; + case EO: + /* + * escape off + * + * .eo + */ + dc.escon = NO; + break; + case EX: + /* + * exit + * + * .ex + */ + if (sofile[0] != stdin) { + fclose (sofile[0]); + } + for (i = 1; i <= Nfiles; i++) { + if (sofile[i] != NULL_FPTR) { + fclose (sofile[i]); + } + } + err_exit(0); + break; + case FI: + /* + * fill + * + * .fi + */ + robrk (); + dc.fill = YES; + break; + case FL: + /* + * flush NOW + * + * .fl + */ + fflush (out_stream); + break; + case FO: + /* + * footer + * + * .fo "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.efoot, &pg.eflim[0]); + gettl (p, pg.ofoot, &pg.oflim[0]); + break; + case FT: + /* + * font change + * + * .ft {R,I,B,S,P} + * + * the way it's implemented here, it causes a break + * rather than be environmental... + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + if (!isalpha (*p)) { + warnx("invalid or missing font name"); + } else { + pfs = &fs[0]; + + fontchange (*p, pfs); + + robrk (); + fflush (out_stream); + fprintf (out_stream, "%s", pfs); + fflush (out_stream); + } + break; + case TL: + case HE: + /* + * header (both are currently identical. .he is -me) + * + * .tl "a" "b" "c" + * .he "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.ehead, &pg.ehlim[0]); + gettl (p, pg.ohead, &pg.ohlim[0]); + break; + case IE: + /* + * if of if/else conditional + * + * .ie condition anything + * .el anything + * + * .ie condition \{\ + * ... + * ... \} + * .el \{\ + * ... + * ... \} + */ + warnx(".ie not available"); + break; + case EL: + /* + * else of if/else conditional + * + * .ie condition anything + * .el anything + * + * .ie condition \{\ + * ... + * ... \} + * .el \{\ + * ... + * ... \} + */ + warnx(".el not available"); + break; + case IF: + /* + * conditional + * + * .if c command [c=n(roff),t(roff),e(ven),o(dd)] + * .if !c command + * .if 's1's2' command [s1 == s2] + * .if !'s1's2' command [s1 != s2] + * .if N command [N > 0] + * .if !N command [N <= 0] + * + * .if cond \{\ + * command + * ... \} + */ + p = skipwd (p); + p = skipbl (p); + not_cond = 0; + if (*p == '!') { + p++; + not_cond = 1; + } + if (islower (*p) && isspace (*(p+1))) { + /* + * single char: n=nroff,t=troff,e=evenpage,o=oddpage + */ + c = *p; + switch (c) { + case 'n': /* if nroff... (always T) */ + p = skipwd (p); + p = skipbl (p); + + DEBUGGING(("comand: p=|%s|", p)); + if (*p != EOS && not_cond == 0) { + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + break; + case 't': /* if troff... (always F) */ + p = skipwd (p); + p = skipbl (p); + + DEBUGGING(("comand: p=|%s|", p)); + + if (*p != EOS && not_cond != 0) { + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + break; + case 'e': /* if even page... */ + p = skipwd (p); + p = skipbl (p); + + DEBUGGING(("comand: p=|%s|", p)); + + if (((pg.curpag % 2) == 0 && not_cond == 0) + || ((pg.curpag % 2) != 0 && not_cond != 0)) { + /* could be newpag, too */ + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + break; + case 'o': /* if odd page... */ + p = skipwd (p); + p = skipbl (p); + + DEBUGGING(("comand: p=|%s|", p)); + + if (((pg.curpag % 2) == 1 && not_cond == 0) + || ((pg.curpag % 2) != 1 && not_cond != 0)) { + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + break; + } + } else if (*p == '\'' || *p == '/' || *p == '\"') { + /* + * compare strings. we need to interpolate here + */ + c = *p; + ps1 = ++p; + while (*p != EOS && *p != c) { + p++; + } + *p = EOS; + ps2 = ++p; + while (*p != EOS && *p != c) { + p++; + } + *p = EOS; + + DEBUGGING(("comand: strcmp (ps1=|%s|,ps2=|%s|)", ps1, ps2)); + + if ((!strcmp (ps1, ps2) && not_cond == 0) + || ( strcmp (ps1, ps2) && not_cond != 0)) { + p++; + p = skipbl (p); + + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + } else { + /* + * number + */ + + DEBUGGING(("comand: p=|%s|", p)); + val = getnumeric (p); + if ((val > 0 && not_cond == 0) + || (val <= 0 && not_cond != 0)) { + p = skipwd (p); + p = skipbl (p); + + if (*p == '\\' && *(p+1) == '{') { + read_if (); + } else { + if (*p == dc.cmdchr) { + comand (p); + } else { + if (*p == '\"') { + p++; + } + if (*p == ' ') { + robrk (); + } + text (p); + } + } + } + } + break; + case IG: + /* + * ignore input lines + * + * .ig name + */ + val = getval (p, &argtyp); + ignoring = TRUE; + defmac (p, sofile[dc.flevel]); + break; + case IN: + /* + * indenting + * + * .in [+/-N] + */ + val = getval (p, &argtyp); + set (&dc.inval, val, argtyp, 0, 0, dc.rmval - 1); + set_ireg (".i", dc.inval, 0); + dc.tival = dc.inval; + break; + case JU: + /* + * justify + * + * .ju + */ + dc.juval = YES; + break; + case LG: + /* + * ligature (IGNORED) + * + * .lg [N] + */ + break; + case LL: + /* + * line length + * + * .ll [+/-N] + * .rm [+/-N] + */ + val = getval (p, &argtyp); + set (&dc.rmval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE); + set (&dc.llval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE); + set_ireg (".l", dc.llval, 0); + break; + case LS: + /* + * line spacing + * + * .ls [+/-N=+1] + */ + val = getval (p, &argtyp); + set (&dc.lsval, val, argtyp, 1, 1, HUGE); + set_ireg (".v", dc.lsval, 0); + break; + case LT: + /* + * title length + * + * .lt N + */ + val = getval (p, &argtyp); + set (&dc.ltval, val, argtyp, PAGEWIDTH, 0, HUGE); + pg.ehlim[RIGHT] = dc.ltval; + pg.ohlim[RIGHT] = dc.ltval; + break; + case M1: + /* + * topmost margin + * + * .m1 N + */ + val = getval (p, &argtyp); + set (&pg.m1val, val, argtyp, 2, 0, HUGE); + break; + case M2: + /* + * second top margin + * + * .m2 N + */ + val = getval (p, &argtyp); + set (&pg.m2val, val, argtyp, 2, 0, HUGE); + break; + case M3: + /* + * 1st bottom margin + * + * .m3 N + */ + val = getval (p, &argtyp); + set (&pg.m3val, val, argtyp, 2, 0, HUGE); + pg.bottom = pg.plval - pg.m4val - pg.m3val; + break; + case M4: + /* + * bottom-most marg + * + * .m4 N + */ + val = getval (p, &argtyp); + set (&pg.m4val, val, argtyp, 2, 0, HUGE); + pg.bottom = pg.plval - pg.m4val - pg.m3val; + break; + case MACRO: + /* + * macro expansion + * + * (internal) + */ + maceval (p, macexp); + break; + case MC: + /* + * margin character (change bars) + * + * .mc [c [N]] + * + * right margin only, default 0.2i + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + mc_ing = FALSE; /* turn off... */ + } else { + mc_ing = TRUE; /* turn on... */ + mc_space = 2; /* force these for now... */ + mc_char = argtyp; /* single char only!!! */ + + p = skipwd (p); + p = skipbl (p); + + val = getval (p, &argtyp); + set (&mc_space, val, argtyp, 2, 0, dc.llval); + } + break; + case NA: + /* + * no adjust + * + * .na + */ + dc.adjval = ADJ_OFF; + dc.juval = NO; + break; + case NE: + /* + * need n lines + * + * .ne N + */ + val = getval (p, &argtyp); + robrk (); + if ((pg.bottom - pg.lineno + 1) < (val * dc.lsval)) { + nroffSpace (HUGE); + } + break; + case NF: + /* + * no fill + * + * .nf + */ + robrk (); + dc.fill = NO; + break; + case NJ: + /* + * no justify + * + * .nj + */ + dc.juval = NO; + break; + case NR: + /* + * set number reg + * + * .nr R +/-N M + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + if (!isalpha (*p)) { + warn("invalid or missing number register name"); + } else { + /* + * indx is the register, R, and val is the final + * value (default = 0). getval does skipwd,skipbl + */ + indx = tolower (*p) - 'a'; + val = getval (p, &argtyp); + set (&dc.nr[indx], val, argtyp, 0, -INFINITE, INFINITE); + + /* + * now get autoincrement M, if any (default = 1). + * getval does skipwd,skipbl + */ + p = skipwd (p); + p = skipbl (p); + val = getval (p, &argtyp); + set (&dc.nrauto[indx], val, '1', 1, -INFINITE, INFINITE); + } + break; + case OF: + /* + * odd footer + * + * .of "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.ofoot, &pg.oflim[0]); + break; + case OH: + /* + * odd header + * + * .oh "a" "b" "c" + */ + val = getval (p, &argtyp); + gettl (p, pg.ohead, &pg.ohlim[0]); + break; + case PC: + /* + * page number char + * + * .pc [c=NULL] + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + dc.pgchr = EOS; + } else { + dc.pgchr = argtyp; + } + break; + case PL: + /* + * page length + * + * .pl N + */ + val = getval (p, &argtyp); + set (&pg.plval, + val, + argtyp, + PAGELEN, + pg.m1val + pg.m2val + pg.m3val + pg.m4val + 1, + HUGE); + set_ireg (".p", pg.plval, 0); + pg.bottom = pg.plval - pg.m3val - pg.m4val; + break; + case PM: + /* + * print macro names and sizes + * + * .pm [t] + */ + val = getval (p, &argtyp); + if (argtyp == '\r' || argtyp == '\n') { + printmac (0); + } else if (argtyp == 't') { + printmac (1); + } else if (argtyp == 'T') { + printmac (2); + } else { + printmac (0); + } + break; + case PN: + /* + * page number + * + * .pn N + */ + val = getval (p, &argtyp); + tmp = pg.curpag; + set (&pg.curpag, val - 1, argtyp, tmp, -HUGE, HUGE); + pg.newpag = pg.curpag + 1; + set_ireg ("%", pg.newpag, 0); + break; + case PO: + /* + * page offset + * + * .po N + */ + val = getval (p, &argtyp); + set (&pg.offset, val, argtyp, 0, 0, HUGE); + set_ireg (".o", pg.offset, 0); + break; + case PS: + /* + * point size (IGNORED) + * + * .ps +/-N + */ + break; + case RR: + /* + * unset number reg + * + * .rr R + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + if (!isalpha (*p)) { + warnx("invalid or missing number register name"); + } else { + indx = tolower (*p) - 'a'; + val = 0; + set (&dc.nr[indx], val, argtyp, 0, -HUGE, HUGE); + } + break; + case SO: + /* + * source file + * + * .so name + */ + val = getval (p, &argtyp); + p = skipwd (p); + p = skipbl (p); + if (getwrd (p, name) == 0) { + break; + } + if (dc.flevel + 1 >= Nfiles) { + errx(-1, ".so commands nested too deeply"); + } + if ((sofile[dc.flevel + 1] = fopen (name, "r")) == NULL_FPTR) { + errx(-1, "unable to open %s\n", name); + } + dc.flevel += 1; + break; + case SP: + /* + * space + * + * .sp [N=1] + */ + val = getval (p, &argtyp); + set (&spval, val, argtyp, 1, 0, HUGE); + nroffSpace (spval); + break; + case SS: + /* + * space char size (IGNORED) + * + * .ss N + */ + break; + case TI: + /* + * temporary indent + * + * .ti [+/-N] + */ + val = getval (p, &argtyp); + robrk (); + set (&dc.tival, val, argtyp, 0, 0, dc.rmval); + break; + case UL: + /* + * underline + * + * .ul [N] + */ + val = getval (p, &argtyp); + set (&dc.ulval, val, argtyp, 0, 1, HUGE); + dc.cuval = dc.boval = 0; + break; + } +} + + +/* + * comtyp + * decodes nro command and returns its associated value. + * ptr "p" is incremented (and returned) + */ +static int +comtyp (char *p, char *m) { + register char c1; + register char c2; + char *s; + char macnam[MNLEN]; + int result; + + /* + * quick check: if null, ignore + */ + if (*p == EOS) { + return (COMMENT); + } + + /* + * skip past dot and any whitespace + */ + p++; + while (*p && (*p == ' ' || *p == '\t')) { + p++; + } + if (*p == '\0') { + return (COMMENT); + } + + /* + * First check to see if the command is a macro. If it is, + * truncate to two characters and return expansion in m + * (i.e. the text of the macro). Note that upper and lower + * case characters are handled differently. + */ + getwrd (p, macnam); + macnam[2] = EOS; + if ((s = getmac (macnam)) != NULL_CPTR) { + strcpy (m, s); + return (MACRO); + } + c1 = *p++; + c2 = *p; + result = UNKNOWN; + + switch (c1) { + case '\\': + switch (c2) { + case '"': result = COMMENT; break; + } + break; + case 'a': + switch (c2) { + case 'd': result = AD; break; + case 'f': result = AF; break; + } + break; + case 'b': + switch (c2) { + case 'd': result = BD; break; + case 'o': result = BO; break; + case 'p': result = BP; break; + case 'r': result = BR; break; + case 's': result = BS; break; + } + break; + case 'c': + switch (c2) { + case '2': result = C2; break; + case 'c': result = CC; break; + case 'e': result = CE; break; + case 's': result = CS; break; + case 'u': result = CU; break; + } + break; + case 'd': + switch (c2) { + case 'e': result = DE; break; + case 's': result = DS; break; + } + break; + case 'e': + switch (c2) { + case 'c': result = EC; break; + case 'f': result = EF; break; + case 'h': result = EH; break; +#if 0 + case 'l': result = EL; break; +#endif + case 'n': result = EN; break; + case 'o': result = EO; break; + case 'x': result = EX; break; + } + break; + case 'f': + switch (c2) { + case 'c': result = FC; break; + case 'i': result = FI; break; + case 'l': result = FL; break; + case 'o': result = FO; break; + case 't': result = FT; break; + } + break; + case 'h': + switch (c2) { + case 'e': result = HE; break; + } + break; + case 'i': + switch (c2) { + case 'f': result = IF; break; +#if 0 + case 'e': result = IE; break; +#endif + case 'g': result = IG; break; + case 'n': result = IN; break; + } + break; + case 'j': + switch (c2) { + case 'u': result = JU; break; + } + break; + case 'l': + switch (c2) { + case 'g': result = LG; break; + case 'l': result = LL; break; + case 's': result = LS; break; + case 't': result = LT; break; + } + break; + case 'm': + switch (c2) { + case '1': result = M1; break; + case '2': result = M2; break; + case '3': result = M3; break; + case '4': result = M4; break; + case 'c': result = MC; break; + } + break; + case 'n': + switch (c2) { + case 'a': result = NA; break; + case 'e': result = NE; break; + case 'f': result = NF; break; + case 'j': result = NJ; break; + case 'r': result = NR; break; + } + break; + case 'o': + switch (c2) { + case 'f': result = OF; break; + case 'h': result = OH; break; + } + break; + case 'p': + switch (c2) { + case 'c': result = PC; break; + case 'l': result = PL; break; + case 'm': result = PM; break; + case 'n': result = PN; break; + case 'o': result = PO; break; + case 's': result = PS; break; + } + break; + case 'r': + switch (c2) { + case 'm': result = RM; break; + case 'r': result = RR; break; + } + break; + case 's': + switch (c2) { + case 'o': result = SO; break; + case 'p': result = SP; break; + case 's': result = SS; break; + } + break; + case 't': + switch (c2) { + case 'i': result = TI; break; + case 'l': result = TL; break; + case 'r': result = TR; break; + } + break; + case 'u': + switch (c2) { + case 'l': result = UL; break; + } + break; + case '.': + result = EN; + break; + } + return result; +} + + + +/* + * gettl + * get header or footer title + */ +static void +gettl (char *p, char *q, int *limit) { + /* + * skip forward a word... + */ + p = skipwd (p); + p = skipbl (p); + + /* + * copy and set limits + */ + strcpy (q, p); + limit[LEFT] = dc.inval; + limit[RIGHT] = dc.rmval; +} + +/* + * getval + * retrieves optional argument following command. + * returns positive integer value with sign (if any) + * saved in character addressed by p_argt. + */ +static int +getval (char *p, char *p_argtyp) { + p = skipwd (p); + p = skipbl (p); + *p_argtyp = *p; + if ((*p == '+') || (*p == '-')) { + ++p; + } + return (ctod (p)); +} + +#define N_ADD 0 +#define N_SUB 1 +#define N_MUL 2 +#define N_DIV 3 +#define N_MOD 4 +#define N_LT 5 +#define N_GT 6 +#define N_LE 7 +#define N_GE 8 +#define N_EQ 9 +#define N_AND 10 +#define N_OR 11 + + +/* + * getnumeric + * + * retrieves numeric argument. will parse for number registers, + * constants, operations, and logical comparisons. no imbeded spaces! + * start at p (don't skip) + */ +static int +getnumeric (char *p) { + char name[10]; + int val; + int thisval; + int autoinc; + char buf[256]; + char *pbuf; + int next_op; + int nreg; + const char *percent = "%"; + char *scratch; + + val = 0; + next_op = N_ADD; + while (*p != EOS && !isspace (*p)) { + if (!strncmp (p, "\\n", 2)) { + DEBUGGING(("getnumeric: found number reg...")); + /* + * number register + */ + autoinc = 0; + p += 2; + if (*p == '+') { + autoinc = 1; + p++; + } else if (*p == '-') { + autoinc = -1; + p++; + } + if (isalpha (*p)) { + /* + * \nx form. find reg (a-z) + */ + nreg = tolower (*p) - 'a'; + p++; + + /* + * was this \n+x or \n-x? if so, do the + * auto incr + */ + if (autoinc > 0) { + dc.nr[nreg] += dc.nrauto[nreg]; + } else if (autoinc < 0) { + dc.nr[nreg] -= dc.nrauto[nreg]; + } + + val = do_oper (val, next_op, dc.nr[nreg]); + } else if (*p == '%') { + /* + * \n% form. find index into reg struct + */ + FINDREG(percent, nreg, scratch); + p++; + if (nreg < 0) { + errx(-1, "no register match"); + } + + /* + * was this \n+% or \n-%? if so, do the + * auto incr + */ + if (autoinc > 0) { + rg[nreg].rval += rg[nreg].rauto; + } else if (autoinc < 0) { + rg[nreg].rval -= rg[nreg].rauto; + } + + + val = do_oper (val, next_op, rg[nreg].rval); + } else if (*p == '(') { + /* + * \n(xx form. find index into reg struct + */ + p++; + name[0] = *p++; + name[1] = *p++; + if (name[1] == ' ' || name[1] == '\t' + || name[1] == '\n' || name[1] == '\r') { + name[1] = '\0'; + } + name[2] = '\0'; + FINDREG(name, nreg, scratch); + if (nreg < 0) { + errx(-1, "no register match"); + } + + /* + * was this \n+(xx or \n-(xx? if so, do the + * auto incr + */ + if (rg[nreg].rflag & RF_WRITE) { + if (autoinc > 0) { + rg[nreg].rval += rg[nreg].rauto; + } else if (autoinc < 0) { + rg[nreg].rval -= rg[nreg].rauto; + } + } + + val = do_oper (val, next_op, rg[nreg].rval); + } + } else if (isdigit (*p)) { + pbuf = buf; + while (1) { + if ((*p == EOS || isspace (*p)) || + (*p == '\\') || + (iscond (*p)) || + (isoper (*p))) { + break; + } + *pbuf++ = *p++; + } + *pbuf = EOS; + + DEBUGGING(("getnumeric: buf:|%s| next_op:%d val:%d", + buf, next_op, val)); + + thisval = ctod (buf); + val = do_oper (val, next_op, thisval); + DEBUGGING(("getnumeric: thisval:%d val:%d", thisval, val)); + } + + /* + * p should now be at the next thing, either a + * space, a null, or an operator + */ + if (*p == EOS || isspace (*p)) { + break; + } + switch (*p) { + case '+': + next_op = N_ADD; + p++; + break; + case '-': + next_op = N_SUB; + p++; + break; + case '*': + next_op = N_MUL; + p++; + break; + case '/': + next_op = N_DIV; + p++; + break; + case '%': + next_op = N_MOD; + p++; + break; + case '&': + next_op = N_AND; + p++; + break; + case ':': + next_op = N_OR; + p++; + break; + case '<': + p++; + if (*p == '=') { + p++; + next_op = N_LE; + } else { + next_op = N_LT; + } + break; + case '>': + p++; + if (*p == '=') { + p++; + next_op = N_GE; + } else { + next_op = N_GT; + } + break; + case '=': + p++; + if (*p == '=') { + p++; + } + next_op = N_EQ; + break; + } + } + return (val); +} + + +/* + * do_oper + */ + +static int +do_oper (int first, int oper, int second) { + int val; + + DEBUGGING(("do_oper: first:%d op:%d second:%d", first, oper, second)); + switch (oper) { + case N_ADD: + val = first + second; + break; + case N_SUB: + val = first - second; + break; + case N_MUL: + val = first * second; + break; + case N_DIV: + val = first / second; + break; + case N_MOD: + val = first % second; + break; + case N_LT: + val = ((first < second) ? 1 : 0); + break; + case N_GT: + val = ((first > second) ? 1 : 0); + break; + case N_LE: + val = ((first <= second) ? 1 : 0); + break; + case N_GE: + val = ((first >= second) ? 1 : 0); + break; + case N_EQ: + val = ((first == second) ? 1 : 0); + break; + case N_AND: + val = ((first && second) ? 1 : 0); + break; + case N_OR: + val = ((first || second) ? 1 : 0); + break; + } + return (val); +} + + +/* + * set + * set parameter and check range. this is for basically all commands + * which take interger args + * + * no param (i.e. \r or \n) means reset default + * + means param += val (increment) + * - means param -= val (decrement) + * anything else makes an assignment within the defined numerical limits + * + * examples: + * + * .nr a 14 set register 'a' to 14 + * .nr a +1 increment register 'a' by 1 + * .nr a reset register 'a' to default value (0) + */ +void +set (int *param, int val, char type, int defval, int minval, int maxval) { + switch (type) { + case '\r': + case '\n': + *param = defval; + break; + case '+': + *param += val; + break; + case '-': + *param -= val; + break; + default: + *param = val; + break; + } + *param = MIN(*param, maxval); + *param = MAX(*param, minval); +} + +/* + * set_ireg + * set internal register "name" to val. ret 0 if ok, else -1 if reg not + * found or 1 if read only + * + * 0=internal, 1=user set + */ +int +set_ireg (const char *name, int val, int opt) { + register int nreg; + char *p; + + FINDREG(name, nreg, p); + if (nreg < 0) { + return (-1); + } + + if ((rg[nreg].rflag & RF_WRITE) || (opt == 0)) { + rg[nreg].rval = val; + + return (0); + } + + return (1); +} + + +/* + * read_if + * read input while in if statement. stop when a line starts with \} + */ +static void +read_if (void) { + char ibuf[MAXLINE]; + char *pp; + + while (getlin (ibuf, sofile[dc.flevel]) != EOF) { + DEBUGGING(("read_if: ibuf=|%s|", ibuf)); + + pp = skipbl (ibuf); + if (*pp == '\\' && *(pp+1) == '}') { + return; + } + + /* + * if line is a command or text + */ + if (ibuf[0] == dc.cmdchr) { + comand (ibuf); + } else { + /* + * this is a text line. first see if + * first char is space. if it is, break + * line. + */ + if (ibuf[0] == ' ') { + robrk (); + } + text (ibuf); + } + + pp = ibuf; + while (*pp != EOS) { + if (*pp == '\\' && *(pp+1) == '}') { + return; + } + } + } +} diff --git a/usr.bin/nroff/config.h b/usr.bin/nroff/config.h new file mode 100644 index 0000000..67a730e --- /dev/null +++ b/usr.bin/nroff/config.h @@ -0,0 +1,100 @@ +/* + * for diffent os, define tos, unix, or minix. for gemdos, pick + * a compiler (alcyon, mwc, etc). see makefile for VERSFLAGS. + * + * for atari TOS, do: cc -Dtos -Dalcyon ... + * + * for minix, do: cc -D_MINIX -D_ST ... (ST minix) + * cc -D_MINIX ... (PC minix) + * + * for unix, do: cc -Dunix ... (generic) + * cc -Dunix -DBSD... (BSD) + * + * note: so far there is no specific ST minix version. -D_ST is ignored. + * + * nroff uses index/rindex. you may need -Dindex=strchr -Drindex=strrchr + * as well. this file is included in "nroff.h" which gets included in all + * sources so any definitions you need should be added here. + * + * all os-dependent code is #ifdef'ed with GEMDOS, MINIX_ST, MINIX_PC, + * MINIX, or UNIX. most of the differences deal with i/o only. + */ +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __GNO__ +#define unix +#define NEWLINE '\r' +#endif + +#ifdef ALCYON +# ifndef tos +# define tos +# endif +# ifndef alcyon +# define alcyon +# endif +#endif + +#ifdef tos +# define GEMDOS +# undef minix +# undef unix +# undef MINIX +# undef MINIX_ST +# undef MINIX_PC +# undef UNIX +/*#define register*/ +#endif + +#ifdef alcyon +# ifndef ALCYON +# define ALCYON /* for gemdos version, alcyon C */ +# endif +# ifndef GEMDOS +# define GEMDOS +# endif +#endif + +#ifdef minix +# ifndef _MINIX +# define _MINIX +# endif +#endif + +#ifdef _MINIX +# define MINIX +# undef tos +# undef unix +# undef GEMDOS +# undef MINIX_ST +# undef MINIX_PC +# undef UNIX +# ifdef _ST +# ifndef atariST +# define atariST +# endif +# endif +# ifdef atariST +# define MINIX_ST +# else +# define MINIX_PC +# endif +#endif + +#ifdef unix +/* just in case does not define it (slightly different anyway) */ +/*#define tolower(x) (isupper(x)?((x)-'A'+'a'):(x))*/ +# undef tos +# undef minix +# undef _MINIX +# undef GEMDOS +# undef _ST +# undef MINIX_ST +# undef MINIX_PC +# ifndef UNIX +# define UNIX +# endif +#endif + +#endif /*CONFIG_H*/ diff --git a/usr.bin/nroff/escape.c b/usr.bin/nroff/escape.c new file mode 100644 index 0000000..27d010a --- /dev/null +++ b/usr.bin/nroff/escape.c @@ -0,0 +1,759 @@ +/* + * escape.c - Escape and special character input processing portion of + * nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: escape.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "escape____"; +#endif + +#define INVERSE '\xF' +#define NORMAL '\xE' + +#include +#include +#include +#ifdef __GNO__ +#include +#else +#include "err.h" +#endif + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" +#include "escape.h" +#include "macros.h" + +static int specialchar (char *s, char *c); + +/* + * expesc + * + * Expand escape sequences in the buffer , placing the results + * in buffer . If the number of characters written into + * would be more than characters, then abort with an error + * message. + */ +void +expesc (char *src, char *dest, size_t len) { + register char *s; + register char *t; + register char *pstr; + register int i; + register int val; + register int autoinc; + char c; + char fs[5]; /* for font change */ + char nrstr[20]; + char fmt[20]; + char name[10]; + int nreg; + char *pfs; + int inc; + int tmp; + char delim; + const char *percent = "%"; + char *scratch; + + + s = src; + t = dest; + + + /* + * if escape parsing is not on, just copy string + */ + if (dc.escon == NO) { + if (strlen(src) > len-1) { + errx(-1, "buffer overflow at %s:%d", __FILE__, __LINE__); + } + strcpy (dest, src); + return; + } + + /* + * do it... + */ + while (*s != EOS) { + if (*s != dc.escchr) { + /* + * not esc, continue... + */ + *t++ = *s++; + } else if (*(s + 1) == dc.escchr) { + /* + * \\ escape escape + */ + *t++ = *s++; + ++s; + } else { + switch(*(s+1)) { + + + case 'n': + /* + * \nx, \n(xx register + * + * first check for \n+... or \n-... (either form) + */ + s += 2; + autoinc = 0; + if (*s == '+') { + autoinc = 1; + s += 1; + } + if (*s == '-') { + autoinc = -1; + s += 1; + } + + + /* + * was this \nx or \n(xx form? + */ + if (isalpha (*s)) { + /* + * \nx form. find reg (a-z) + */ + nreg = tolower (*s) - 'a'; + + + /* + * was this \n+x or \n-x? if so, do the + * auto incr + */ + if (autoinc > 0) { + dc.nr[nreg] += dc.nrauto[nreg]; + } else if (autoinc < 0) { + dc.nr[nreg] -= dc.nrauto[nreg]; + } + + /* + * display format + */ + if (dc.nrfmt[nreg] == '1') { + /* + * normal decimal digits + */ + t += itoda (dc.nr[nreg], t, 6) - 1; + } else if (dc.nrfmt[nreg] == 'i') { + /* + * lower roman + */ + t += itoroman (dc.nr[nreg], t, 24) - 1; + } else if (dc.nrfmt[nreg] == 'I') { + /* + * upper roman + */ + t += itoROMAN (dc.nr[nreg], t, 24) - 1; + } else if (dc.nrfmt[nreg] == 'a') { + /* + * lower letters + */ + t += itoletter (dc.nr[nreg], t, 12) - 1; + } else if (dc.nrfmt[nreg] == 'A') { + /* + * upper letters + */ + t += itoLETTER (dc.nr[nreg], t, 12) - 1; + } else if (dc.nrfmt[nreg] & 0x80) { + /* + * zero-filled decimal + */ + sprintf (fmt, "%%0%dld", (int)(dc.nrfmt[nreg] & 0x7F)); + fmt[5] = '\0'; + sprintf (nrstr, fmt, (long) dc.nr[nreg]); + tmp = dc.nrfmt[nreg] & 0x7F; + nrstr[tmp] = '\0'; + + strcpy (t, nrstr); + t += strlen (nrstr); + } else { + /* + * normal (default) + */ + t += itoda (dc.nr[nreg], t, 6) - 1; + } + ++s; + } else if (*s == '%') { + /* + * \n% form. find index into reg struct + */ + FINDREG(percent, nreg, scratch); + if (nreg < 0) { + errx(-1, "no register match"); + } + + + /* + * was this \n+% or \n-%? if so, do the + * auto incr + */ + if (autoinc > 0) { + rg[nreg].rval += rg[nreg].rauto; + } else if (autoinc < 0) { + rg[nreg].rval -= rg[nreg].rauto; + } + + + /* + * display format + */ + if (rg[nreg].rfmt == '1') { + /* + * normal decimal digits + */ + t += itoda (rg[nreg].rval, t, 6) - 1; + } else if (rg[nreg].rfmt == 'i') { + /* + * lower roman + */ + t += itoroman (rg[nreg].rval, t, 24) - 1; + } else if (rg[nreg].rfmt == 'I') { + /* + * upper roman + */ + t += itoROMAN (rg[nreg].rval, t, 24) - 1; + } else if (rg[nreg].rfmt == 'a') { + /* + * lower letters + */ + t += itoletter (rg[nreg].rval, t, 12) - 1; + } else if (rg[nreg].rfmt == 'A') { + /* + * upper letters + */ + t += itoLETTER (rg[nreg].rval, t, 12) - 1; + } else if (rg[nreg].rfmt & 0x80) { + /* + * zero-filled decimal + */ + sprintf (fmt, "%%0%dld", + (int)(rg[nreg].rfmt & 0x7F)); + fmt[5] = '\0'; + sprintf (nrstr, fmt, (long) rg[nreg].rval); + tmp = rg[nreg].rfmt & 0x7F; + nrstr[tmp] = '\0'; + + strcpy (t, nrstr); + t += strlen (nrstr); + } else { + /* + * normal (default) + */ + t += itoda (rg[nreg].rval, t, 6) - 1; + } + s += 1; + } else if (*s == '(') { + /* + * \n(xx form. find index into reg struct + */ + s += 1; + name[0] = *s; + name[1] = *(s + 1); + if (name[1] == ' ' || name[1] == '\t' + || name[1] == '\n' || name[1] == '\r') { + name[1] = '\0'; + } + name[2] = '\0'; + FINDREG(name, nreg, scratch); + if (nreg < 0) { + errx(-1, "no register match"); + } + + + /* + * was this \n+(xx or \n-(xx? if so, do the + * auto incr + */ + if (rg[nreg].rflag & RF_WRITE) { + if (autoinc > 0) { + rg[nreg].rval += rg[nreg].rauto; + } else if (autoinc < 0) { + rg[nreg].rval -= rg[nreg].rauto; + } + } + + + /* + * display format + */ + if (rg[nreg].rfmt == '1') { + /* + * normal decimal digits + */ + t += itoda (rg[nreg].rval, t, 6) - 1; + } else if (rg[nreg].rfmt == 'i') { + /* + * lower roman + */ + t += itoroman (rg[nreg].rval, t, 24) - 1; + } else if (rg[nreg].rfmt == 'I') { + /* + * upper roman + */ + t += itoROMAN (rg[nreg].rval, t, 24) - 1; + } else if (rg[nreg].rfmt == 'a') { + /* + * lower letters + */ + t += itoletter (rg[nreg].rval, t, 12) - 1; + } else if (rg[nreg].rfmt == 'A') { + /* + * upper letters + */ + t += itoLETTER (rg[nreg].rval, t, 12) - 1; + } else if (rg[nreg].rfmt & 0x80) { + /* + * zero-filled decimal + */ + sprintf (fmt, "%%0%dld", + (int)(rg[nreg].rfmt & 0x7F)); + fmt[5] = '\0'; + sprintf (nrstr, fmt, (long) rg[nreg].rval); + tmp = rg[nreg].rfmt & 0x7F; + nrstr[tmp] = '\0'; + + strcpy (t, nrstr); + t += strlen (nrstr); + } else { + /* + * normal (default) + */ + t += itoda (rg[nreg].rval, t, 6) - 1; + } + s += 2; + } + + break; + + + case '"': /* \" comment */ + *s = EOS; + *t = *s; + return; + + case '*': /* \*x, \*(xx string */ + /* + + */ + s += 2; + if (*s == '(') { + /* + * \*(xx form + */ + s += 1; + name[0] = *s; + name[1] = *(s + 1); + name[2] = '\0'; + pstr = getstr (name); + if (!pstr) { + errx(-1,"string not found"); + } + while (*pstr) { + *t++ = *pstr++; + } + s += 2; + } else { + /* + * \*x form + */ + name[0] = *s; + name[1] = '\0'; + pstr = getstr (name); + if (!pstr) { + errx(-1, "string not found"); + } + while (*pstr) { + *t++ = *pstr++; + } + s += 1; + } + break; + + case 'f': /* \fx font */ + s += 2; + pfs = fs; /* set up ret string */ + fs[0] = '\0'; + + /* + * it parses 1-2 char of s and returns esc seq for + * \fB and \fR (\fI is same as \fB) + */ + fontchange (*s, pfs); + + /* + * imbed the atari (vt52) escape seq + */ + while (*pfs) { + *t++ = *pfs++; + } + ++s; /* skip B,I,R,S,P */ + break; + + case '(': /* \(xx special char */ + s += 2; + + /* + * it returns num char to skip and sets c to + * the ascii value of the char + */ + inc = specialchar (s, &c); + + /* + * skip proper num char in s and add c to target + */ + if (inc) { + s += inc; + *t++ = c; + } + break; + + case 'e': /* \e printable version of escape */ + *t++ = dc.escchr; + s += 2; + break; + + case '-': /* \- minus */ + case '`': /* \` grave, like \(ga */ + case '\'': /* \' accute, like \(aa */ + case '.': /* \. period */ + case ' ': /* \(space) space */ + + /* verbatim */ + *t++ = *(s+1); + s += 2; + break; + + case '0': /* \0 digital width space */ + *t++ = ' '; + s += 2; + break; + + case '|': /* \| narrow width char (0 in nroff) */ + case '^': /* \^ narrow width char (0 in nroff) */ + case '&': /* \& non-printing zero width */ + case '!': /* \! transparent copy line */ + case '$': /* \$N interpolate arg 1<=N<=9 */ + case 'a': /* \a */ + case 'b': /* \b'abc...' */ + case 'c': /* \c */ + case 'd': /* \d */ + case 'k': /* \kx */ + case 'l': /* \l'Nc' */ + case 'L': /* \L'Nc' */ + case 'p': /* \p */ + case 'r': /* \r */ + case 's': /* \sN,\s+-N */ + case 'u': /* \u */ + case 'w': /* \w'str' */ + case 'x': /* \x'N' */ + case '{': /* \{ */ + case '}': /* \} */ + case '\n': /* \(newline) ignore newline */ + case '\r': /* \(newline) ignore newline */ + + s += 2; /* currently ignored */ + break; + + case '%': /* \% hyphen */ + *t++ = '-'; + *t++ = '-'; + s += 2; + break; + + case 'h': /* \h'N' horiz motion*/ + s += 2; + delim = *s++; + val = atoi (s); + for (i = 0; i < val; i++) { + *t++ = ' '; + } + while (*s != delim) { + if (*s == 0) { + break; + } + s++; + } + if (*s) { + s++; + } + break; + + case 'o': /* \o'abc...' overstrike*/ + s += 2; + delim = *s++; + while (*s != EOS && *s != delim) { + *t++ = *s++; + *t++ = 0x08; + } + s++; + break; + + case 't': /* \t horizontal tab*/ + *t++ = '\t'; + s += 2; + break; + + case 'v': /* \v'N' vert tab*/ + s += 2; + delim = *s++; + val = atoi (s); + for (i = 0; i < val; i++) { + *t++ = 0x0A; + } + while (*s != delim) { + if (*s == 0) { + break; + } + s++; + } + if (*s) { + s++; + } + break; + + case 'z': /* \zc print c w/o spacing*/ + s += 2; + *t++ = *s++; + *t++ = 0x08; + break; + + default: /* \X any other character not above*/ + s += 1; + *t++ = *s++; + break; + } + } + } + + /* + * end the string and return it in original buf + */ + *t = EOS; + /* gdr: this seems to defeat the expansion we just did. */ + strcpy (src, dest); +} + + + +/* + * specialchar + * handles \(xx escape sequences for special characters (atari-specific) + */ +static int +specialchar (register char *s, register char *c) { + register char c1; + register char c2; + + c1 = *s; + c2 = *(s+1); + + /* + * symbols (std font) + */ + if (c1 == 'e' && c2 == 'm') {*c = 0x2D; return 2;} /* dash */ + if (c1 == 'h' && c2 == 'y') {*c = 0x2D; return 2;} /* hyphen */ + if (c1 == 'b' && c2 == 'u') {*c = 0xF9; return 2;} /* bullet */ + if (c1 == 's' && c2 == 'q') {*c = 0xF9; return 2;} /* square */ + if (c1 == 'r' && c2 == 'u') {*c = 0x5F; return 2;} /* rule */ + if (c1 == '1' && c2 == '2') {*c = 0xAB; return 2;} /* 1/2 */ + if (c1 == '1' && c2 == '4') {*c = 0xAC; return 2;} /* 1/4 */ + if (c1 == 'd' && c2 == 'e') {*c = 0xF8; return 2;} /* degree */ + if (c1 == 'd' && c2 == 'g') {*c = 0xBB; return 2;} /* dagger */ + if (c1 == 'f' && c2 == 'm') {*c = 0xBA; return 2;} /* dagger */ + if (c1 == 'c' && c2 == 't') {*c = 0x9B; return 2;} /* cent */ + if (c1 == 'c' && c2 == 'o') {*c = 0xBD; return 2;} /* copyrite */ + if (c1 == 'r' && c2 == 'g') {*c = 0xBE; return 2;} /* registered */ + if (c1 == 't' && c2 == 'm') {*c = 0xBF; return 2;} /* trademark */ + if (c1 == 'p' && c2 == '2') {*c = 0xFD; return 2;} /* ^2 */ + if (c1 == 'p' && c2 == '3') {*c = 0xFE; return 2;} /* ^3 */ + if (c1 == 'p' && c2 == 'n') {*c = 0xFC; return 2;} /* ^n */ + if (c1 == 'a' && c2 == 'a') {*c = 0xBA; return 2;} /* acute */ + if (c1 == 'g' && c2 == 'a') {*c = 0x60; return 2;} /* grave */ + if (c1 == 'd' && c2 == 't') {*c = 0xFA; return 2;} /* dot */ + if (c1 == 'p' && c2 == 'p') {*c = 0xBC; return 2;} /* paragraph */ + if (c1 == '^' && c2 == 'g') {*c = 0x07; return 2;} /* ring bell */ + if (c1 == 'u' && c2 == 'a') {*c = 0x01; return 2;} /* up arrow */ + if (c1 == 'd' && c2 == 'a') {*c = 0x02; return 2;} /* dn arrow */ + if (c1 == '-' && c2 == '>') {*c = 0x03; return 2;} /* rt arrow */ + if (c1 == '<' && c2 == '-') {*c = 0x04; return 2;} /* lf arrow */ + if (c1 == 'd' && c2 == 'i') {*c = 0xF6; return 2;} /* divide */ + if (c1 == 's' && c2 == 'r') {*c = 0xFB; return 2;} /* sq root */ + if (c1 == '=' && c2 == '=') {*c = 0xF0; return 2;} /* == */ + if (c1 == '>' && c2 == '=') {*c = 0xF2; return 2;} /* >= */ + if (c1 == '<' && c2 == '=') {*c = 0xF3; return 2;} /* <= */ + if (c1 == '+' && c2 == '-') {*c = 0xF1; return 2;} /* +- */ + if (c1 == '~' && c2 == '=') {*c = 0xF7; return 2;} /* ~= */ + if (c1 == 'a' && c2 == 'p') {*c = 0x7E; return 2;} /* approx */ + if (c1 == 'n' && c2 == 'o') {*c = 0xAA; return 2;} /* not */ + if (c1 == 'm' && c2 == 'o') {*c = 0xEE; return 2;} /* member */ + if (c1 == 'c' && c2 == 'a') {*c = 0xEF; return 2;} /* intersect */ + if (c1 == 'c' && c2 == 'u') {*c = 0x55; return 2;} /* union */ + if (c1 == 'i' && c2 == '1') {*c = 0xF4; return 2;} /* integral1 */ + if (c1 == 'i' && c2 == '2') {*c = 0xF5; return 2;} /* integral2 */ + if (c1 == 'b' && c2 == 'r') {*c = 0x7C; return 2;} /* box v rule */ + if (c1 == 'b' && c2 == 'v') {*c = 0x7C; return 2;} /* bold vert */ + if (c1 == 'p' && c2 == 'l') {*c = 0x2B; return 2;} /* math plus */ + if (c1 == 'm' && c2 == 'i') {*c = 0x2D; return 2;} /* math minus */ + if (c1 == 'e' && c2 == 'q') {*c = 0x3D; return 2;} /* math equal */ + if (c1 == '*' && c2 == '*') {*c = 0x2A; return 2;} /* math star */ + if (c1 == 's' && c2 == 'l') {*c = 0x2F; return 2;} /* slash */ + if (c1 == 'u' && c2 == 'l') {*c = 0x5F; return 2;} /* underrule */ + if (c1 == 's' && c2 == 'c') {*c = 0xDD; return 2;} /* section */ + + + /* + * greek + */ + if (c1 == '*' && c2 == 'a') {*c = 0xE0; return 2;} /* alpha */ + if (c1 == '*' && c2 == 'b') {*c = 0xE1; return 2;} /* beta */ + if (c1 == '*' && c2 == 'g') {*c = 0xE2; return 2;} /* gamma */ + if (c1 == '*' && c2 == 'd') {*c = 0x7F; return 2;} /* delta */ + if (c1 == '*' && c2 == 's') {*c = 0xE4; return 2;} /* sigma */ + if (c1 == '*' && c2 == 'p') {*c = 0xE3; return 2;} /* pi */ + if (c1 == '*' && c2 == 'm') {*c = 0xE6; return 2;} /* mu */ + + *c = ' '; + return 0; +} + + + + +/* + * fontchange + * handles \fx font change escapes for R,B,I,S,P (atari-specific) + * resets current and last font in dc struct (last used for .ft + * with no args) + */ +#undef SHORT_STANDOUT + +void +fontchange (char fnt, char *s) { + int tmp; + + *s = '\0'; + switch (fnt) { + case 'R': /* Times Roman */ + if (dc.dofnt == YES) { +#ifdef SHORT_STANDOUT + s[0] = E_STANDOUT; s[1] = 0; +#else + strcpy (s, e_standout); +#endif + } + dc.lastfnt = dc.thisfnt; + dc.thisfnt = 1; + break; + case 'I': /* Times italic */ + if (dc.dofnt == YES) { +#ifdef SHORT_STANDOUT + s[0] = S_STANDOUT; s[1] = 0; +#else + strcpy (s, s_standout); +#endif + } + dc.lastfnt = dc.thisfnt; + dc.thisfnt = 2; + break; + case 'B': /* Times bold */ + if (dc.dofnt == YES) { +#ifdef SHORT_STANDOUT + s[0] = S_STANDOUT; s[1] = 0; +#else + strcpy (s, s_standout); +#endif + } + dc.lastfnt = dc.thisfnt; + dc.thisfnt = 3; + break; + case 'S': /* math/special */ + *s = '\0'; + dc.lastfnt = dc.thisfnt; + dc.thisfnt = 4; + break; + case 'P': /* previous (exchange) */ + if (dc.dofnt == YES) { + if (dc.lastfnt == 1) { +#ifdef SHORT_STANDOUT + s[0] = E_STANDOUT; s[1] = 0; +#else + strcpy (s, e_standout); /* to R */ +#endif + } else if (dc.lastfnt == 2) { +#ifdef SHORT_STANDOUT + s[0] = S_STANDOUT; s[1] = 0; +#else + strcpy (s, s_standout); /* to I */ +#endif + } else if (dc.lastfnt == 3) { +#ifdef SHORT_STANDOUT + s[0] = S_STANDOUT; s[1] = 0; +#else + strcpy (s, s_standout); /* to B */ +#endif + } else { + *s = '\0'; /* nothing */ + } + } + tmp = dc.thisfnt; /* swap this/last */ + dc.thisfnt = dc.lastfnt; + dc.lastfnt = tmp; + break; + default: + *s = '\0'; + break; + } + + set_ireg (".f", dc.thisfnt, 0); +} + + + +#if 0 /* using macro version */ + +/* + * findreg + * + * find register named 'name' in pool. return index into array or -1 + * if not found. + */ +int +findreg (register char *name) { + register int i; + register char *prname; + + for (i = 0; i < MAXREGS; i++) { + prname = rg[i].rname; + if (*prname == *name && *(prname + 1) == *(name + 1)) { + break; + } + } + return ((i < MAXREGS) ? i : -1); +} + +#endif diff --git a/usr.bin/nroff/escape.h b/usr.bin/nroff/escape.h new file mode 100644 index 0000000..394b5d0 --- /dev/null +++ b/usr.bin/nroff/escape.h @@ -0,0 +1,25 @@ +/* + * $Id: escape.h,v 1.1 1997/03/14 06:22:27 gdr Exp $ + * + * FINDREG -- macro version of findreg(). + * is the register name to find + * is the returned index (-1 iff was not found) + * is a scratch integer variable + * is a scratch char * variable + */ + +#define FINDREG(name,result,scratch_p) \ +{ \ + for (result = 0; result < MAXREGS; result++) { \ + scratch_p = rg[result].rname; \ + if (*scratch_p == *name && *(scratch_p + 1) == *(name + 1)) { \ + break; \ + } \ + } \ + if (result >= MAXREGS) { \ + result = -1; \ + } \ +} + +void expesc (char *src, char *dest, size_t len); +void fontchange (char fnt, char *s); diff --git a/usr.bin/nroff/io.c b/usr.bin/nroff/io.c new file mode 100644 index 0000000..088113c --- /dev/null +++ b/usr.bin/nroff/io.c @@ -0,0 +1,325 @@ +/* + * io.c - low level I/O processing portion of nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: io.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "io________"; +#endif + +#include +#include +#include +#include +#ifdef __GNO__ +#include +#include +#else +#include "err.h" +#include "termcap.h" +#endif + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" +#include "macros.h" +#include "io.h" +#include "escape.h" + +char __i; +char *__s; +FILE *fpGLOB; + +int +tprchar(char c) +{ + return putc( c, fpGLOB ); +} + +/* + * getlin + * + * retrieve one line of input text from the push-back buffer or + * in_buf, place it in out_buf + */ + + +int +getlin (char *out_buf, FILE *in_buf) { +#if 0 + /* + * gdr: these optimizations should work, but don't as yet ... + */ + register char *q; + register int i; + int c; + int nreg; + const char *dotc = ".c"; + + + i = 0; + + /* get characters from the push-back buffer */ + q = out_buf; + while ((i < MAXLINE - 1) && (mac.ppb >= mac.pbb)) { +#if 1 /* doesn't happen */ + c = *mac.ppb--; + if (c == EOF) { + *q = EOS; + return (i == 0) ? EOF : i; + } + *q++ = c; +#else + *q++ = c = *mac.ppb--; +#endif + if (c == '\n') { + break; + } + i++; + } + *q = EOS; + + /* get characters from stream */ + c = MAXLINE - i; + if (c > 0) { + fgets(q, c, in_buf); + } + + FINDREG(dotc, nreg, q); + if (nreg > 0) { + set_ireg (dotc, rg[nreg].rval + 1, 0); + } + + i = strlen(out_buf); + assert(i || feof(in_buf)); + return (i == 0) ? EOF : i; +#else /* gdr: old way */ + register char *q; + register int i; + int c; + int nreg; + const char *dotc = ".c"; + + q = out_buf; + for (i = 0; i < MAXLINE - 1; ++i) { + c = NGETC (in_buf); + if (c == EOF) { + *q = EOS; + c = strlen (out_buf); + return (c == 0 ? EOF : c); + } + *q++ = c; + if (c == '\n') { + break; + } + } + *q = EOS; + + FINDREG(dotc, nreg, q); + if (nreg > 0) { + set_ireg (dotc, rg[nreg].rval + 1, 0); + } + + return (strlen (out_buf)); +#endif +} + + +/* + * pbstr + * Push back string into input stream + */ +void +pbstr (char *str) { + char *p; + + if (str == NULL) { + return; + } + p = str + strlen(str) - 1; + while (p >= str) { + PUTBAK(*p); + --p; + } + return; +} + + +/* + * put + * put out line with proper spacing and indenting + */ +void +put (char *p) { + register int j; + char os[MAXLINE]; + + if (pg.lineno == 0 || pg.lineno > pg.bottom) { + phead (); + } + if (dc.prflg == TRUE) { + if (!dc.bsflg) { + if (strkovr (p, os) == TRUE) { + for (j = 0; j < pg.offset; ++j) { + PRCHAR2(' ', out_stream); + } + for (j = 0; j < dc.tival; ++j) { + PRCHAR2(' ', out_stream); + } + putlin (os, out_stream); + } + } + for (j = 0; j < pg.offset; ++j) { + PRCHAR2(' ', out_stream); + } + for (j = 0; j < dc.tival; ++j) { + PRCHAR2(' ', out_stream); + } + putlin (p, out_stream); + } + dc.tival = dc.inval; + skip (MIN(dc.lsval - 1, pg.bottom - pg.lineno)); + pg.lineno = pg.lineno + dc.lsval; + set_ireg ("ln", pg.lineno, 0); + if (pg.lineno > pg.bottom) { + pfoot (); +#ifdef GEMDOS + if (stepping) { + wait_for_char(); + } +#endif + } +} + +/* + * putlin + * output a null terminated string to the file + * specified by pbuf. + */ +void +putlin (char *p, FILE *pbuf) +{ + while (*p != EOS) { + PRCHAR(*p, pbuf); + p++; + } +} + + + +#ifdef NOT_USED + +/* + * prchar + * print character with test for printer + */ +void +prchar (char __c, FILE *fp) +{ +#if 0 +/* this really slows things down. it should be fixed. for now, ignore + * line printer... + */ + if (fp == stdout) { + putc (c, fp); + } else { + putc_lpr (c, fp); + } +#endif + +#if 0 + switch(c) { + case S_STANDOUT: + fpGLOB = fp; + tputs(s_standout,1,tprchar); + break; + case E_STANDOUT: + fpGLOB = fp; + tputs(e_standout,1,tprchar); + break; + case S_BOLD: + fpGLOB = fp; + tputs(s_bold,1,tprchar); + break; + case E_BOLD: + fpGLOB = fp; + tputs(e_bold,1,tprchar); + break; + case S_ITALIC: + fpGLOB = fp; + tputs(s_italic,1,tprchar); + break; + case E_ITALIC: + fpGLOB = fp; + tputs(e_italic,1,tprchar); + break; + case 13: + break; + default: + putc(c, fp); + } +#else + /* + * Don't use a case statement here; the macros are out of range + * for some compilers. + */ + if (__c == S_STANDOUT) { + fpGLOB = fp; + tputs(s_standout,1,tprchar); + } else if (__c == E_STANDOUT) { + fpGLOB = fp; + tputs(e_standout,1,tprchar); + } else if (__c == S_BOLD) { + fpGLOB = fp; + tputs(s_bold,1,tprchar); + } else if (__c == E_BOLD) { + fpGLOB = fp; + tputs(e_bold,1,tprchar); + } else if (__c == S_ITALIC) { + fpGLOB = fp; + tputs(s_italic,1,tprchar); + } else if (__c == E_ITALIC) { + fpGLOB = fp; + tputs(e_italic,1,tprchar); + } else if (__c == 13) { + ; + } else { + putc(c, fp); + } +#endif + +} + +/* + * putc_lpr + * write char to printer + */ +void +putc_lpr (char c, FILE *fp) +{ + putc (c, fp); +} + +#endif /* NOT_USED */ + diff --git a/usr.bin/nroff/io.h b/usr.bin/nroff/io.h new file mode 100644 index 0000000..cb1800d --- /dev/null +++ b/usr.bin/nroff/io.h @@ -0,0 +1,75 @@ +/* + * $Id: io.h,v 1.1 1997/03/14 06:22:27 gdr Exp $ + * + * prchar + * print character with test for printer -- macro version + * + * profiling has shown that this is where we spend most of our time + * Don't use a case statement here; the macros are out of range + * for some compilers. + */ + +#if 0 + +#define PRCHAR(__c, fp) \ +{ \ + if (__c == S_STANDOUT) { \ + fpGLOB = fp; \ + tputs(s_standout,1,tprchar); \ + } else if (__c == E_STANDOUT) { \ + fpGLOB = fp; \ + tputs(e_standout,1,tprchar); \ + } else if (__c == S_BOLD) { \ + fpGLOB = fp; \ + tputs(s_bold,1,tprchar); \ + } else if (__c == E_BOLD) { \ + fpGLOB = fp; \ + tputs(e_bold,1,tprchar); \ + } else if (__c == S_ITALIC) { \ + fpGLOB = fp; \ + tputs(s_italic,1,tprchar); \ + } else if (__c == E_ITALIC) { \ + fpGLOB = fp; \ + tputs(e_italic,1,tprchar); \ + } else if (__c == 13) { \ + ; \ + } else { \ + putc(c, fp); \ + } \ +} + +#else + + +#define PRCHAR(c, fp) \ +{ \ + __i = c; \ + switch(__i) { \ + case S_STANDOUT: __s = s_standout; break; \ + case E_STANDOUT: __s = e_standout; break; \ + case S_BOLD: __s = s_bold; break; \ + case E_BOLD: __s = e_bold; break; \ + case S_ITALIC: __s = s_italic; break; \ + case E_ITALIC: __s = e_italic; break; \ + case 13: __s = (char *)0x01L; break; \ + default: __s = NULL; \ + } \ + switch((unsigned long)__s) { \ + case 0L: putc(c, fp); break; \ + case 1L: ; break; \ + default: fpGLOB = fp; tputs(__s, 1, tprchar); \ + } \ +} + +#define PRCHAR2(c,fp) putc(c,fp) + +extern char __i; +extern char *__s; +extern FILE *fpGLOB; + +int getlin (char *p, FILE *in_buf); +void pbstr (char *str); +void put (char *p); +void putlin (char *p, FILE *pbuf); +int tprchar(char c); +#endif diff --git a/usr.bin/nroff/low.c b/usr.bin/nroff/low.c new file mode 100644 index 0000000..b1b9809 --- /dev/null +++ b/usr.bin/nroff/low.c @@ -0,0 +1,928 @@ +/* + * low.c - misc low-level functions for nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: low.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "low_______"; +#endif + +#include +#include +#include +#include +#ifdef __GNO__ +#include +#else +#include "err.h" +#endif + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" + + +/* convert ascii character to decimal */ +#define ATOD(c) (((c) < '0') || ((c) > '9')) ? -1 : ((c) - '0') + +#if 0 /* not currently used */ +static void inptobu (char *); /* convert input units to b.u. */ +static void butochar (char *); /* convert b.u. to char spaces */ +#endif + +/* + * ctod + * + * convert string to decimal. processes only positive values. + * this takes a constant like "1", "1.0i", etc. + * + * Returns converted value (including zero) on success, zero on failure. + */ +int +ctod (char *p) { + long val; + int d; + char *pp = p; + char *ptmp; + int rside = 0; + int lside = 0; + int has_rside = 0; + int has_lside = 0; + + if (*p == EOS) { + return 0; + } + + ptmp = skipwd (pp); + pp = --ptmp; + + switch (*pp) { + case 'i': + case 'c': + val = 0L; + while (*p != EOS && isdigit (*p)) { + has_lside++; + lside = ATOD(*p); + p++; + if (lside == -1) { + break; + } + val = 10L * val + (long) lside; + } + lside = (int) val; + if (*p == '.') { + p++; + val = 0L; + while (*p != EOS && isdigit (*p)) { + has_rside++; + rside = ATOD(*p); + p++; + if (rside == -1) { + break; + } + val = 10L * val + (long) rside; + if (has_rside > 2) { /* more than enough */ + break; + } + } + rside = (int) val; + } + + /* + * now put it together. 1.0i -> 240, 1.50i -> 360, etc. + */ + val = 0L; + if (has_lside) { + val = (long) lside * BU_INCH; + } + switch (has_rside) { + case 1: + val = val + ((long) rside * BU_INCH / 10L); + break; + case 2: + val = val + ((long) rside * BU_INCH / 100L); + break; + case 3: + val = val + ((long) rside * BU_INCH / 1000L); + break; + default: + break; + } + + if (*pp == 'c') { + val = (val * BU_CM) / BU_INCH; + } + + /* + * for now we convert to basic char size, 1 em... + */ + val = val / BU_EM; + break; + + case 'P': + case 'm': + case 'n': + case 'p': + case 'u': + case 'v': + val = 0L; + while (*p != EOS) { + d = ATOD(*p); + p++; + if (d == -1) + break; + val = 10L * val + (long) d; + } + switch (*pp) { + case 'P': + val = val * BU_PICA; + break; + case 'p': + val = val * BU_POINT; + break; + case 'u': + val = val * BU_BU; + break; + case 'm': + val = val * BU_EM; + break; + case 'n': + val = val * BU_EN; + break; + case 'v': + val = val * BU_EM; + break; + } + + /* + * for now we convert to basic char size, 1 em... + */ + val = val / BU_EM; + break; + + default: + /* + * this is the default behavior. it SHOULD make things + * compatible with the old way... + */ + val = 0L; + while (*p != EOS) { + d = ATOD(*p); + p++; + if (d == -1) { + break; + } + val = 10L * val + (long) d; + } + break; + } + + return (int) val; +} + +#if 0 /* not currently used */ + +/* + * inptobu + * + * convert input units to b.u. + */ +static void +inptobu (char *ps) +{ + return; +} + +/* + * butochar + * + * convert b.u. to char spaces + */ +static void +butochar (char *ps) +{ + return; +} + +#endif /* 0 */ + +/* + * skipbl + * + * skip blanks and tabs in character buffer. return ptr to first + * non-space or non-tab char. this could mean EOS or \r or \n. + */ +char * +skipbl (register char *p) +{ + while ((*p != EOS) && (*p == ' ' || *p == '\t')) { + p++; + } + return (p); +} + + +/* + * skipwd + * + * skip over word and punctuation. anything but space,\t,\r,\n, and EOS + * is skipped. return ptr to the first of these found. + */ +char * +skipwd (register char *p) { + while (*p != EOS && *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n') { + p++; + } + return (p); +} + + +/* + * nroffSpace + * + * space vertically n lines. this does header and footer also. + */ +void +nroffSpace (int n) { + robrk (); + if (pg.lineno > pg.bottom) { + return; + } + if (pg.lineno == 0) { + phead (); + } + skip (MIN(n, pg.bottom + 1 - pg.lineno)); + pg.lineno += n; + set_ireg ("ln", pg.lineno, 0); + if (pg.lineno > pg.bottom) { + pfoot (); + } +} + + +/* + * getfield + * get field from title + */ +char * +getfield (register char *p, register char *q, char delim) { + while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS) { + *q++ = *p++; + } + *q = EOS; + if (*p == delim) { + ++p; + } + return p; +} + + +/* + * getwrd + * + * get non-blank word from p0 into p1. + * return number of characters processed. + */ +int +getwrd (register char *src, register char *dest) { +#if 0 /* gdr changes */ + char *orgsrc, *orgdest; + + orgsrc = src; + orgdest = dest; + + /* + * skip leading whitespace + */ + while (*src == ' ' || *src == '\t') { + src++; + } + + /* find end of word */ + while (*src != '\0' && !isspace(*src)) { + *dest++ = *src++; + } + + /* I don't understand what this is supposed to achieve */ +#ifdef WHATTHEFUCK + assert (dest - orgdest >= 1); /* gdr */ + c = *(dest - 1); + if (c == '"') { + asssert(dest - orgdest >= 2); /* gdr */ + c = *(dest - 2); + } + if (c == '?' || c == '!') { + *dest++ = ' '; + } + if (c == '.' && (*src == '\n' || *src == '\r' || islower (*p))) { + *dest++ = ' '; + } +#endif /* WHATTHEFUCK */ + *dest = EOS; + + return src - orgsrc; +#elif 1 + char c; + register int i; + register char *p; + char *orgsrc, *orgdest; + + orgsrc = src; + orgdest = dest; + /* + * init counter... + */ + i = 0; + + /* + * skip leading whitespace + */ + while (*src == ' ' || *src == '\t') { + ++i; + ++src; + } + + /* + * set ptr and start to look for end of word + */ + p = src; + while (*src != ' ' && *src != EOS && *src != '\t') { + if (*src == '\n' || *src == '\r') { + break; + } + *dest = *src++; + ++dest; + ++i; + } + + if (dest > orgdest) { + c = *(dest - 1); + if (c == '"' && (dest > orgdest + 1)) { + c = *(dest - 2); + } + if (c == '?' || c == '!') { + *dest++ = ' '; + ++i; + } + if (c == '.' && (*src == '\n' || *src == '\r' || islower (*p))) { + *dest++ = ' '; + ++i; + } + } + *dest = EOS; + + return (i); +#else + char c; + register int i; + register char *p; + char *orgsrc, *orgdest; + + orgsrc = src; + orgdest = dest; + /* + * init counter... + */ + i = 0; + + /* + * skip leading whitespace + */ + while (*src == ' ' || *src == '\t') { + ++i; + ++src; + } + + /* + * set ptr and start to look for end of word + */ + p = src; + while (*src != ' ' && *src != EOS && *src != '\t') { + if (*src == '\n' || *src == '\r') { + break; + } + *dest = *src++; + ++dest; + ++i; + } + + if (dest > orgdest) { + c = *(dest - 1); + if (c == '"') { + ASSERT(dest > orgdest + 1, + ("%s:%d: array indexing error", __FILE__, __LINE__)); + c = *(dest - 2); + } + if (c == '?' || c == '!') { + *dest++ = ' '; + ++i; + } + if (c == '.' && (*src == '\n' || *src == '\r' || islower (*p))) { + *dest++ = ' '; + ++i; + } + } + *dest = EOS; + + return (i); +#endif +} + + +/* + * countesc + * count atari escape sequence characters in given null-terminated + * string + */ + +#define ESC 27 + +int +countesc (register char *p) { + register char *pp; + register int num; + + pp = p; + num = 0; + + while (*pp != EOS) { + if (*pp == ESC) { + /* + * count escape char (atari-specific, vt52) + * generally only p,q,b,and c will show up... + */ + switch (*(pp+1)) { + case 'A': /* ESC-a */ + case 'B': + case 'C': + case 'D': + case 'E': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'd': + case 'e': + case 'f': + case 'j': + case 'k': + case 'l': + case 'o': + case 'p': + case 'q': + case 'v': + case 'w': + num += 2; + break; + case 'b': /* ESC-a-b */ + case 'c': + num += 3; + break; + case 'Y': /* ESC-a-b-c */ + case '[': /* Esc [ 7 m */ + num += 4; + break; + default: + num += 1; + break; + } + } + pp++; + } + return num; +} + + +/* + * itoda + * convert integer to decimal ascii string + * + * Pre: is the number to convert + *

is the output buffer + * is the number of bytes in the output buffer + * + * Post:

contains an ascii representation of + * + * Returns: + */ +int +itoda (int value, register char *p, register int size) { +#if 0 + int len; + /* + * buffer must be big enough for representation of largest integer, + * plus 1 byte for sign, plus 1 byte for terminator. On a 32-bit + * machine this is 10+1+1 == 12 bytes. + */ +#define MAX_INT_LENGTH 15 + char buffer[MAX_INT_LENGTH]; + + len = sprintf(buffer, "%d", value); + if (len == EOF) { + errx(1, "itoda failed with EOF"); + } + if (len >= size) { + errx(1, "%s:%d: buffer overflow", __FILE__, __LINE__); + } + strncpy(p, buffer, len); + return len; +#else + + int i, j, aval; + char c[20]; + + aval = abs (value); + c[0] = EOS; + i = 1; + do { + c[i++] = (aval % 10) + '0'; + aval /= 10; + } while (aval > 0 && i <= size); + + if (value < 0 && i <= size) { + c[i++] = '-'; + } + for (j = 0; j < i; ++j) { + *p++ = c[i - j - 1]; + } + + return i; +#endif +} + + +/* + * itoROMAN + * convert integer to upper roman. must be positive + */ +int +itoROMAN (int value, register char *p, register int size) { + register int i; + register int j; + register int aval; + char c[100]; + int rem; + + aval = abs (value); + c[0] = EOS; + i = 1; + + /* + * trivial case: + */ + if (aval == 0) { + c[i++] = '0'; + goto done_100; + } + + /* + * temporarily mod 100... + */ + aval = aval % 100; + + if (aval > 0) { + /* + * build backward + * + * | I| 1 + * | II| 2 + * | III| 3 + * | VI| 4 + * | V| 5 + * | IV| 6 + * | IIV| 7 + * | IIIV| 8 + * | XI| 9 + * | X| 0 + * | IX| 11 + * | IIX| 12 + */ + if ((aval % 5 == 0) && (aval % 10 != 0)) { /* 5 */ + c[i++] = 'V'; + } else { + rem = aval % 10; + if (rem == 9) { /* 9 */ + c[i++] = 'X'; + c[i++] = 'I'; + }else if (rem == 8) { /* 8 */ + c[i++] = 'I'; + c[i++] = 'I'; + c[i++] = 'I'; + c[i++] = 'V'; + } else if (rem == 7) { /* 7 */ + c[i++] = 'I'; + c[i++] = 'I'; + c[i++] = 'V'; + } else if (rem == 6) { /* 6 */ + c[i++] = 'I'; + c[i++] = 'V'; + } else if (rem == 4) { /* 4 */ + c[i++] = 'V'; + c[i++] = 'I'; + } else { /* 3,2,1 */ + for (j = 0; j < rem; j++) { + c[i++] = 'I'; + } + } + } + + aval /= 10; + if (aval == 0) { + goto done_100; + } + + rem = aval % 10; + if (rem == 4) { + c[i++] = 'L'; + c[i++] = 'X'; + } else if (rem == 5) { + c[i++] = 'L'; + } else if (rem < 4) { + for (j = 0; j < rem; j++) { + c[i++] = 'X'; + } + } else { + for (j = 0; j < rem - 5; j++) { + c[i++] = 'X'; + } + c[i++] = 'L'; + } + } + + + done_100: + /* + * divide by 100 (they are done) and temp mod by another 10 + */ + aval = abs (value); + aval /= 100; + + if (aval > 0) { + rem = aval % 10; + if (rem == 4) { + c[i++] = 'D'; + c[i++] = 'C'; + } + if (rem == 5) { + c[i++] = 'D'; + } else if (rem < 4) { + for (j = 0; j < rem; j++) { + c[i++] = 'C'; + } + } else if (rem == 9) { + c[i++] = 'M'; + c[i++] = 'C'; + } else if (rem < 9) { + for (j = 0; j < rem - 5; j++) { + c[i++] = 'C'; + } + c[i++] = 'D'; + } + } + + aval /= 10; + + if (aval > 0) { + rem = aval % 10; + if (rem < 4) { + for (j = 0; j < rem; j++) { + c[i++] = 'M'; + } + } + } + + if (value < 0) { + c[i++] = '-'; + } + + for (j = 0; j < i; ++j) { + *p++ = c[i - j - 1]; + } + + return i; +} + + +/* + * itoroman + * convert integer to lower roman + */ +int +itoroman (int value, char *p, int size) +{ + register int i; + register int len; + char c[100]; + + c[0] = EOS; + len = itoROMAN (value, c, size); + + for (i = 0; i < len; i++) { + p[i] = c[i]; + if (isalpha (p[i])) { + p[i] = tolower (c[i]); + } + } + return len; +} + +/* + * itoLETTER + * convert integer to upper letter value: 0,A,B,C,...,AA,AB,AC,... + */ +int +itoLETTER (int value, register char *p, register int size) { + register int i; + register int j; + register int aval; + char c[20]; + + aval = abs (value); + c[0] = EOS; + i = 1; + + /* + * 1 based: + * + * 0 0 + * 1 A + * 25 Z + * 26 AA + * 51 AZ + * 52 AAA + * ... + */ + if (aval == 0) { + c[i++] = '0'; + } else if (aval < 27) { + c[i++] = aval - 1 + 'A'; + } else { + do { + c[i++] = ((aval - 1) % 26) + 'A'; + aval = (aval - 1) / 26; + } while (aval > 0 && i <= size); + } + + if (value < 0 && i <= size) { + c[i++] = '-'; + } + + for (j = 0; j < i; ++j) { + *p++ = c[i - j - 1]; + } + + return i; +} + + +/* + * itoletter + * convert integer to upper letter value: 0,a,b,c,...,aa,ab,ac,... + */ +int +itoletter (int value, register char *p, register int size) { + register int i; + register int j; + register int aval; + char c[20]; + + aval = abs (value); + c[0] = EOS; + i = 1; + + /* + * 1 based: + * + * 0 0 + * 1 A + * 25 Z + * 26 AA + * 51 AZ + * 52 AAA + * ... + */ + if (aval == 0) { + c[i++] = '0'; + } else if (aval < 27) { + c[i++] = aval - 1 + 'a'; + } else { + do { + c[i++] = ((aval - 1) % 26) + 'a'; + aval = (aval - 1) / 26; + } while (aval > 0 && i <= size); + } + + if (value < 0 && i <= size) { + c[i++] = '-'; + } + + for (j = 0; j < i; ++j) { + *p++ = c[i - j - 1]; + } + + return i; +} + + +#if 0 /* min, max not needed */ +/* + * min + * find minimum of two integer ONLY + */ +#ifdef min +#undef min +#endif + +int +min (register int v1, register int v2) { + return ((v1 < v2) ? v1 : v2); +} + + +/* + * max + * find maximum of two integers ONLY + */ + +#ifdef max +#undef max +#endif + +int +max (register int v1, register int v2) { + return ((v1 > v2) ? v1 : v2); +} +#endif /* 0 */ + +/* + * err_exit + * exit cleanly on fatal error (close files, etc). also handles normal + * exit. + */ +void +err_exit (int code) { + if (err_stream != stderr && err_stream != (FILE *) 0) { + /* + * not going to stderr (-o file) + */ + fflush (err_stream); + fclose (err_stream); + } + if (debugging && dbg_stream != stderr && dbg_stream != (FILE *) 0) { + fflush (dbg_stream); + fclose (dbg_stream); + } + if (out_stream != stdout && out_stream != (FILE *) 0) { + /* + * not going to stdout (-l) + */ + fflush (out_stream); + fclose (out_stream); + } + +#ifdef GEMDOS + if (hold_screen) { + wait_for_char(); + } +#endif + exit(code); +} + + + +#ifdef GEMDOS +#include + +/* + * Wait for a character + */ +void +wait_for_char (void) { + printf ("enter any key..."); fflush (stdout); + Cconin (); +} +#endif + diff --git a/usr.bin/nroff/macros.c b/usr.bin/nroff/macros.c new file mode 100644 index 0000000..23a27d0 --- /dev/null +++ b/usr.bin/nroff/macros.c @@ -0,0 +1,692 @@ +/* + * macros.c - macro input/output processing for nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: macros.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "macros____"; +#endif + +#include +#include +#include +#include "err.h" + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" +#include "macros.h" +#include "io.h" + +static int colmac (char *p, char *d, int i); +static int putmac (char *name, char *p); + +void +initMacros (void) { + memset(mac.mnames, 0, MXMDEF * sizeof(char*)); + memset(mac.mb, 0, MACBUF); + memset(mac.pbb, 0, MAXLINE); +#if 0 + for (i = 0; i < MXMDEF; ++i) { + mac.mnames[i] = NULL_CPTR; + } + for (i = 0; i < MACBUF; ++i) { + mac.mb[i] = EOS; + } + for (i = 0; i < MAXPBB; ++i) { + mac.pbb[i] = EOS; + } +#endif + mac.lastp = 0; + mac.emb = &mac.mb[0]; + mac.ppb = NULL_CPTR; + +} + +/* + * defmac + * + * Define a macro. top level, read from stream. + * + * we should read macro without interpretation EXCEPT: + * + * 1) number registers are interpolated + * 2) strings indicated by \* are interpolated + * 3) arguments indicated by \$ are interpolated + * 4) concealed newlines indicated by \(newline) are eliminated + * 5) comments indicated by \" are eliminated + * 6) \t and \a are interpreted as ASCII h tab and SOH. + * 7) \\ is interpreted as backslash and \. is interpreted as a period. + * + * currently, we do only 3. a good place to do it would be here before + * putmac, after colmac... + */ + +void +defmac (char *line, FILE *infp) +{ + register char *q; + register int i; + char name[MNLEN]; + char defn[MXMLEN]; + char newend[10]; + + +#ifdef BORK + fprintf(stderr, "DEBUG: defmac: \"%s\"\n", line); +#endif + + /* + * terminate defn; if it's still this way when we're ready to putmac(), + * then the macro definition was empty and we're going to ignore it. + */ + defn[0] = '\0'; + + /* + * skip the .de and get to the name... + */ + q = skipwd (line); + q = skipbl (q); + + /* + * q now points to the name. Copy it into the "name" buffer. + * Make sure it is valid (i.e. first char is alpha...). The + * getwrd function returns the length of the word. + */ + i = getwrd (q, name); + if (!isprint (*name)) { + errx(-1, "missing or illegal macro definition name"); + } + + /* + * truncate to 2 char max name. + */ + if (i > 2) { + name[2] = EOS; + } + + /* + * skip the name and see if we have a new end defined... + */ + q = skipwd (line); + q = skipbl (q); + for (i = 0; i < 10; i++) { + newend[i] = EOS; + } + + for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++) { + newend[i] = q[i]; + } + + /* + * read a line from input stream until we get the end of macro + * command (.en or ..). actually. we should have read the next + * field just above here to get the .de NA . or .de NA en string + * to be new end of macro. + */ + i = 0; + while (getlin (line, infp) != EOF) { +#ifdef BORK + fprintf(stderr,"DEBUG: %s:%d line is \"%s\"\n", __FILE__, __LINE__, + line); +#endif + if (line[0] == dc.cmdchr && line[1] == '\\' && line[2] == '\"') { + /* + * comment, ignore it + */ + continue; + } + if (line[0] == dc.cmdchr && newend[0] != EOS + && line[1] == newend[0] && line[2] == newend[1]) { + /* + * replacement end found + */ + break; + } + if (line[0] == dc.cmdchr && line[1] == 'e' && line[2] == 'n') { + /* + * .en found + */ + break; + } + if (line[0] == dc.cmdchr && line[1] == dc.cmdchr) { + /* + * .. found + */ +#ifdef BORK + fprintf(stderr,"DEBUG: %s:%d: dot-dot found\n",__FILE__,__LINE__); +#endif + break; + } + + /* + * collect macro from the line we just read. all this does + * is put it in the string defn. + */ +#ifdef BORK + fprintf(stderr,"DEBUG: %s:%d: collecting macro\n",__FILE__,__LINE__); +#endif + if ((i = colmac (line, defn, i)) == ERR) { + errx(1, "macro definition too long"); + } + } + + /* + * store the macro + */ + if (!ignoring && defn[0] != '\0') { + if (putmac (name, defn) == ERR) { + errx(-1, "macro definition table full"); + } + } +} + + +/* + * colmac + * + * Collect macro definition from input stream + */ +static int +colmac (char *p, char *d, int i) { + + char *pstart; + int istart; + + pstart = p; + istart = i; + while (*p != EOS) { + /* + * are we over the length limit for a single macro? + */ + if (i >= MXMLEN - 1) { + d[i - 1] = EOS; + return (ERR); + } + + /* + * "i break for comments..." + */ + if (*p == '\\' && *(p+1) == '\"') { + /* + * first back over any whitespace between comment + * start and last character in line. remember to + * decrement counter i, too... + */ + p--; + while (isspace (*p) && p > pstart && i > istart) { + p--; + i--; + } + + /* + * now skip over the comment until we reach the + * trailing newline + */ + while (*p != EOS) { + if (*p == '\n' || *p == '\r') { + break; + } + p++; + } + } + + /* + * skip quoted things + */ + if (*p == '\\' && *(p+1) == '\\') { + p++; + } + + /* + * copy it + */ + d[i++] = *p++; + } + d[i] = EOS; + return (i); +} + + +/* + * putmac + * + * Put macro definition into table + * + * NOTE: any expansions of things like number registers SHOULD + * have been done already. + */ + +static int +putmac (char *name, char *p) { + + /* + * any room left? (did we exceed max number of possible macros) + */ + if (mac.lastp >= MXMDEF) { + return (ERR); + } + + /* + * will new one fit in big buffer? + */ +#ifdef DEBUG + strlen(name); + strlen(p); +#endif + if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF]) { + return (ERR); + } + + /* + * add it... + * + * bump counter, set ptr to name, copy name, copy def. + * finally increment end of macro buffer ptr (emb). + * + * macro looks like this in mb: + * + * mac.mb[MACBUF] size of total buf + * lastp < MXMDEF number of macros possible + * *mnames[MXMDEF] -> names, each max length + * ..._____________________________...____________________... + * / / /|X|X|0|macro definition |0| / / / / / / / + * .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_... + * ^ + * | + * \----- mac.mnames[mac.lastp] points here + * + * both the 2 char name (XX) and the descripton are null term and + * follow one after the other. + */ + ++mac.lastp; + mac.mnames[mac.lastp] = mac.emb; + strcpy (mac.emb, name); + strcpy (mac.emb + strlen (name) + 1, p); + mac.emb += strlen (name) + strlen (p) + 2; + + return (OK); +} + +/* + * getmac + * + * Get (lookup) macro definition from namespace + */ +char * +getmac (char *name) { + int i; + + /* + * loop for all macros, starting with last one + */ + for (i = mac.lastp; i >= 0; --i) { + /* + * is this REALLY a macro? + */ + if (mac.mnames[i]) { + /* + * if it compares, return a ptr to it + */ + if (!strcmp (name, mac.mnames[i])) { +#if 0 /* !!!debug */ + puts (mac.mnames[i]); +#endif + + if (mac.mnames[i][1] == EOS) { + return (mac.mnames[i] + 2); + } else { + return (mac.mnames[i] + 3); + } + /*NOTREACHED*/ + } + } + } + + /* + * none found, return null + */ + return (NULL_CPTR); +} + + +/* + * maceval + * + * Evaluate macro expansion from p into m + */ +void +maceval (char *p, char *m) { + register int i; + char *argp[15]; + char c; + int xc; + + /* + * replace command char with EOS + */ + *p++ = EOS; + + /* + * initialize argp array to substitute command + * string for any undefined argument + * + * NO!!! this is fixed... + */ +#if 0 + for (i = 0; i < 10; ++i) { + argp[i] = p; + } +#endif + + /* + * skip the command name + */ + p = skipwd (p); + *p++ = EOS; + + /* + * loop for all $n variables... + */ + for (i = 0; i < 10; ++i) { + /* + * get to substituted param and if no more, reset remaining + * args to NULL and stop. using "i" here IS ok... + */ + p = skipbl (p); + if (*p == '\r' || *p == '\n' || *p == EOS) { + DEBUGGING(("maceval: set_ireg(.$, %d, 0)", i)); + + set_ireg (".$", i, 0); + for ( ; i < 10; i++) { + argp[i] = NULL_CPTR; + } + break; + } + + /* + * ...otherwise, see if this param is quoted. if it is, + * it is all one parameter, even with blanks (but not + * newlines...). look for another "c" (which is the quote). + * + * if no quote, just read the arg as a single word and null + * terminate it. + */ + if (*p == '\'' || *p == '"') { + c = *p++; + argp[i] = p; + while (*p != c && *p != '\r' && *p != '\n' && *p != EOS) { + ++p; + } + *p++ = EOS; + } else { + argp[i] = p; + p = skipwd (p); + *p++ = EOS; + } + } + + /* + * m contains text of the macro. p contained the input line. + * here we start at the end of the macro def and see if there + * are any $n thingies. go backwards. + */ + for (i = strlen (m) - 1; i >= 0; --i) { + /* + * found a $. + */ + if (i > 0 && m[i - 1] == '$') { + if (!isdigit (m[i])) { + /* + * it wasn't a numeric replacement arg so + * push this char back onto input stream + */ + PUTBAK(m[i]); + } else { + /* + * it WAS a numeric replacement arg. so we + * want to push back the appropriate macro + * invocation arg. m[i]-'0' is the numerical + * value of the $1 thru $9. if the arg is + * not there, argp[n] will be (char *) 0 + * and pbstr will do nothing. + */ + xc = m[i] - '1'; + if (argp[xc]) { + pbstr (argp[xc]); + } + --i; + } + } else { + /* + * no $ so push back the char... + */ + PUTBAK(m[i]); + } + } + + /* + * at this point, the iobuf will hold the new macro command, full + * expanded for $n things. the return gets us right back to the + * main loop in main() and we parse the (new) command just as if + * it were read from a file. + */ +} + + +/* + * printmac + * print macro data: + * opt print + * === ===== + * 0 name and size + * 1 total size + * 2 full information + */ + +void +printmac (int opt) { + register int i; /* was long, minix needs int */ + register long localSpace; + register long totalspace; + register char *pname; + register char *pdef; + + + localSpace = 0L; + totalspace = 0L; + + fflush (out_stream); + fflush (err_stream); + + for (i = mac.lastp; i >= 0; --i) { + /* + * is this REALLY a macro? + */ + if (mac.mnames[i]) { + pname = (char *) (mac.mnames[i]); + pdef = pname + 3; + if (*(pname + 1) == '\0') { + pdef = pname + 2; + } + + localSpace = (long) strlen (pdef); + totalspace += localSpace; + + switch (opt) { + case 0: + fprintf (err_stream, "%s %ld\n", pname, localSpace); + break; + case 2: + fprintf (err_stream, "%s %ld\n", pname, localSpace); + fprintf (err_stream, "%s\n", pdef); + break; + case 1: + default: + break; + } + } + } + fprintf (err_stream, "Total space: %ld\n", totalspace); +} + + + + +/* + * putstr + * + * Put string definition into (macro) table + * + * NOTE: any expansions of things like number registers SHOULD + * have been done already. strings and macros share mb buffer + */ + +int +putstr (const char *name, const char *p) { + + /* + * any room left? (did we exceed max number of possible macros) + */ + if (mac.lastp >= MXMDEF) { + return (ERR); + } + + /* + * will new one fit in big buffer? + */ + if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF]) { + return (ERR); + } + + + /* + * add it... + * + * bump counter, set ptr to name, copy name, copy def. + * finally increment end of macro buffer ptr (emb). + * + * string looks like this in mb: + * + * mac.mb[MACBUF] size of total buf + * lastp < MXMDEF number of macros/strings possible + * *mnames[MXMDEF] -> names, each max length + * ...______________________________...____________________... + * / / /|X|X|0|string definition |0| / / / / / / / + * .../_/_/_|_|_|_|_________________...___|_|/_/_/_/_/_/_/_... + * ^ + * | + * \----- mac.mnames[mac.lastp] points here + * + * both the 2 char name (XX) and the descripton are null term and + * follow one after the other. + */ + ++mac.lastp; + mac.mnames[mac.lastp] = mac.emb; + strcpy (mac.emb, name); + strcpy (mac.emb + strlen (name) + 1, p); + mac.emb += strlen (name) + strlen (p) + 2; + return (OK); +} + + +/* + * getstr + * Get (lookup) string definition from namespace + */ +char * +getstr (char *name) { + int i; + + /* + * loop for all macros, starting with last one + */ + for (i = mac.lastp; i >= 0; --i) { + /* + * is this REALLY a macro? + */ + if (mac.mnames[i]) { + /* + * if it compares, return a ptr to it + */ + if (!strcmp (name, mac.mnames[i])) { +#if 0 /* !!!debug */ + puts (mac.mnames[i]); +#endif + if (mac.mnames[i][1] == EOS) { + return (mac.mnames[i] + 2); + } else { + return (mac.mnames[i] + 3); + } + } + } + } + + /* + * none found, return null + */ + return NULL; +} + + +#ifdef NOT_USED + +/* + * putbak + * + * Push character back into input stream. we use the push-back buffer + * stored with macros. + */ +void +putbak (char c) +{ + if (mac.ppb == NULL) { /* first time executing this code */ + mac.ppb = mac.pbb; + *mac.ppb = c; + } else if (mac.ppb < mac.pbb + MAXPBB) { + mac.ppb++; + *(mac.ppb) = c; + } else { + errx(-1, "push back buffer overflow (%d chars)", MAXPBB); + } +} + + + +/* + * ngetc + * get a character from the putback buffer or from + */ +int ngetc (FILE *infp) +{ + register int c; + + if (mac.ppb >= mac.pbb) { + c = *mac.ppb--; + } else { + c = getc (infp); + } + return (c); +} +#endif /* NOT_USED */ diff --git a/usr.bin/nroff/macros.h b/usr.bin/nroff/macros.h new file mode 100644 index 0000000..338abfe --- /dev/null +++ b/usr.bin/nroff/macros.h @@ -0,0 +1,43 @@ +/* + * $Id: macros.h,v 1.1 1997/03/14 06:22:27 gdr Exp $ + * + * PUTBAK + * + * Push character back into input stream. we use the push-back buffer + * stored with macros. + */ +#define PUTBAK(c) \ +{ \ + if (mac.ppb == NULL) { /* first time executing this code */ \ + mac.ppb = mac.pbb; \ + *mac.ppb = c; \ + } else if (mac.ppb < mac.pbb + MAXPBB) { \ + mac.ppb++; \ + *(mac.ppb) = c; \ + } else { \ + errx(-1, "push back buffer overflow (%d chars)", MAXPBB); \ + } \ +} + +/* NGETC -- get character from input file or push back buffer */ +#define NGETC(infp) ((mac.ppb >= mac.pbb) ? *mac.ppb-- : getc(infp)) + +typedef struct macros_t { + char *mnames[MXMDEF]; /* table of ptrs to macro names */ + int lastp; /* index to last mname */ + char *emb; /* next char avail in macro defn buf */ + char mb[MACBUF]; /* table of macro definitions */ + char *ppb; /* pointer into push back buffer */ + char pbb[MAXPBB]; /* push back buffer */ +} macros_t; + + +extern macros_t mac; + +void initMacros (void); +void defmac (char *line, FILE *infp); +char *getmac (char *name); +void maceval (char *p, char *m); +void printmac (int opt); +int putstr (const char *name, const char *p); +char *getstr (char *name); diff --git a/usr.bin/nroff/makefile.mk b/usr.bin/nroff/makefile.mk new file mode 100644 index 0000000..117a8ea --- /dev/null +++ b/usr.bin/nroff/makefile.mk @@ -0,0 +1,100 @@ +# +# Makefile for nroff(1). +# +# $Id: makefile.mk,v 1.1 1997/03/14 06:22:28 gdr Exp $ +# + +IIGS = FALSE # TRUE or FALSE +USE_INSIGHT = FALSE # TRUE or FALSE + +BINDIR = /usr/bin +TMACDIR = /usr/lib/tmac +MANDIR = /usr/man + +# +###### end of configuration +# + +PROFILE = # -pg + +.IF $(IIGS) == TRUE +DEFINES = +OPTIMIZE = +LDLIBS = +.ELIF $(USE_INSIGHT) == TRUE +CC = insight +DEFINES = +OPTIMIZE = -g +LDLIBS = int.tqs -ltermcap +.ELSE +CC = gcc +DEFINES = # -DDEBUG +OPTIMIZE = $(PROFILE) -g +LDLIBS = $(PROFILE) -ltermcap +.END + +.IF $(IIGS) == TRUE +UX_SRC = +UX_OBJ = +.ELSE +UX_SRC = err.c +UX_OBJ = err.o +.END + +GCC_PARANOIA = \ + -Wstrict-prototypes \ + -Wmissing-prototypes \ + -Waggregate-return \ + -Wnested-externs \ + -fno-asm -fno-builtin -fno-inline + +.IF $(CC) == gcc +GCC_FLAGS = -Wall -funsigned-char $(GCC_PARANOIA) +.ELSE +GCC_FLAGS = +.END + + +CFLAGS = $(OPTIMIZE) $(GCC_FLAGS) $(DEFINES) + +SUNOS_H = sunos.h +OBJS = main.o command.o escape.o io.o low.o macros.o strings.o \ + text.o $(UX_OBJ) +SRCS = main.c command.c escape.c io.c low.c macros.c strings.c \ + text.c $(UX_SRC) + +default: nroff + +nroff: $(OBJS) + $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LDLIBS) + +clobber: + $(RM) -f nroff $(OBJS) +# $(RM) -f nroff $(OBJS) *~ core tca.* *.tqs insight.log + +dep: + gcc -MM $(CFLAGS) *.c > depend + +callchart: + cflow $(SRCS) > $@ + +install: + $(INSTALL) -d $(BINDIR) $(TMACDIR) $(MANDIR)/man1 $(MANDIR)/man7 + $(INSTALL) -m755 nroff $(BINDIR) + $(INSTALL) -m644 tmac.an $(TMACDIR) + $(INSTALL) -m644 tmac.s $(TMACDIR) + $(INSTALL) -m644 nroff.1 $(TMACDIR)/man1 + $(INSTALL) -m644 man.7 $(TMACDIR)/man7 + $(INSTALL) -m644 ms.7 $(TMACDIR)/man7 + +# +# additional dependancies +# +command.o:: $(SUNOS_H) nroff.h config.h +escape.o:: $(SUNOS_H) nroff.h config.h +io.o:: $(SUNOS_H) nroff.h config.h macros.h io.h +low.o:: $(SUNOS_H) nroff.h config.h +macros.o:: $(SUNOS_H) nroff.h config.h macros.h +main.o:: $(SUNOS_H) nroff.h config.h macros.h +strings.o:: $(SUNOS_H) nroff.h config.h +text.o:: $(SUNOS_H) nroff.h config.h io.h diff --git a/usr.bin/nroff/man.7 b/usr.bin/nroff/man.7 new file mode 100644 index 0000000..f4a611c --- /dev/null +++ b/usr.bin/nroff/man.7 @@ -0,0 +1,248 @@ +.\" man(7) manpage by rosenkra@convex.com (Bill Rosenkranz, 7/22/90) +.\" +.TH MAN 7 +.SH NAME +man - nroff macro package for manual pages +.SH SYNOPSIS +nroff -man file ... +.SH DESCRIPTION +These macros are used to lay out reference pages for manuals. +.PP +Any text argument +t +may be zero to six words. +Quotes may be used to include blanks in a 'word'. +Text +can be empty, but unlike normal Unix macros, the next line is not used. +.PP +A prevailing indent distance is remembered between successive +indented paragraphs, and is reset to default value upon +reaching a non-indented paragraph (i.e. at .SH or .SS). +In contrast with normal Unix procedure, all indents (tabs) are 8 spaces +instead of 5. +This can be changed by modifying tmac.an. +.SH FILES +.ec | +\lib\tmac\tmac.an the macro library +.ec \ +.SH SEE ALSO +nroff(1), man(1) +.SH "REQUEST SUMMARY" +.nf +.cc + +Request Cause Explanation + Break? + +.B t no Text t is bold. Quote to imbed blanks. +.I t no Text t is italic. Quote to imbed blanks. +.IP x yes Set prevailing indent to 8. Begin + indented paragraph with hanging tag + given by first argument. Tag x is + always placed on a separate line. +.LP yes Same as .PP. +.PP yes Begin paragraph. Set prevailing + indent to 8. +.RE yes End of relative indent. Set prevailing + indent to amount of starting .RS. +.RP x yes Like .IP, but use relative indent. Must + end the section with .RE. +.RS yes Start relative indent, move left margin + in distance 8. +.SH t yes Subhead. Quote to imbed blanks. +.SS t yes Subsection. Quote to imbed blanks. No + indent for t. +.TH n s c v d yes Begin page named n of chapter s; c is + the chapter name; d is the date of the + most recent change; v is version number. + Sets prevailing indent and tabs to 8. + ++cc . +.fi +.ne 8 +.SH EXAMPLE +The following illustrates some of the requests available +with this macro package: +.RS +.nf +.cc + + +.\\\|" this is a comment +.TH DEMO 1 "Commands Manual" "Version 1.0" "\\\|*\|(DA" +.SH NAME +demo - show how to use -man package \\\|" this is a comment +.SH SYNOPSIS +demo [options] file [...] +.SH DESCRIPTION +This is a test for showing how to use the +.I nroff(1) +man package. +It shows how to use .TH, .SH, .PP, .I, and .IP commands. +.PP +This will be a new paragraph. +You can also use normal +.I nroff(1) +commands in the text. +.SS NROFF COMMANDS: +.IP '\\\\\|"' +This is the comment command. +Note how you have to quote this sucker! +You'll probably never have to write an +.I nroff(1) +manpage, so don't worry about it. +.IP nf +No fill mode (the normal mode is fill mode where things +get justified right and left). +.IP fi +Re-enter fill mode. +.IP br +Break line here no matter what. +.IP sp +Vertical space (also causes a break to occur). +.sp +Note that to continue an indent and make a new paragraph (as +is the case here), just put in a space (.sp). +.PP +Now we should be at a new paragraph. + ++cc . +.fi +.RE +.ne 8 +Executing 'nroff -man demo.man' results in the following output: +.RS +.nf +.cc + + +DEMO (1) Commands Manual DEMO (1) + +NAME + demo - show how to use -man package + +SYNOPSIS + demo [options] file [...] + +DESCRIPTION + This is a test for showing how to use the nroff(1) + man package. It shows how to use .TH, .SH, .PP, .I, + and .IP commands. + + This will be a new paragraph. You can also use normal + nroff(1) commands in the text. + + NROFF COMMANDS: + + \\\|" + This is the comment command. Note how you have to + quote this sucker! You'll probably never have to + write an nroff(1) manpage, so don't worry about + it. + + nf + No fill mode (the normal mode is fill mode where + things get justified right and left). + + fi + Re-enter fill mode. + + br + Break line here no matter what. + + sp + Vertical space (also causes a break to occur). + + Note that to continue an indent and make a new + paragraph (as is the case here), just put in a + space (.sp). + + Now we should be at a new paragraph. + +Version 1.0 23:33:57 2/25/90 1 + + ++cc . +.fi +.RE +.ne 8 +.SH CONVENTIONS +A typical manual page for a command or function is laid out as follows: +.sp +.RS +.SS ".TH TITLE [1-8]" +The name of the command or function in upper-case, +which serves as the title of the manual page. +This is followed by the number of the section in which it appears. +.SS ".SH NAME" +name - one-line summary +.PP +The name, or list of names, by which the command is called, followed by +a dash and then a one-line summary of the action performed. +All in roman font, this section contains no troff(1) commands or escapes, +and no macro requests. +It is used to generate the whatis(1) database. +.SS ".SH SYNOPSIS" +Commands: +.sp +.RS +The syntax of the command and its arguments as typed on the command line. +When in boldface, a word must be typed exactly as printed. +When in italics, a word can be replaced with text that you supply. +Syntactic symbols appear in roman face: +.RP "[ ]" +An argument, when surrounded by brackets is optional. +.RE +.RP | +Arguments separated by a vertical bar are exclusive. +You can supply only item from such a list. +.RE +.RP ... +Arguments followed by an elipsis can be repeated. +When an elipsis follows a bracketed set, the expression within the +brackets can be repeated. +.RE +.RE +.sp +Functions: +.sp +.RS +If required, the data declaration, or #include directive, is shown first, +followed by the function declaration. +Otherwise, the function declaration is shown. +.RE +.SS ".SH DESCRIPTION" +A narrative description of the command or function in detail, including +how it interacts with files or data, and how it handles the standard +input, standard output and standard error. +.PP +Filenames, and references to commands or functions described elswhere +in the manual, are italicised. +The names of options, variables and other literal terms are +in boldface. +.SS ".SH OPTIONS" +The list of options along with a description of how each affects the +commands operation. +.SS ".SH FILES" +A list of files associated with the command or function. +.SS '.SH "SEE ALSO"' +A comma-separated list of related manual pages, followed by references +to other published materials. +This section contains no troff(1) escapes or commands, and no macro requests. +.SS ".SH DIAGNOSTICS" +A list of diagnostic messages and an explanation of each. +.SS ".SH NOTES" +Any additional notes such as installation-dependent functionality. +.SS ".SH BUGS" +A description of limitations, known defects, and possible problems +associated with the command or function. +.SS ".SH AUTHOR" +The program's author and any pertinent release info. +.SS ".SH VERSION" +The program's current version number and release date. +.RE +.SH AUTHOR +.nf +Adapted for Atari ST (TOS) and Minix by Bill Rosenkranz + +net: rosenkra@convex.com +CIS: 71460,17 +GENIE: W.ROSENKRANZ +.fi diff --git a/usr.bin/nroff/ms.7 b/usr.bin/nroff/ms.7 new file mode 100644 index 0000000..a666d56 --- /dev/null +++ b/usr.bin/nroff/ms.7 @@ -0,0 +1,105 @@ +.\" ms(7) manpage by rosenkra@convex.com (Bill Rosenkranz, 7/22/90) +.\" +.TH MS 7 +.SH NAME +ms - text formatting macros +.SH SYNOPSIS +nroff -ms [ options ] file ... +.SH DESCRIPTION +This package of nroff macro definitions provides a +formatting facility for various styles of articles, theses, and books. +All external -ms macros are defined below. +.PP +Note that this -ms macro package is a subset of the complete ms package +since nroff(1) is not quite up to it yet. +Still, it supports most of what is normally used, including the table +of contents macros. +.PP +Some nroff requests may be unsafe in conjunction with this package. +However, the first four requests below may be used with impunity after +initialization, and the last two may be used even before initialization: +.nf + + .bp begin new page + .br break output line + .sp n insert n spacing lines + .ce n center next n lines + + .ls n line spacing: n=1 single, n=2 double space + .na no alignment of right margin + +.fi +Font changes with \f are also allowed; +for example, '\\fIword\\fR' will italicize word. +.SH FILES +.ec | +\lib\tmac\tmac.s +.ec \ +.SH REQUESTS +.nf +.cc + +Macro Initial Break? Explanation +Name Value Reset? +.AB x - y begin abstract; if x=no don't label abstract +.AE - y end abstract +.AI - y author's institution, centered +.AU - y author's name, centered +.B x - n embolden x; if no x, switch to boldface +.I x - n italicize x; if no x, switch to italics +.IP x - y,y indented paragraph, with hanging tag x +.LP - y,y left (block) paragraph. +.NH x - y,y numbered header; x=level, x=0 resets +.PP - y,y paragraph with first line indented +.QP - y,y quoted paragraph (indented, shorter) +.R on n return to Roman font +.RE - y,y end level of relative indentation +.RS 5n y,y right shift: start level of relative indent +.SH - y,y section header, no numbering +.TL - y title, centered +.XP - y,y extended paragraph (biblio entry) +.XS p - y begin index entry, p = page +.XA p - y another index entry, p = page +.XE - y end index entry +.PX - y print index (ignored) + ++cc . +.fi +.SH REGISTERS +There are currently no user controlled registers in this implementation. +.PP +Here is a list of string registers available in -ms; they +may be used anywhere in the text: +.nf +.ec | + + Name String's Function + + \*(DW weekday + \*(MO month (month of the year) + \*(DY day (current date) + \*Q quote (" in nroff) + \*U unquote (" in nroff) + \*- dash (-- in nroff) + +.ec \ +.fi +.SH EXAMPLES +For an example, see the test files (*.ms) included in the distribution. +.SH BUGS +Probably zillions, especially considering it is so incomplete. +However, it is useful (better than nothing at all). +I have used this package extensively at home to write reports for work. +The results were nearly 100% compatible with Unix (BSD). +No support for displays and keeps, tables, boxed text, multicolumn, other +modes (e.g. thesis mode), footnotes, and beginning/end page traps. +Indented paragraph with tag puts the tag on its own line regardless how +long it is. +.SH AUTHOR +.nf +Adapted for Atari ST (TOS) and Minix by Bill Rosenkranz + +net: rosenkra@convex.com +CIS: 71460,17 +GENIE: W.ROSENKRANZ +.fi + diff --git a/usr.bin/nroff/nroff.1 b/usr.bin/nroff/nroff.1 new file mode 100644 index 0000000..7cb75eb --- /dev/null +++ b/usr.bin/nroff/nroff.1 @@ -0,0 +1,766 @@ +.\" nroff(1) manpage by rosenkra@convex.com (Bill Rosenkranz, 7/22/90) +.\" +.TH NROFF 1 +.SH NAME +nroff - text processor (Version 1.10) +.SH SYNOPSIS +nroff [options] file [...] +.SH DESCRIPTION +Nroff is a text processor and formatter based on the design +provided in "Software Tools" by Kernighan and Plauger. +It has been modified to closely resemble the Unix(tm) nroff command. +The text and commands found in the file(s) +are processed to generate formatted text. +Note that one (and only one) of the files can be "-" which reads +input from stdin at that point. +The output always goes to stdout which can be redirected by the shell. +.\" Using the command line option -l will cause the output to +.\" be sent to the printer instead. +The -o option lets you redirect error output to the specified +file rather than stderr. +Debugging information always goes to the file "nroff.dbg" and is +generally used only for program development. +.SH OPTIONS +The following command line options are available: +.IP -d +Set debug mode. +.IP -h +Hold before exit (Atari TOS only). +.IP -m +Process macro file tmac.. +Thus -man would cause the file tmac.an to be loaded. +Note that files processed in this way should contain only macro definitions, +no immediate output should be generated from this file (see ENVIRONMENT). +.IP -o +Set error log file (default is stderr). +.IP -raN +Preset number register 'a' (single character) to N (decimal integer only). +.IP -po +Shift output right n spaces (like .po). +.IP -pn +Initial page number (like .pn). +.IP -v +Prints the version information to stdout. +.IP + +Causes output to start with page n. +.IP - +Causes output to stop after page n. +.IP - +Input from stdin. +.sp +.SH ENVIRONMENT +Nroff recognizes the following environment variables from the shell: +.IP TMACDIR +An alternate directory to find the files tmac.* ("." for example). +The default is c:\\lib\\tmac under TOS and /usr/lib/tmac under +Minix or Unix(tm). +.IP TMPDIR +An alternate directory to place any temporary files. +The default is the current directory. +Note that nroff does not currently use any temporary files. +.SH COMMANDS +Commands typically are distinguished by a period in column one +of the input +followed by a two character abbreviation for the command funtion. +The abbreviation may then be followed by an optional numeric or +character argument. +The numeric argument may be an absolute value such as setting +the right margin to a particular column, or the argument may be +preceded by a plus sign or a minus sign to indicate that the +parameter should be modified relative to a previous setting. +The following commands are recognized (those marked "extension" +are requests added to the basic set provided by Unix(tm) nroff): +.\" +.IP .ad +Begin line adjustment. +If fill mode is not on, adjustment is defered until it is back on. +If a type indicator is present, the adjustment type is changed as follows: +.nf + + Indicator Type + l adjust left margin only + r adjust right margin only + c center + b or n adjust both margins (default) + absent unchanged +.fi +.\" +.IP .af +Assign format to number register. +The available formats are: +.nf + + Format Numbering Sequence + 1 0,1,2,3,4,... + 001 000,001,002,... + i 0,i,ii,iii,iv,v,... + I 0,I,II,III,IV,V,... + a 0,a,b,...,z,aa,ab,...zz,aaa,... + A 0,A,B,...,Z,AA,AB,...ZZ,AAA,... + +.fi +The second format above indicates that the field width, i.e. number +of digits, is specified by the number of digits in the format type. +.\" +.IP .bd +Ignored by nroff. +.\" +.IP .bo (extension) +Causes the following lines of text to appear in boldface. +The optional argument specifies the number of lines to be typed in boldface. +Boldface and underlining are mutually exclusive features. +The appearance of a boldface command will cause any underlining to cease. +.\" +.IP .bp (extension) +Causes succeeding text to appear at the top of a new page. +The optional argument specifies the page number for the new page. +The initial value is one and the default value is one more than +the previous page number. +.\" +.IP .br +Causes succeeding text to start on a new line at the current left margin. +There is no numeric argument for this command. +.\" +.IP .bs (extension) +Enables or disables the appearance of backspaces in the output text. +Underlining and boldface options are implemented by inserting +character - backspace - character combinations into the output buffer. +This is fine for devices which properly recognize the backspace character. +Some printers, however, do not recognize backspaces, so the option is +provided to overprint one line buffer with another. +The first line buffer is terminated with just a carriage return +rather than the carriage return - linefeed combination. +A zero argument or no argument to the backspace command removes +backspaces from the output. +A non-zero argument leaves them in the output. +The default is to remove backspaces. +.\" +.IP .cc +Changes the nroff command character to that specified by the +character argument. +If no argument is provided, the default is a period (\.). +.\" +.IP .ce +Causes the next line of text to appear centered on the output. +The optional argument specifies if more than one line is to be centered. +.\" +.IP .cs +Ignored by nroff. +.\" +.IP .cu +Causes the next line(s) of text to be continuously underlined. +Unlike the underline command (see \.ul) which underlines only +alphanumerics, continuous underlining underlines all printable characters. +The optional argument specifies the number of lines of text to underlined. +Any normal underlining or boldface commands currently in effect will be +terminated. +.\" +.IP .c2 +Changes the nroff no break character to that specified by the +character argument. +If no argument is provided, the default is a single quote. +.\" +.IP .de +Causes all text and commands following to be used to define a macro. +The definition is terminated by a \.en command or the +default \.\. terminator. +The first two characters of the argument following the \.de +command become the name of the new command. +It should be noted that upper and lower case arguments are considered different. +Thus, the commands \.PP and \.pp could define two different macros. +Care should be exercised since existing commands may be redefined. +.sp +A macro may contain up to nine arguments. +In the macro definition, the placement of arguments is designated by the +two character sequences, $1, $2, ... $9. +When the macro is invoked, each argument of the macro command line is +substituted for its corresponding designator in the expansion. +The first argument of the macro command is substituted for the $1 +in the expansion, the second argument for the $2, and so forth. +Arguments are typically strings which do not contain blanks or tabs. +If an argument is to contain blanks, then it should be surrounded by +either single or double quotes. +.\" +.IP .ds +Define a string. +To initiate the string with a blank or include blanks +in the string, start it with a single or double quite. +The string +can contain other defined strings or number registers as well as normal +text. +Strings are stored on the macro name space. +.\" +.IP .ec +Changes the nroff escape character to that specified by the +character argument. +If no argument is provided, the default is a backslash. +.\" +.IP .ef (extension) +Specifies the text for the footer on even numbered pages. +The format is the same as for the footer command (see \.fo). +.\" +.IP .eh (extension) +Specifies the text for the header on even numbered pages. +The format is the same as for the footer command (see \.fo). +.\" +.IP .en (extension) +Designates the end of a macro definition. +.\" +.IP .eo +Turn the escape mechanism off. +.\" +.IP .ex +Exit nroff at this point in the processing. +Ex forces all files closed and flushes the output. +.\" +.IP .fi +Causes the input text to be rearranged or filled to obtain the maximum +word count possible between the previously set left and right margins. +No argument is expected. +.\" +.IP .fl +Causes the output buffer to be flushed immediately. +.\" +.IP .fo (extension) +Specifies text to be used for a footer. +The footer text contains three strings seperated by a delimiter character. +The first non-blank character following the command is designated +as the delimiter. +The first text string is left justified to the current indentation +value (specified by \.in). +The second string is centered between the current indentation value +and the current right margin value (specified by \.rm). +The third string is right justified to the current right margin value. +The absence of footer text will result in the footer being printed as +one blank line. +The presence of the page number character (set by \.pc) in the footer +text results in the current page number being inserted at that position. +Multiple occurrances of the page number character are allowed. +.\" +.IP .ft +Changes the current font. +The choices are R (Times Roman), I (Times Italic), B (Times Bold), +S (math special), and P used to request the previous font. +P resets the next previous font to be the one just changed, amounting to a swap. +.\" +.IP .he (extension) +Specifies text to be used for a header. +The format is the same as for the footer (see \.fo). +.\" +.IP .if +Execute a command if the condition is true. +Format is: +.nf + + .if c command + .if !c command + .if N command + .if !N command + .if "str1"str2" command + .if !"str1"str2" command + +.fi +Here c is a single letter: n (true if nroff), t (true if troff), e (true +if even page), or o (true if odd page). +N is a numerical experssion and can include operators +, -, *, /, % (mod), +>, <, >=, <=, = (or ==), & (and), or : (or). +If the result is greater than 0, the condition evaluates true. +Numbers in the expression can be either constants or contents of number +registers. +Strings are tested using delimeter / or " only at this time. +Note that "block" conditionals like: +.nf + + .if c \\{\\ + ... + ... + ... \\} + +.fi +are not yet supported. +Also the .ie/.el conditional is not yet supported. +.\" +.IP .in +Indents the left margin to the column value specified by the argument. +The default left margin is set to zero. +.\" +.IP .ju (extension) +Causes blanks to be inserted between words in a line of +output in order to align or justify the right margin. +The default is to justify. +.\" +.IP .lg +Ignored by nroff. +.\" +.IP .ll +Sets the current line length. +The default is eighty. +.\" +.IP .ls +Sets the line spacing to the value specified by the argument. +The default is for single spacing. +.\" +.IP .lt +Set length of three-part titles. +Line length and title length +are independent. +Indents do not apply to titles but page offsets do. +.\" +.IP .m1 (extension) +Specifies the number of lines in the header margin. +This is the space from the physical top of page to and including +the header text. +A value of zero causes the header to not be printed. +A value of one causes the header to appear at the physical top of page. +Larger argument values cause the appropriate number of blank +lines to appear before the header is printed. +.\" +.IP .m2 (extension) +Specifies the number of blank lines to be printed between +the header line and the first line of the processed text. +.\" +.IP .m3 (extension) +Specifies the number of blank lines to be printed between +the last line of processed text and the footer line. +.\" +.IP .m4 (extension) +Specifies the number of lines in the footer margin. +This command affects the footer the same way the \.m1 +command affects the header. +.\" +.IP .mc +Margin character. The first argument is the character to use, +the second is the distance to the right of the right margin +to place the margin character. Useful for change bars. +No arguments turns the capability off. Note that with this +nroff, the margin character is always a single character only +and this distance is prefered to be in inches (e.g. 0.2i). +The default space is 0.2i (2 spaces). +.\" +.IP .na +Noadjust. +Ajdustment is turned off; the right margin is ragged. +The adjustment type for \.ad is not changed. +Output line filling still occurs if fill mode is on. +.\" +.IP .ne +Specifies a number of lines which should not be broken across a page boundary. +If the number of lines remaining on a page is less than the +value needed, then a new output page is started. +.\" +.IP .nf +Specifies that succeeding text should be printed without +rearrangement, or with no fill. +No argument is expected. +.\" +.IP .nj (extension) +Specifies that no attempt should be made to align or justify the right margin. +No argument is expected. +.\" +.IP .nr +Causes the value of a number register to be set or modified. +A total of twenty-six number registers are available designated +\\na through \\nz (either upper or lower case is allowed). +When the sequence \\nc is imbedded in the text, the current value +of number register c replaces the sequence, thus, such things as +paragraph numbering can be accomplished with relative ease. +.\" +.IP .of (extension) +Specifies the text for the footer on odd numbered pages. +The format is the same as the footer command (see \.fo). +.\" +.IP .oh (extension) +Specifies the text for the header on odd numbered pages. +The format is the same as the footer command (see \.fo). +.\" +.IP .pc +Specifies the page number character to be used in headers and footers. +The occurrance of this character in the header or footer text +results in the current page number being printed. +The default for this character is the percent sign (%). +.\" +.IP .pl +Specifies the page length or the number of lines per output page. +The default is sixty-six. +.\" +.IP .pm +Print macros. +The names and sizes of the macros are printed to stdout. +This is useful when building a macro package to see how much of the +total namespace is consumed by the package. +.\" +.IP .pn +Changes the page number of the current page and all +subsequent pages to its argument. +If no argument is given, the command is ignored. +.\" +.IP .po +Specifies a page offset value. +This allows the formatted text to be shifted to the right by +the number of spaces specified. +This feature may also be invoked by a switch on the command line. +.\" +.IP .ps +Ignored by nroff. +.\" +.IP .rr +Removes a number register. +.\" +.IP .so +Causes input to be retrieved from the file specified +by the command's character string argument. +The contents of the new file are inserted into the output +stream until an EOF is detected. +Processing of the original file is then resumed. +Command nesting is allowed. +.\" +.IP .sp +Specifies a number of blank lines to be output before +printing the next line of text. +.\" +.IP .ss +Ignored by nroff. +.\" +.IP .ti +Temporarily alters the indentation or left margin value for a single +succeeding input line. +.\" +.IP .tl +Specifies text to be used for a page title. +The format is the same as for the header (see \.he). +.\" +.IP .ul +Causes the next line(s) of text to be underlined. +Unlike the \.cu command, this command causes only alphanumerics +to be underlined, skipping punctuation and white space. +Underline and boldface are mutually exclusive. +.PP +The following nroff commands, normally available, are currently +not implemented in this version: +.cc + +\.fp, \.mk, \.rt, \.vs, \.sv, \.os, \.ns, \.rs, \.am, \.as, \.rm, \.rn, +\.di, \.da, \.wh, \.ch, \.dt, \.it, \.em, \.ta, \.tc, \.lc, \.fc, \.lg, +\.uf, \.tr, \.nh, \.hy, \.hc, \.hw, \.nm, \.nn, \.ie, \.el, \.ev, \.rd, +\.ex, \.nx, \.pi, \.tm, and \.ig. ++cc . +.\" +.SH ESCAPE SEQUENCES +Escape sequences are used to access special characters (such as Greek +letters) which may be outside the normal printable ASCII character set. +The are also used to toggle certain actions such as font selection. +.PP +.ne 5 +The escape sequences include: +.sp +.eo +.\" .ec - +.nf +\\ backslash character +\e printable version of escape character +\' accute accent (equivalent to \\(aa) +\` grave accent (equivalent to \\(ga) +\- minus sign +\. period +\ a single, unpaddable space +\0 digit-width space +\| 1\6em space (zero space in nroff) +\^ 1\12em space (zero space in nroff) +\& non-printing zero-width character +\" beginning of comment +\% default hyphenation character +\(xx special character named xx +\*x,\*(xx interpolate string x or xx +\fc font change (c = R,I,B,S,P) +\nx interpolate number register x +\t horizontal tab +.fi +.sp +.ne 5 +The Atari ST (TOS) version of nroff includes the following special +characters. NOTE: THESE ARE NOT AVAILABLE UNDER Minix OR Unix(tm)! +.sp +.nf +\(co copyright +\(rg registered +\(tm trademark +\(12 1/2 +\(14 1/4 +\(p2 exponent 2 +\(p3 exponent 3 +\(pn exponent n +\(aa acute +\(ga grave +\(de degree +\(dg dagger +\(ct cent +\(bu bullet +\(pp paragraph +\(^g ring bell +\(ua up arrow +\(da dn arrow +\(-> rt arrow +\(<- lf arrow +\(di divide +\(sr sq root +\(== == +\(>= >= +\(<= <= +\(+- +- +\(~= ~= +\(ap approx +\(no not +\(mo memeber +\(ca intersect +\(cu union +\(*a alpha +\(*b beta +\(*g gamma +\(*d delta +\(*s sigma +\(*p pi +\(*m mu +.fi +.ec +.SH PREDEFINED GENERAL NUMBER REGISTERS +The following number registers are available for both reading and writing. +They are accessed with the \\n(xx and \\nx escape and can be set with .nr: +.nf +.ne 5 + +% current page number +dw current day of the week (1-7) +dy current day of the month (1-31) +hh current hours (0-23) +ln current line number +mm current minutes (0-59) +mo current month (1-12) +ss current seconds (0-59) +yr last 2 digits of current year +.fi +.sp +The following number registers are available for reading only: +.nf +.cc + + +.$ number of args available in current macro +.A always 1 in nroff +.H available horizontal resolution +.T always 0 in nroff +.V available vertical resolution +.c number of lines read from current file +.f current font (1-4) +.i current indent +.l current line length +.o current page offset +.p current page length +.v current vertical spacing ++cc . + +.fi +.SH NOTES +There are several missing features, notably diversions, traps, +conditionals, all the hard stuff. +This means you can't use some existing macro packages (yet, I hope). +There is no complete -ms and -me packages as a result. +The goal is to make this nroff work with all the SunOS macro packages +sometime before Unix becomes obsolete! +.PP +If you make additions to this code, please mail the changes to me so I +can make formal distributions. +.SH BUGS +Undoubtedly more than I know about. +Here are a few: +.PP +The ability to perform numerical calculations on registers is not +implemented. +.PP +All dimensional units are in em's or inches only. +.PP +Lines with multiple string instances (i.e. \\*(xx) don't seem to work. +.PP +Lines with font changes (e.g. for italics) use vt52 escape sequences +to go to highlight mode. +This should read termcap/terminfo to do it right. +.PP +Some interpolations don't work properly. +.PP +The code uses statically allocated arrays for macros, strings, and registers. +This should be changed to dynamically allocated buffers or +write to intermediate files on small memory systems (i.e. Minix). +.SH FILES +.nf +.ec | +\lib\tmac\tmac.* predefined macros (see ENVIRONMENT) +nroff.dbg debugging output +stderr default error output stream +stdout output stream + +.ec \ +.fi +.SH AUTHOR +.nf +Adapted for Atari ST (TOS) and Minix by Bill Rosenkranz 11/89 + +net: rosenkra@convex.com +CIS: 71460,17 +GENIE: W.ROSENKRANZ + +Original author: + +Stephen L. Browning +5723 North Parker Avenue +Indianapolis, Indiana 46220 + +.fi +.SH HISTORY +.nf +Originally written in BDS C (by Stephen L. Browning?) +Adapted for standard C by W. N. Paul +Heavily hacked up to conform to the "real" nroff with numerous +additions by Bill Rosenkranz 11/89 +Bug fixes (termcap) and Minix 1.5.5 compatibility by +Wim 'Blue Baron' van Dorst (wsincc@tuerc3.urc.tue.nl) + +.fi + +.SH RECOMMENDATIONS +I envisioned this rather limited version as a way of formatting +man pages for my Atari ST system. +It works just fine for that. +The man macro package is certainly adequate for that purpose. +However, it would be nice to have more. +I suggest you limit +yourself to things which would port easily to other environments. +All the man macros available here should port without effort +to a more complete Unix(tm) environment. +.PP +Nroff as it stands can certainly be useful. +I recommend you don't +use the commands marked "extension". +Study the source for the man pages here (nroff(1), ms(7), and man(7)) as +well as the macro packages (tmac.an and tmac.s) and the examples to find +out the quirks. +Some things may not quite work like they do under Unix(tm), but it is +fairly close for what is here. +.SH REFERENCES +This document briefly describes the workings of nroff. +It is certainly not the definitive work on text processing. +I suggest you go out and get a good book (there are several on the market) +or refer to the Unix(tm) manuals for more help. +Nroff is just like a compiler and is much more complicated than (say) the C +language which only has a handful of rules and is much more thoroughly +documented. +Good luck! +.SH REQUEST SUMMARY +The following table summarizes the nroff requests currently available: +.nf +.ne 8 +.cc + + +Request Form Initial Default Notes Explanation +-------------- ------- ------- ------- ---------------------- +Font and Character Size Control + +.ps +-N 10pt prev E point size (ignored) +.ss N 12/36em ignored E space size (ignored) +.cs F N M off - P constant space mode (ign) +.bd F N off - P embolden font F (ignored) +.bd S F N off - P embolden special font +.ft F Roman prev E change to font F + ++ne 4 +Page Control + +.pl +-N 11in 11in v page length +.bp +-N N=1 - B,v eject page +.pn +-N N=1 ignored - next page number N +.po +-N 0 prev v page offset +.ne N - N=1V D,v need N vertical space + ++ne 4 +Text Filling, Adjusting, and Centering + +.br - - B break +.fi fill - B,E fill mode +.nf fill - B,E no fill or adjust +.ad c adj,both adjust E adjust output, mode c +.na adjust - E no adjust +.ce N off N=1 B,E center N lines + ++ne 4 +Vertical Spacing + +.ls N N=1 prev E output N-1 Vs +.sp N - N=1V B,v space vertical + ++ne 4 +Line Length and Indenting + +.ll +-N 6.5i prev E,m line length +.in +-N N=0 prev B,E,m indent +.ti +-N - ignored B,E,m temporary indent + ++ne 4 +Macros, Strings, Diversions, and Position Traps + +.de xx yy - .yy=.. - define macro xx +.ds xx str - ignored - define string xx + ++ne 4 +Number Registers + +.nr R +-N M - u define and set num reg +.af R c arabic - - assign format to reg +.rr R - - - remove register + ++ne 4 +I/O Conventions and Character Translation + +.ec c \ \ - set escape char +.eo on - - turn off escape mech +.lg N - - - ligature mode (ignored) +.ul N off N=1 E underline N lines +.cu N off N=1 E cont. underline +.cc c . . E set control char +.c2 c ' ' E set nobreak control char + ++ne 4 +Three-part Titles + +.tl 'l'c'r' - - three-part title +.pc c % off - page number char +.lt +-N 6.5in prev E,m length of title + ++ne 4 +Conditional Acceptence of Input + +.if c cmd - - if c true, accept cmd +.if !c cmd - - if c false, accept cmd +.if N cmd - - if N > 0, accept cmd +.if !N cmd - - if N <= 0, accept cmd +.if "s1"s2" cmd - - if strings same, accept cmd +.if !"s1"s2" cmd - - if strings differ, accept cmd + ++ne 4 +Input/Output File Switching + +.so filename - - switch source file + ++ne 4 +Miscellaneous + +.mc c N - off E,m margin char c, seperation N +.pm t - all - print macro names +.fl - - B flush output buffer + ++ne 4 +Notes + +B causes a break +D mode or parameters associated with current diversion level +E relevant parameters are a part of the current environment +O must stay in effect until logical output +P mode must be still or again in effect at time of physical output +v,p,m,u default scale indicators ++cc +.fi diff --git a/usr.bin/nroff/nroff.c b/usr.bin/nroff/nroff.c new file mode 100644 index 0000000..297f1ec --- /dev/null +++ b/usr.bin/nroff/nroff.c @@ -0,0 +1,991 @@ +/* + * main.c - main for nroff word processor + * + * similar to Unix(tm) nroff or RSX-11M RNO. adaptation of text processor + * given in "Software Tools", Kernighan and Plauger. + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: nroff.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "main______"; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __GNO__ +#include +#include +#else +#include "err.h" +#include "termcap.h" +#endif + +#ifdef sparc +#include +#include "sunos.h" +#endif + +#include "nroff.h" +#include "macros.h" +#include "io.h" + +static void init (void); +static void processFile (void); +static int pswitch (char *p, int *q); +static void usage (void); + +/************************************************************************* + * + * Global variables block. Keep them in main.c so that the IIgs' + * debuggers can find them. + */ + +struct docctl dc; +struct page pg; +struct macros_t mac; +struct regs rg[MAXREGS]; +FILE *out_stream; +FILE *err_stream; +FILE *dbg_stream; +FILE *sofile[Nfiles+1]; +int ignoring; /* .ig vs .de */ +int hold_screen; +int debugging; +int stepping; /* paging */ +int mc_ing = 0; /* turned off */ +int mc_space = 2; +char mc_char = '|'; +char tmpdir[256]; +char s_standout[20]; +char e_standout[20]; +char s_bold[20]; +char e_bold[20]; +char s_italic[20]; +char e_italic[20]; +char *dbgfile = "nroff.dbg"; +#ifdef GEMDOS +char *printer = "prn:"; /* this WON'T work!!! */ +#else +char *printer = ".ttyb"; /* this probably won't */ +#endif + +static char termcap[1024]; /* _must_ be 1024 */ +static char *progname; +static char *version = "(GNO) v1.2, 5 Mar 97 gdr"; + +/* + * End of global variable definitions. + * + *************************************************************************/ + +int +main (int argc, char *argv[]) { + register int i; + int swflg; + int ifp = 0; + char *ptmp; + char *pterm; + char capability[100]; + char *pcap; + char *ps; + +#ifdef __GNO__ + if (argc > 0) { + progname = __prognameGS(); + } else { + exit(1); /* not running from a shell? */ + } +#else + if (argc > 0) { + progname = basename(argv[0]); + } else { + progname = "nroff"; + } +#endif + + + /* + * set up initial flags and file descriptors + */ + swflg = FALSE; + ignoring = FALSE; + hold_screen = FALSE; + debugging = FALSE; + stepping = FALSE; + mc_ing = FALSE; + out_stream = stdout; + err_stream = stderr; + dbg_stream = stderr; + + + /* + * this is for tmp files, if ever needed. it SHOULD start + * out without the trailing slash. if not in env, use default + */ + if ((ptmp = getenv ("TMPDIR")) != NULL) { + strcpy (tmpdir, ptmp); + } else { + strcpy (tmpdir, "."); + } + + /* + * handle terminal for \fB, \fI + */ + s_standout[0] = '\0'; + e_standout[0] = '\0'; + s_bold[0] = '\0'; + e_bold[0] = '\0'; + s_italic[0] = '\0'; + e_italic[0] = '\0'; + + /* + * get termcap information + */ + if ((pterm = getenv("TERM")) == NULL) { + errx(1, "TERM environment variable not set"); + } + switch (tgetent(termcap, pterm)) { + case -1: + errx(1, "couldn't open termcap database"); + /*NOTREACHED*/ + case 0: + errx(1, "terminal type %s not found in termcap database", pterm); + /*NOTREACHED*/ + } + + /* + * we currently use standout mode for all weirdness + * like BOLD, italic, etc. + */ + pcap = capability; + if ((ps = tgetstr ("so", &pcap)) != NULL) { + /* + * sun has padding in here. this is NOT portable. + * better to use tputs() to strip it... + */ + /* while (*ps && *ps != 0x1b) ps++; */ + strcpy (s_standout, ps); + strcpy (s_bold, ps); + strcpy (s_italic, ps); + } else { + err(1, "couldn't get standout mode"); + /*NOTREACHED*/ + } + if ((ps = tgetstr ("se", &pcap)) != NULL) { + /* while (*ps && *ps != 0x1b) ps++; */ + strcpy (e_standout, ps); + strcpy (e_bold, ps); + strcpy (e_italic, ps); + } + + /* + * initialize structures (defaults) + */ + init (); + + /* + * parse cmdline flags + */ + for (i = 1; i < argc; ++i) { + if (*argv[i] == '-' || *argv[i] == '+') { + if (pswitch (argv[i], &swflg) == ERR) { + err_exit (-1); + } + } + } + + /* + * loop on files + */ + for (i = 1; i < argc; ++i) { + if (*argv[i] != '-' && *argv[i] != '+') { + /* + * open this file... + */ + if ((sofile[0] = fopen (argv[i], "r")) == NULL_FPTR) { + err(-1, "unable to open file %s", argv[i]); + } else { + /* + * do it for this file... + */ + ifp = 1; + processFile (); + fclose (sofile[0]); + } + } else if (*argv[i] == '-' && *(argv[i]+1) == 0) { + /* + * - means read stdin (anywhere in file list) + */ + sofile[0] = stdin; + ifp = 1; + sleep(1); + processFile (); + } + } + + + /* + * if no files, usage (should really use stdin...) + */ + if ((ifp == 0 && swflg == FALSE) || argc <= 1) { + usage (); + err_exit (-1); + } + + /* + * normal exit. this will fflush/fclose streams... + */ + err_exit (0); +#if defined(__GNUC__) || defined(__INSIGHT__) + return 0; +#endif +} + + +/*------------------------------*/ +/* usage */ +/*------------------------------*/ +static void +usage (void) { + /* + * note: -l may not work correctly + */ + + fprintf(stderr, "Usage: %s [options] file [...]\n", progname); + fputs("\t-a\tno font changes\n", stderr); + fputs("\t-b\t\tbackspace\n", stderr); + fputs("\t-d\t\tdebug mode (file: nroff.dbg)\n", stderr); +#ifdef GEMDOS + fputs("\t-h\t\thold screen before desktop\n", stderr); +#endif +#if 0 + fputs("\t-l\t\toutput to printer\n", stderr); +#endif + fputs("\t-m\tmacro file (e.g. -man)\n", stderr); + fputs("\t-o\terror log file (stderr is default)\n", stderr); + fputs("\t-po\t\tpage offset\n", stderr); + fputs("\t-pn\t\tinitial page number\n", stderr); + fputs("\t-pl\t\tpage length\n", stderr); + fputs("\t-s\t\tstep through pages\n", stderr); + fputs("\t-v\t\tprint version only\n", stderr); + fputs("\t+\t\tfirst page to do\n", stderr); + fputs("\t-\t\tlast page to do\n", stderr); + fputs("\t-\t\tuse stdin (in file list)\n", stderr); +} + + +/* + * init + * initialize parameters for nro word processor + */ +static void +init (void) { + + +#ifdef MINIX + register int i; +#else + register long i; +#endif + time_t tval; + char *ctim; + + /* + * misc global flags, etc... + */ + mc_space = 2; + mc_char = '|'; + tval = time (0L); + ctim = ctime (&tval); + + /* + * basic document controls... + */ + dc.fill = YES; + dc.dofnt = YES; + dc.lsval = 1; + dc.inval = 0; + dc.rmval = PAGEWIDTH - 1; + dc.llval = PAGEWIDTH - 1; + dc.ltval = PAGEWIDTH - 1; + dc.tival = 0; + dc.ceval = 0; + dc.ulval = 0; + dc.cuval = 0; + dc.juval = YES; + dc.adjval = ADJ_BOTH; + dc.boval = 0; + dc.bsflg = FALSE; + dc.prflg = TRUE; + dc.sprdir = 0; + dc.flevel = 0; + dc.lastfnt = 1; + dc.thisfnt = 1; + dc.escon = YES; + dc.pgchr = '%'; + dc.cmdchr = '.'; + dc.escchr = '\\'; + dc.nobrchr = '\''; + for (i = 0; i < 26; ++i) { + dc.nr[i] = 0; + } + for (i = 0; i < 26; ++i) { + dc.nrauto[i] = 1; + } + for (i = 0; i < 26; ++i) { + dc.nrfmt[i] = '1'; + } + + /* + * initialize internal regs. first zero out... + */ + for (i = 0; i < MAXREGS; i++) { + rg[i].rname[0] = EOS; + rg[i].rname[1] = EOS; + rg[i].rname[2] = EOS; + rg[i].rname[3] = EOS; + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + } + + /* + * predefined regs. these are read/write: + */ + i = 0; + + strcpy (rg[i].rname, "%"); /* current page */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "ct"); /* character type */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "dl"); /* width of last complete di */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "dn"); /* height of last complete di */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "dw"); /* day of week (1-7) */ + rg[i].rval = 0; + if (!strncmp (&ctim[0], "Sun", 3)) rg[i].rval = 1; + else if (!strncmp (&ctim[0], "Mon", 3)) rg[i].rval = 2; + else if (!strncmp (&ctim[0], "Tue", 3)) rg[i].rval = 3; + else if (!strncmp (&ctim[0], "Wed", 3)) rg[i].rval = 4; + else if (!strncmp (&ctim[0], "Thu", 3)) rg[i].rval = 5; + else if (!strncmp (&ctim[0], "Fri", 3)) rg[i].rval = 6; + else if (!strncmp (&ctim[0], "Sat", 3)) rg[i].rval = 7; + rg[i].rauto = 1; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "dy"); /* day of month (1-31) */ + rg[i].rauto = 1; + rg[i].rval = atoi (&ctim[8]); + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "hp"); /* current h pos on input */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "ln"); /* output line num */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "mo"); /* current month (1-12) */ + rg[i].rval = 0; + if (!strncmp (&ctim[4], "Jan", 3)) rg[i].rval = 1; + else if (!strncmp (&ctim[4], "Feb", 3)) rg[i].rval = 2; + else if (!strncmp (&ctim[4], "Mar", 3)) rg[i].rval = 3; + else if (!strncmp (&ctim[4], "Apr", 3)) rg[i].rval = 4; + else if (!strncmp (&ctim[4], "May", 3)) rg[i].rval = 5; + else if (!strncmp (&ctim[4], "Jun", 3)) rg[i].rval = 6; + else if (!strncmp (&ctim[4], "Jul", 3)) rg[i].rval = 7; + else if (!strncmp (&ctim[4], "Aug", 3)) rg[i].rval = 8; + else if (!strncmp (&ctim[4], "Sep", 3)) rg[i].rval = 9; + else if (!strncmp (&ctim[4], "Oct", 3)) rg[i].rval = 10; + else if (!strncmp (&ctim[4], "Nov", 3)) rg[i].rval = 11; + else if (!strncmp (&ctim[4], "Dec", 3)) rg[i].rval = 12; + rg[i].rauto = 1; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "nl"); /* v pos of last base-line */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "sb"); /* depth of str below base */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "st"); /* height of str above base */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "yr"); /* last 2 dig of current year*/ + rg[i].rauto = 1; + rg[i].rval = atoi (&ctim[22]); + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, "hh"); /* current hour (0-23) */ + rg[i].rauto = 1; + rg[i].rval = atoi (&ctim[11]); + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = 2 | 0x80; + i++; + + strcpy (rg[i].rname, "mm"); /* current minute (0-59) */ + rg[i].rauto = 1; + rg[i].rval = atoi (&ctim[14]); + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = 2 | 0x80; + i++; + + strcpy (rg[i].rname, "ss"); /* current second (0-59) */ + rg[i].rauto = 1; + rg[i].rval = atoi (&ctim[17]); + rg[i].rflag = RF_READ | RF_WRITE; + rg[i].rfmt = 2 | 0x80; + i++; + + + /* + * these are read only (by user): + */ + strcpy (rg[i].rname, ".$"); /* num args at current macro*/ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".A"); /* 1 for nroff */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".H"); /* hor resolution */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".T"); /* 1 for troff */ + rg[i].rauto = 0; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".V"); /* vert resolution */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".a"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".c"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".d"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".f"); /* current font (1-4) */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".h"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".i"); /* current indent */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".l"); /* current line length */ + rg[i].rauto = 1; + rg[i].rval = PAGEWIDTH - 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".n"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".o"); /* current offset */ + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".p"); /* current page len */ + rg[i].rauto = 1; + rg[i].rval = PAGELEN; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".s"); /* current point size */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".t"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".u"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".v"); /* current v line spacing */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".w"); /* width of prev char */ + rg[i].rauto = 1; + rg[i].rval = 1; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".x"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".y"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + i++; + + strcpy (rg[i].rname, ".z"); + rg[i].rauto = 1; + rg[i].rval = 0; + rg[i].rflag = RF_READ; + rg[i].rfmt = '1'; + + /* + * page controls... + */ + pg.curpag = 0; + pg.newpag = 1; + pg.lineno = 0; + pg.plval = PAGELEN; + pg.m1val = 2; + pg.m2val = 2; + pg.m3val = 2; + pg.m4val = 2; + pg.bottom = pg.plval - pg.m4val - pg.m3val; + pg.offset = 0; + pg.frstpg = 0; + pg.lastpg = 30000; + pg.ehead[0] = pg.ohead[0] = '\n'; + pg.efoot[0] = pg.ofoot[0] = '\n'; + memset(pg.ehead + 1, EOS, MAXLINE -1); + memset(pg.ohead + 1, EOS, MAXLINE -1); + memset(pg.efoot + 1, EOS, MAXLINE -1); + memset(pg.ofoot + 1, EOS, MAXLINE -1); + +#if 0 + for (i = 1; i < MAXLINE; ++i) { + pg.ehead[i] = pg.ohead[i] = EOS; + pg.efoot[i] = pg.ofoot[i] = EOS; + } +#endif + pg.ehlim[LEFT] = pg.ohlim[LEFT] = dc.inval; + pg.eflim[LEFT] = pg.oflim[LEFT] = dc.inval; + pg.ehlim[RIGHT] = pg.ohlim[RIGHT] = dc.rmval; + pg.eflim[RIGHT] = pg.oflim[RIGHT] = dc.rmval; + + /* + * output buffer controls... + */ + initOutbuf(); + + /* + * macros... + */ + initMacros(); + + /* + * file descriptors (for sourced files) + */ + for (i = 0; i < Nfiles+1; ++i) { + sofile[i] = NULL_FPTR; + } +} + + +/* + * pswitch + * + * process switch values from command line + */ +static int +pswitch (char *p, int *q) { + int swgood; + char mfile[256]; + char *ptmac; + int indx; + int val; + + swgood = TRUE; + if (*p == '-') { + /* + * since is STILL use the goofy atari/dri xmain code, i + * look for both upper and lower case. if you use dLibs + * (and if its startup code does not ucase the cmd line), + * you can probably look for just lower case. gulam and + * other shells typically don't change case of cmd line. + */ + switch (*++p) { + case 0: /* stdin */ + break; + + case 'a': /* font changes */ + case 'A': + dc.dofnt = NO; + break; + + case 'b': /* backspace */ + case 'B': + dc.bsflg = TRUE; + break; + + case 'd': /* debug mode */ + case 'D': + if ((dbg_stream = fopen (dbgfile, "w")) == NULL) { + warn ("unable to open debug file %s, using stderr", dbgfile); + dbg_stream = stderr; + } + debugging = TRUE; + break; + + case 'h': /* hold screen */ + case 'H': + hold_screen = TRUE; + break; + + case 'l': /* to lpr (was P) */ + case 'L': +#ifdef GEMDOS + out_stream = (FILE *) 0; +#else + out_stream = fopen (printer, "w"); +#endif + setPrinting(TRUE); + break; + + case 'm': /* macro file */ + case 'M': + /* + * build macro file name. start with lib + * + * put c:\lib\tmac in environment so we can + * read it here. else use default. if you want + * file from cwd, "setenv TMACDIR ." from shell. + * + * we want file names like "tmac.an" (for -man) + */ + if ((ptmac = getenv ("TMACDIR")) != NULL) { + /* + * this is the lib path (e.g. "c:\lib\tmac") + */ + strcpy (mfile, ptmac); + + /* + * this is the prefix (i.e. "\tmac.") + */ + strcat (mfile, TMACPRE); + } else { + /* + * use default lib/prefix (i.e. + * "c:\lib\tmac\tmac.") + */ + strcpy (mfile, TMACFULL); + } + + /* + * finally, add extension (e.g. "an") + */ + strcat (mfile, ++p); + + /* + * open file and read it + */ + if ((sofile[0] = fopen (mfile, "r")) == NULL_FPTR) { + err(-1, "unable to open macro file %s", mfile); + /*NOTREACHED*/ + } + processFile (); + fclose (sofile[0]); + break; + + case 'o': /* output error log */ + case 'O': + if (!*(p+1)) { + err(-1, "no error file specified"); + /*NOTREACHED*/ + } + if ((err_stream = fopen (p+1, "w")) == NULL) { + err(-1, "unable to open error file %s", p+1); + /*NOTREACHED*/ + } + err_set_file(err_stream); + break; + + case 'p': /* .po, .pn */ + case 'P': + if (*(p+1) == 'o' || *(p+1) == 'O') { /* -po___ */ + p += 2; + set (&pg.offset, ctod (p), '1', 0, 0, HUGE); + set_ireg (".o", pg.offset, 0); + } else if (*(p+1) == 'n' || *(p+1) == 'N') { /* -pn___ */ + p += 2; + set (&pg.curpag, ctod (p) - 1, '1', 0, -HUGE, HUGE); + pg.newpag = pg.curpag + 1; + set_ireg ("%", pg.newpag, 0); + } else if (*(p+1) == 'l' || *(p+1) == 'L') { /* -pl___ */ + p += 2; + set (&pg.plval, ctod (p) - 1, '1', 0, + pg.m1val + pg.m2val + pg.m3val + pg.m4val + 1, + HUGE); + set_ireg (".p", pg.plval, 0); + pg.bottom = pg.plval - pg.m3val - pg.m4val; + } else { /* -p___ */ + p++; + set (&pg.offset, ctod (p), '1', 0, 0, HUGE); + set_ireg (".o", pg.offset, 0); + } + break; + + case 'r': /* set number reg */ + case 'R': + if (!isalpha (*(p+1))) { + warnx("invalid number register name (%c)", *(p+1)); + } else { + /* + * indx is the user num register and val + * is the final value. + */ + indx = tolower (*(p+1)) - 'a'; + val = atoi (p+2); + set (&dc.nr[indx], val, '1', 0, -INFINITE, INFINITE); + } + break; + + case 's': /* page step mode */ + case 'S': + stepping = TRUE; + break; + + case 'v': /* version */ + case 'V': + printf ("%s %s\n", progname, version); + *q = TRUE; + break; + + case '0': /* last page */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + pg.lastpg = ctod (p); + break; + + default: /* illegal */ + swgood = FALSE; + break; + } + } else if (*p == '+') { /* first page */ + pg.frstpg = ctod (++p); + } else { /* illegal */ + swgood = FALSE; + } + + + if (swgood == FALSE) { + warnx("illegal option: %s", p); + return (ERR); + } + + return (OK); +} + + +/* + * processFile + * + * process input files from command line + */ +static void +processFile (void) { + + static char ibuf[MAXLINE]; + int i; + + /* + * handle nesting of includes (.so). note that .so causes dc.flevel + * to be increased... + */ + for (dc.flevel = 0; dc.flevel >= 0; dc.flevel -= 1) { + while ((i = getlin (ibuf, sofile[dc.flevel])) != EOF) { + /* + * if line is a command or text + */ + if (ibuf[0] == dc.cmdchr) { + comand (ibuf); + } else { + /* + * this is a text line. first see if + * first char is space. if it is, break + * line. + */ + if (ibuf[0] == ' ') { + robrk (); + } + text (ibuf); + } + } + + /* + * close included file + */ + if (dc.flevel > 0) { + fclose (sofile[dc.flevel]); + } + } + if (pg.lineno > 0) { + nroffSpace (HUGE); + } +} + +#pragma optimize 8 +#pragma debug 0 + +void +debugMessage (const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + fprintf(err_stream, "%s: ", progname); + vfprintf(err_stream, fmt, ap); + va_end(ap); + return; +} diff --git a/usr.bin/nroff/nroff.desc b/usr.bin/nroff/nroff.desc new file mode 100644 index 0000000..af5348b --- /dev/null +++ b/usr.bin/nroff/nroff.desc @@ -0,0 +1,9 @@ +Name: nroff +Version: 1.2 (17 Mar 97) +Shell: ORCA/Shell, GNO/ME +Author: Various. Maintained by Devin Reade. +Contact: gdr@myrias.com +Where: /usr/bin +FTP: apple2.caltech.edu, ground.isca.uiowa.edu + + Text Processing Typesetter diff --git a/usr.bin/nroff/nroff.h b/usr.bin/nroff/nroff.h new file mode 100644 index 0000000..fbf82d2 --- /dev/null +++ b/usr.bin/nroff/nroff.h @@ -0,0 +1,483 @@ +#ifndef NRO_H +#define NRO_H + +#include "config.h" /* os/compiler options */ + +#ifndef NEWLINE +#define NEWLINE '\n' +#endif + +/* + * nroff.h - stuff for nroff + * + * adapted for atariST/TOS by Bill Rosenkranz 10/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * things to look for here: + * 1) TMAC definition for default macro package lib + * 2) configuration sizes (see _STKSIZ below if alcyon/dri) + * 3) libc should have getenv(), time(), and ctime() + * 4) look in version.h for *printer file name (included below) + * + * all data is currently allocated in static arrays. the biggest + * chunks are the parameters which control number registers and the + * macro name space area. these are defined below: MAXREGS, MACBUF. + * MACBUF is the larger. it holds all macros, strings, etc. if you + * find yourself running out of macro space, increase MACBUF. + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + */ + +#include + +/* + * default prefix of macro files. files will be of the form "tmac.an" + * (for -man), "tmac.s" (for -ms), "tmac.e" (for -me), etc. first + * checks environment for TMACDIR which would be path (e.g. "c:\lib\tmac" + * or ".", no trailing slash char!). + */ +#ifdef tmacfull +# define TMACFULL tmacfull +#endif +#ifdef tmacpre +# define TMACPRE tmacpre +#endif + +#ifdef GEMDOS +# ifndef TMACFULL +# define TMACFULL "c:\\lib\\tmac\\tmac." +# endif +# ifndef TMACPRE +# define TMACPRE "\\tmac." +# endif +#endif + +#ifdef MINIX +# ifndef TMACFULL +# define TMACFULL "/usr/lib/tmac/tmac." +# endif +# ifndef TMACPRE +# define TMACPRE "/tmac." +# endif +#endif + +#ifdef UNIX +# ifndef TMACFULL +# define TMACFULL "/usr/lib/tmac/tmac." +# endif +# ifndef TMACPRE +# define TMACPRE "/tmac." +# endif +#endif + +/* + * command codes. indented defines are commands not yet implemented + */ +#undef PI +#define MACRO 0 /* macro definition */ +#define BP 1 /* begin page */ +#define BR 2 /* break */ +#define CE 3 /* center */ +#define FI 4 /* fill */ +#define FO 5 /* footer */ +#define HE 6 /* header */ +#define IN 7 /* indent */ +#define LS 8 /* line spacing */ +#define NF 9 /* no fill */ +#define PL 10 /* page length */ +#define RM 11 /* remove macro */ +#define SP 12 /* line space */ +#define TI 13 /* temp indent */ +#define UL 14 /* underline */ +#define JU 15 /* justify */ +#define NJ 16 /* no justify */ +#define M1 17 /* top margin */ +#define M2 18 /* second top margin */ +#define M3 19 /* first bottom margin */ +#define M4 20 /* bottom-most margin */ +#define BS 21 /* allow/disallow '\b' in output */ +#define NE 22 /* need n lines */ +#define PC 23 /* page number character (%) */ +#define CC 24 /* control character (.) */ +#define PO 25 /* page offset */ +#define BO 26 /* bold face */ +#define EH 27 /* header for even numbered pages */ +#define OH 28 /* header for odd numbered pages */ +#define EF 29 /* footer for even numbered pages */ +#define OF 30 /* footer for odd numbered pages */ +#define SO 31 /* source file */ +#define CU 32 /* continuous underline */ +#define DE 33 /* define macro */ +#define EN 34 /* end macro definition */ +#define NR 35 /* set number register */ +#define EC 36 /* escape character (\) */ +#define FT 37 /* font change (R,B,I,S,P) */ +#define EO 38 /* turn escape parsing off */ +#define LL 39 /* line length (same as RM) */ +#define FL 40 /* flush output NOW */ +#define PN 41 /* page number for next page */ +#define RR 42 /* remove register */ +#define C2 43 /* nobreak char */ +# define TR 44 /* translate character */ +#define LT 45 /* length of title */ +# define FC 46 /* field delimeter */ +#define TL 47 /* like HE */ +#define AF 48 /* assign format to nr */ +#define AD 49 /* adjust line */ +#define NA 50 /* no adjust */ +#define DS 51 /* define string */ +#define PM 52 /* print macro names */ +#define IF 53 /* if */ +# define IE 54 /* if/else */ +# define EL 55 /* else */ +#define PS 56 /* point size (IGNORED in nroff) */ +#define SS 57 /* space char size (IGNORED in nroff) */ +#define CS 58 /* constant char space (IGNORED in nroff) */ +#define BD 59 /* embolden font (IGNORED in nroff) */ +# define FP 60 /* font position */ +# define MK 61 /* mark vertical place */ +# define RT 62 /* return to marked vert place */ +# define VS 63 /* vertical baseline spacing */ +# define SV 64 /* save vertical distance */ +# define OS 65 /* output saved vertical distance */ +# define NS 66 /* no-space mode */ +# define RS 67 /* restore spacing mode */ +# define AM 68 /* append to macro */ +# define AS 69 /* append to string */ +# define RN 70 /* rename */ +# define DI 71 /* divert to macro */ +# define DA 72 /* divert/append to macro */ +# define WH 73 /* set location trap */ +# define CH 74 /* change trap location */ +# define DT 75 /* set diversion trap */ +# define IT 76 /* set input line trap */ +# define EM 77 /* end macro */ +# define TA 78 /* tab settings */ +# define TC 79 /* tab repetition char */ +# define LC 80 /* leader repetition char */ +# define LG 81 /* ligature mode */ +# define UF 82 /* underline font */ +# define NH 83 /* no hyphenation */ +# define HY 84 /* hyphenate */ +# define HC 85 /* hyphenation indication char */ +# define HW 86 /* hyphenation exception words */ +# define NM 87 /* number mode */ +# define NN 88 /* no number next lines */ +# define EV 89 /* environment switch */ +# define RD 90 /* read insertion */ +# define EX 91 /* exit */ +# define NX 92 /* next file */ +# define PI 93 /* pipe to program */ +# define MC 94 /* set margin char */ +# define TM 95 /* print to terminal */ +#define IG 96 /* ignore */ + +#define COMMENT 1000 /* comment (.\") */ +#define UNKNOWN -1 + + +/* + * MAXLINE is set to a value slightly larger than twice the longest + * expected input line. Because of the way underlining is handled, the + * input line which is to be underlined, can almost triple in length. + * Unlike normal underlining and boldfacing, continuous underlining + * affects all characters in the buffer, and represents the worst case + * condition. If the distance between the left margin and the right + * margin is greater than about 65 characters, and continuous underlining + * is in effect, there is a high probability of buffer overflow. + */ +/* FIXME */ +#define MAXLINE 500 /*500*/ /* 200 */ +#define PAGELEN 66 +#define PAGEWIDTH 80 +#define HUGE 256 +#define INFINITE 32760 +#define LEFT 0 /* indecies into hdr margin lim arrays */ +#define RIGHT 1 +#define Nfiles 4 /* nesting depth for input files */ + +/* + * The following parameters may be defined elsewhere so undef/def + */ +#undef min +#undef max +#undef YES +#define YES 1 +#undef NO +#define NO 0 +#undef ERR +#define ERR -1 +#define EOS '\0' +#undef FALSE +#define FALSE 0 +#undef TRUE +#define TRUE !FALSE +#undef OK +#define OK !ERR + +/* + * a rational way of dealing with the NULL thing... + */ +#define NULL_CPTR (char *) 0 +#define NULL_FPTR (FILE *) 0 +#define NULL_IPTR (int *) 0 +#define NULL_LPTR (long *) 0 +#define NULL_SPTR (short *) 0 +#define NULL_PTR (char *) 0 +#define NULLP(type) (type *) 0 + + +/* + * for justification during line fill + */ +#define ADJ_OFF 0 +#define ADJ_LEFT 1 +#define ADJ_RIGHT 2 +#define ADJ_CENTER 3 +#define ADJ_BOTH 4 + +/* + * Markers for various terminal/printer modes + */ +#define S_STANDOUT 128 +#define E_STANDOUT 129 +#define S_BOLD 130 +#define E_BOLD 131 +#define S_ITALIC 132 +#define E_ITALIC 133 + +/* + * basic unit (b.u.) conversions. in nroff, all output is fixed spaced, + * at least in THIS nroff. so unit conversion to b.u. amount to 1 Em per + * character or 24 b.u. per character. thus 0.5i = 120 b.u. = 5 chars. + * everything is rounded up to the nearest Em. it is highly recommended + * to use inches for everything... + * + * to convert (say inches) to char spaces, do this: + * + * char_spaces = (int)(inches * (float) BU_INCH) / BU_EM; + */ +#define BU_INCH 240 /* 1.0i = 240 b.u. */ +#define BU_CM 945/10 /* 1.0c = 240*50/127 b.u. */ +#define BU_PICA 40 /* 1P = 240/6 b.u. */ +#define BU_EM 24 /* 1m = 240/10 b.u. (10 char/inch) */ +#define BU_EN 24 /* 1n = 240/10 b.u. */ +#define BU_POINT 240/72 /* 1p = 240/72 b.u. */ +#define BU_BU 1 /* 1 = 1 b.u. */ + + +/* + * The parameter values selected for macro definitions are somewhat + * arbitrary. MACBUF is the storage area for both macro names and + * definitions. Since macro processing is handled by pushing back + * the expansion into the input buffer, the longest possible expansion + * would be MAXLINE characters. Allowing for argument expansion, + * MXMLEN was chosen slightly less than MAXLINE. It is assumed that + * most macro definitions will not exceed 20 characters, hence MXMDEF + * of 150. + */ +#define MXMDEF 150 /* max no. of macro definitions */ +#define MACBUF 32000 /*100000*//* macro definition buffer size (32000) */ +#define MXMLEN 1000 /* max length of each macro definition (250) */ +#define MNLEN 10 /* max length of macro name */ +#define MAXREGS 100 /* max number of registers (2-char) */ +#define MAXPBB 5000 /* size of push back buffer */ + + +/* + * number registers + */ +#define RF_READ 0x0001 /* register flags */ +#define RF_WRITE 0x0002 + +struct regs +{ + char rname[4]; /* 2-char register name */ + int rauto; /* autoincrement value */ + int rval; /* current value of the register */ + int rflag; /* register flags */ + char rfmt; /* register format (1,a,A,i,I,...) */ +}; + + + +/* + * control parameters for nroff + */ +struct docctl +{ + int fill; /* fill if YES, init = YES */ + int dofnt; /* handle font change, init = YES */ + int lsval; /* current line spacing, init = 1 */ + int inval; /* current indent, >= 0, init = 0 */ + int rmval; /* current right margin, init = 60 */ + int llval; /* current line length, init = 60 */ + int ltval; /* current title length, init = 60 */ + int tival; /* current temp indent, init = 0 */ + int ceval; /* number of lines to center, init = 0 */ + int ulval; /* number of lines to underline, init = 0 */ + int cuval; /* no lines to continuously uline, init = 0 */ + int juval; /* justify if YES, init = YES */ + int adjval; /* adjust type, init = ADJ_BOTH */ + int boval; /* number of lines to bold face, init = 0 */ + int bsflg; /* can output contain '\b', init = FALSE */ + int prflg; /* print on or off, init = TRUE */ + int sprdir; /* direction for spread(), init = 0 */ + int flevel; /* nesting depth for source cmd, init = 0 */ + int lastfnt; /* previous used font */ + int thisfnt; /* current font, init = 1 (1=R,2=I,3=B,4=S) */ + int escon; /* whether esc parsing is on, init = YES */ + int nr[26]; /* number registers */ + int nrauto[26]; /* number registers auto increment */ + char nrfmt[26]; /* number registers formats, init = '1' */ + /* input code how printed */ + /* 1 '1' 1,2,3,... */ + /* a 'a' a,b,c,...,aa,bb,cc,... */ + /* A 'A' A,B,C,...,AA,BB,CC,... */ + /* i 'i' i,ii,iii,iv,v... */ + /* I 'I' I,II,III,IV,V... */ + /* 01 2 01,02,03,... */ + /* 001 3 001,002,003,... */ + /* 0..1 8 00000001,00000002,... */ + char pgchr; /* page number character, init = '%' */ + char cmdchr; /* command character, init = '.' */ + char escchr; /* escape char, init = '\' */ + char nobrchr; /* nobreak char, init = '\'' */ +}; + + +/* + * page control parameters + */ +struct page +{ + int curpag; /* current output page number, init =0 */ + int newpag; /* next output page number, init = 1 */ + int lineno; /* next line to be printed, init = 0 */ + int plval; /* page length in lines, init = 66 */ + int m1val; /* margin before and including header */ + int m2val; /* margin after header */ + int m3val; /* margin after last text line */ + int m4val; /* bottom margin, including footer */ + int bottom; /* last live line on page + = plval - m3val - m4val */ + int offset; /* page offset from left, init = 0 */ + int frstpg; /* first page to print, init = 0 */ + int lastpg; /* last page to print, init = 30000 */ + int ehlim[2]; /* left/right margins for headers/footers */ + int ohlim[2]; /* init = 0 and PAGEWIDTH */ + int eflim[2]; + int oflim[2]; + char ehead[MAXLINE]; /* top of page title, init = '\n' */ + char ohead[MAXLINE]; + char efoot[MAXLINE]; /* bottom of page title, init = '\n' */ + char ofoot[MAXLINE]; +}; + + + + +/* + * forward refs from nroff + */ + +/* main.c */ +void debugMessage (const char *fmt, ...); + +/* command.c */ +void comand (char *p); +int set_ireg (const char *name, int val, int opt); +void set (int *param, int val, char type, int defval, int minval, int maxval); + +/* low.c */ +int ctod (char *p); +char *skipbl (char *p); +char *skipwd (char *p); +void nroffSpace (int n); +char *getfield (char *p, char *q, char delim); +int getwrd (char *src, char *dest); +int countesc (char *p); +int itoda (int value, char *p, int size); +int itoROMAN (int value, char *p, int size); +int itoroman (int value, char *p, int size); +int itoLETTER (int value, char *p, int size); +int itoletter (int value, char *p, int size); +void err_exit (int code); + +/* text.c */ +void initOutbuf (void); +void pfoot (void); +void phead (void); +void robrk (void); +void setPrinting (int val); +void skip (int n); +int strkovr (char *p, char *q); +void text (char *p); + + +/* strings.c */ +void defstr (char *line); + +/* + * Globals. + */ +extern struct docctl dc; +extern struct page pg; +extern struct regs rg[MAXREGS]; +extern FILE *out_stream; +extern FILE *err_stream; +extern FILE *dbg_stream; +extern FILE *sofile[Nfiles+1]; +extern int ignoring; +extern int hold_screen; +extern int debugging; +extern int stepping; +extern int mc_ing; +extern int mc_space; +extern char mc_char; +extern char tmpdir[]; +extern char s_standout[]; +extern char e_standout[]; +extern char s_italic[]; +extern char e_italic[]; +extern char s_bold[]; +extern char e_bold[]; +extern char *dbgfile; +extern char *printer; + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#define DEBUGGING(args) \ +{ \ + if (debugging) { \ + debugMessage args; \ + } \ +} + +#ifdef DEBUG +#define ASSERT(condition, args) \ +{ \ + if (!(condition)) { \ + printf("%s:%d: assertion failed (%s): ",__FILE__,__LINE__,#condition);\ + printf args; \ + abort(); \ + } \ +} +#else +#define ASSERT(condition, args) +#endif + +#endif /*NRO_H*/ diff --git a/usr.bin/nroff/nroff.rez b/usr.bin/nroff/nroff.rez new file mode 100644 index 0000000..8d05a8d --- /dev/null +++ b/usr.bin/nroff/nroff.rez @@ -0,0 +1,18 @@ +/* + * $Id: nroff.rez,v 1.1 1997/03/14 06:22:29 gdr Exp $ + */ + +#include "Types.Rez" + +resource rVersion (0x1, purgeable3, nocrossbank) { + + { 1, 2, 0, /* version 1.2.0 */ + release, /* development|alpha|beta|final|release */ + 0 /* non-final release number */ + }, + verBritain, /* close enough */ + "nroff", + "Text Processing Typesetter\n" + "Devin Reade \n" + "Canada" +}; diff --git a/usr.bin/nroff/strings.c b/usr.bin/nroff/strings.c new file mode 100644 index 0000000..59d5f81 --- /dev/null +++ b/usr.bin/nroff/strings.c @@ -0,0 +1,194 @@ +/* + * strings.c - String input/output processing for nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: strings.c,v 1.1 1997/03/14 06:22:29 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "strings___"; +#endif + +#include +#include +#include +#ifdef __GNO__ +#include +#else +#include "err.h" +#endif + +#ifdef sparc +#include "sunos.h" +#endif + +#include "nroff.h" +#include "macros.h" + +static int colstr (const char *src, char *dest, size_t len); + +/* + * defstr + * + * Define a string. top level, read from command line. + * + * we should read string without interpretation EXCEPT: + * + * 1) number registers are interpolated + * 2) strings indicated by \* are interpolated + * 3) arguments indicated by \$ are interpolated + * 4) concealed newlines indicated by \(newline) are eliminated + * 5) comments indicated by \" are eliminated + * 6) \t and \a are interpreted as ASCII h tab and SOH. + * 7) \\ is interpreted as backslash and \. is interpreted as a period. + * + * currently, we do only 3. a good place to do it would be here before + * putstr, after colstr... + */ +void +defstr (char *line) { + register char *q; + register int i; + static char name[MNLEN]; + static char defn[MXMLEN+1]; + + name[0] = '\0'; + defn[0] = '\0'; + +#ifdef BORK + fprintf(stderr, "DEBUG: %s:%d name = 0x%x\tdefn = 0x%x line=%s\n", + __FILE__, __LINE__, name, defn, line); +#endif + /* + * skip the .ds and get to the name... + */ + q = skipwd (line); + q = skipbl (q); + + /* + * ok, name now holds the name. make sure it is valid (i.e. first + * char is alpha...). getwrd returns the length of the word. + */ + i = getwrd (q, name); + if (!name[0]) { + errx(-1, "missing or illegal string definition name"); + } + + /* + * truncate to 2 char max name. + */ + if (i > 2) { + name[2] = EOS; + } + + /* + * skip the name to get to the string. it CAN start with a " to + * have leading blanks... + */ + q = skipwd (q); + q = skipbl (q); + + /* + * read rest of line from input stream and collect string into + * temp buffer defn + */ + if ((i = colstr (q, defn, MXMLEN)) == ERR) { + errx(-1, "string definition too long"); + } + + /* + * store the string + */ + if (putstr (name, defn) == ERR) { + errx(-1, "string definition table full"); + } +} + + + + +/* + * colstr + * Collect string definition from input stream + */ +static int +colstr (const char *src, char *dest, size_t len) { + const char *orgsrc; + char *orgdest, *destlimit; + + orgsrc = src; + orgdest = dest; + destlimit = dest + len; /* don't let dest go past this pointer */ + +#ifdef BORK + fprintf(stderr,"DEBUG: %s:%d src=\"%s\"\n", __FILE__, __LINE__, src); +#endif + /* + * if there is a " here, we have leading blanks (skipbl in caller + * found it). just get past it... + */ + if (*src == '\"') { + src++; + } + + while ((*src != '\n') && (*src != '\r') && (*src != '\0') + && (dest < destlimit - 1)) { + + /* + * If it's a comment, it ends terminates string collection + */ + if (*src == '\\' && *(src+1) == '\"') { + /* + * first back over any whitespace between the start of the + * comment and the last non-whitespace character preceeding + * the comment + */ + while (dest > orgdest && isspace(*dest)) { + --dest; + } + + /* forward src until we hit newline or end of string */ + while (*src != '\n' && *src != '\r' && *src != '\0') { + src++; + } + break; + } + + /* + * stop at the newline... + */ + if (*src == '\n' || *src == '\r') { + break; + } + + /* + * copy it + */ + *dest++ = *src++; + } + *dest = '\0'; + + /* did we attempt to go over the allowed length for dest? */ + if (*src == '\0' || *src == '\n' || *src == '\r') { + return dest - orgdest; + } else { + return ERR; + } +} diff --git a/usr.bin/nroff/text.c b/usr.bin/nroff/text.c new file mode 100644 index 0000000..8450fe7 --- /dev/null +++ b/usr.bin/nroff/text.c @@ -0,0 +1,849 @@ +#undef OLD_WAY +/* + * text.c - text output processing portion of nroff word processor + * + * adapted for atariST/TOS by Bill Rosenkranz 11/89 + * net: rosenkra@hall.cray.com + * CIS: 71460,17 + * GENIE: W.ROSENKRANZ + * + * original author: + * + * Stephen L. Browning + * 5723 North Parker Avenue + * Indianapolis, Indiana 46220 + * + * history: + * + * - Originally written in BDS C; + * - Adapted for standard C by W. N. Paul + * - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz + * - Heavily modified by Devin Reade to avoid memory trashing bugs. + * + * $Id: text.c,v 1.1 1997/03/14 06:22:29 gdr Exp $ + */ + +#ifdef __ORCAC__ +segment "text______"; +#endif + +#include +#include +#include +#ifdef __GNO__ +#include +#else +#include "termcap.h" +#endif + +#include "nroff.h" +#include "io.h" +#include "escape.h" + +/* + * output buffer control parameters + */ +static struct { + int outp; /* next avail char pos in outbuf, init = 0 */ + int outw; /* width of text currently in buffer */ + int outwds; /* number of words in buffer, init = 0 */ + int lpr; /* output to printer, init = FALSE */ + int outesc; /* number of escape char on this line */ + char outbuf[MAXLINE];/* output of filled text */ +} co; + + +static void bold (char *p0, char *p1, int size); +static void center (char *p); +static void expand (char *p0, char c, char *s); +static void justcntr (char *p, char *q, int *limit); +static void justleft (char *p, char *q, int limit); +static void justrite (char *p, char *q, int limit); +static void leadbl (char *p); +static void puttl (char *p, int *lim, int pgno); +static void putwrd (char *wrdbuf); +static void spread (char *p, int outp, int nextra, int outwds,int escapes); +static void underl (char *p0, char *p1, int size); +static int width (char *s); +static void do_mc (char *p); + + +/* + * text + * main text processing + * + * Pre: contains the line we wish to process (and print) + * it is MAXLINE characters long, including the + * terminating NULL character. + * + * Post: + */ +void +text (char *line) { + register int i; + char wrdbuf[MAXLINE]; + + /* + * skip over leading blanks if in fill mode. we indent later. + * since leadbl does a robrk, do it if in .nf mode + */ + if (dc.fill == YES) { + if (*line == ' ' || *line == '\n' || *line == '\r') { + /* note that leadbl shifts left as necessary */ + leadbl (line); + } + } else { + robrk (); + } + + /* + * expand escape sequences from into + */ + expesc (line, wrdbuf, MAXLINE); + + /* + * test for how to output + */ + if (dc.ulval > 0) { + /* + * underline (.ul) + * + * Because of the way underlining is handled, + * MAXLINE should be declared to be three times + * larger than the longest expected input line + * for underlining. Since many of the character + * buffers use this parameter, a lot of memory + * can be allocated when it may not really be + * needed. A MAXLINE of 180 would allow about + * 60 characters in the output line to be + * underlined (remember that only alphanumerics + * get underlined - no spaces or punctuation). + */ + underl (line, wrdbuf, MAXLINE); + --dc.ulval; + } + if (dc.cuval > 0) { + /* + * continuous underline (.cu) + */ + underl (line, wrdbuf, MAXLINE); + --dc.cuval; + } + if (dc.boval > 0) { + /* + * bold (.bo) + */ + bold (line, wrdbuf, MAXLINE); + --dc.boval; + } + if (dc.ceval > 0) { + /* + * centered (.ce) + */ + center (line); + do_mc (line); + put (line); + --dc.ceval; + } else if ((*line == '\r' || *line == '\n') && dc.fill == NO) { + /* + * all blank line + */ + do_mc (line); + put (line); + } else if (dc.fill == NO) { + /* + * unfilled (.nf) + */ + do_mc (line); + put (line); + } else { + /* + * anything else... + * + * init escape char counter for this line... + */ + /* co.outesc = 0;*/ + + + /* + * get a word and put it out. increment ptr to the next + * word. + */ + while ((i = getwrd (line, wrdbuf)) > 0) { + /* co.outesc += countesc (wrdbuf);*/ + + putwrd (wrdbuf); + line += i; + } + } +} + + +/* + * bold + * insert bold face text (by overstriking) + */ +static void +bold (register char *p0, register char *p1, int size) +{ + + register int i; + register int j; + + j = 0; + for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i) + { + if (isalpha (p0[i]) || isdigit (p0[i])) + { + p1[j++] = p0[i]; + p1[j++] = '\b'; + } + p1[j++] = p0[i]; + } + p1[j++] = '\n'; + p1[j] = EOS; + while (*p1 != EOS) + *p0++ = *p1++; + *p0 = EOS; +} + +/* + * center + * center a line by setting tival + */ +static void +center (register char *p) { + int t; + + t = (dc.rmval + dc.tival - width (p)) >> 1; + dc.tival = MAX(t, 0); +} + + +/* + * expand + * expand title buffer to include character string + */ +static void +expand (register char *p0, char c, register char *s) { + register char *p; + register char *q; + register char *r; + char tmp[MAXLINE]; + + p = p0; + q = tmp; + while (*p != EOS) { + if (*p == c) { + r = s; + while (*r != EOS) { + *q++ = *r++; + } + } else { + *q++ = *p; + } + ++p; + } + *q = EOS; + strcpy (p0, tmp); /* copy it back */ +} + +/* + * justcntr + * center title text into print buffer + */ +static void +justcntr (register char *p, char *q, int *limit) { + register int len; + + len = width (p); + q = &q[(limit[RIGHT] + limit[LEFT] - len) >> 1]; + while (*p != EOS) { + *q++ = *p++; + } +} + +/* + * justleft + * left justify title text into print buffer + */ +static void +justleft (register char *p, char *q, int limit) { + q = &q[limit]; + while (*p != EOS) { + *q++ = *p++; + } +} + +/* + * justrite + * right justify title text into print buffer + */ +static void +justrite (register char *p, char *q, int limit) { + register int len; + + len = width (p); + q = &q[limit - len]; + while (*p != EOS) { + *q++ = *p++; + } +} + +/* + * leadbl + * delete leading blanks, set tival + * + * REVIEWED + */ +static void +leadbl (register char *p) { + register char *q; + register int i; + + /* + * end current line and reset co struct + */ + robrk (); + + /* + * skip spaces + */ + for (i = 0; p[i] == ' ' || p[i] == '\t'; ++i); + + /* + * if not end of line, reset current temp indent + */ + if (p[i] != '\n' && p[i] != '\r') { + dc.tival = i; + } + + /* + * shift string + */ + q = &p[i]; +#ifdef DEBUG + i = 0; +#endif + while (*q) { +#ifdef DEBUG + i++; + ASSERT(i 0) { + if ((pg.curpag % 2) == 0) { + puttl (pg.efoot, pg.eflim, pg.curpag); + } else { + puttl (pg.ofoot, pg.oflim, pg.curpag); + } + skip (pg.m4val - 1); + } + } +} + + +/* + * phead + * put out page header + */ +void +phead (void) { + pg.curpag = pg.newpag; + if (pg.curpag >= pg.frstpg && pg.curpag <= pg.lastpg) { + dc.prflg = TRUE; + } else { + dc.prflg = FALSE; + } + ++pg.newpag; + set_ireg ("%", pg.newpag, 0); + if (dc.prflg == TRUE) { + if (pg.m1val > 0) { + skip (pg.m1val - 1); + if ((pg.curpag % 2) == 0) { + puttl (pg.ehead, pg.ehlim, pg.curpag); + } else { + puttl (pg.ohead, pg.ohlim, pg.curpag); + } + } + skip (pg.m2val); + } + /* + * initialize lineno for the next page + */ + pg.lineno = pg.m1val + pg.m2val + 1; + set_ireg ("ln", pg.lineno, 0); +} + + +/* + * puttl + * put out title or footer + */ +static void +puttl (register char *p, int *lim, int pgno) { + register int i; + char pn[8]; + char t[MAXLINE]; + char h[MAXLINE]; + char delim; + + itoda (pgno, pn, 6); + for (i = 0; i < MAXLINE; ++i) { + h[i] = ' '; + } + delim = *p++; + p = getfield (p, t, delim); + expand (t, dc.pgchr, pn); + justleft (t, h, lim[LEFT]); + p = getfield (p, t, delim); + expand (t, dc.pgchr, pn); + justcntr (t, h, lim); + p = getfield (p, t, delim); + expand (t, dc.pgchr, pn); + justrite (t, h, lim[RIGHT]); + for (i = MAXLINE - 4; h[i] == ' '; --i) { + h[i] = EOS; + } + h[++i] = '\n'; + h[++i] = '\r'; + h[++i] = EOS; + if (strlen (h) > 2) { + for (i = 0; i < pg.offset; ++i) { + PRCHAR2(' ', out_stream); + } + } + putlin (h, out_stream); +} + +/* + * putwrd + * put word in output buffer + */ + +static void +putwrd (register char *wrdbuf) { + register char *p0; + register char *p1; + int w; + int last; + int llval; + int nextra; + + /* + * check if this word puts us over the limit + */ + w = width (wrdbuf); + last = strlen (wrdbuf) + co.outp; + llval = dc.rmval - dc.tival; + /* if (((co.outp > 0) && ((co.outw + w) > llval))*/ + co.outesc += countesc (wrdbuf); + if (((co.outp > 0) && ((co.outw + w - co.outesc) > llval)) + ||(last > MAXLINE)) { + /* + * last word exceeds limit so prepare to break line, print + * it, and reset outbuf. + */ + last -= co.outp; + if (dc.juval == YES) { + nextra = llval - co.outw + 1; + + /* + * Do not take in the escape char of the + * word that didn't fit on this line anymore + */ + co.outesc -= countesc (wrdbuf); + + /* + * Check whether last word was end of + * sentence and modify counts so that + * it is right justified. + */ + if (co.outbuf[co.outp - 2] == ' ') { + --co.outp; + ++nextra; + } +#ifdef OLD_WAY + spread (co.outbuf, co.outp - 1, nextra, co.outwds, co.outesc); + if ((nextra > 0) && (co.outwds > 1)) { + co.outp += (nextra - 1); + } +#if 0 + if (co.outesc > 0) { + co.outp += co.outesc; + } +#endif /* 0 */ +#else /* OLD_WAY */ + spread (co.outbuf, co.outp - 1, nextra, co.outwds, co.outesc); + if ((nextra + co.outesc > 0) && (co.outwds > 1)) { + co.outp += (nextra + co.outesc - 1); + } +#endif + } + + /* + * break line, output it, and reset all co members. reset + * esc count. + */ + robrk (); + co.outesc = countesc (wrdbuf); + } + + /* + * copy the current word to the out buffer which may have been + * reset + */ + p0 = wrdbuf; + p1 = co.outbuf + co.outp; + while (*p0 != EOS) { + *p1++ = *p0++; + } + + co.outp = last; + co.outbuf[co.outp++] = ' '; + co.outw += w + 1; + co.outwds += 1; +} + +/* + * skip + * skips the number of lines specified by n. + */ +void +skip (register int n) { + register int i; + register int j; + + if (dc.prflg == TRUE && n > 0) { + for (i = 0; i < n; ++i) { + /* + * handle blank line with changebar + */ + if (mc_ing == TRUE) { + for (j = 0; j < pg.offset; ++j) { + PRCHAR2(' ', out_stream); + } + for (j = 0; j < dc.rmval; ++j) { + PRCHAR2(' ', out_stream); + } + for (j = 0; j < mc_space; j++) { + PRCHAR2(' ', out_stream); + } + PRCHAR(mc_char, out_stream); + } + PRCHAR2('\n', out_stream); +#if 0 + /* gdr: not required */ + prchar ('\r', out_stream); +#endif + } + } +} + + +/* + * spread + * spread words to justify right margin + */ +static void +spread (register char *p, int outp, int nextra, int outwds, int escapes) { + register int i; + register int j; + register int nb; + register int ne; + register int nholes; + + + /* + * quick sanity check... + */ +#ifdef OLDWAY + if ((nextra <= 0) || (outwds <= 1)) { + return; + } +#else + if ((nextra + escapes < 1) || (outwds < 2)) { + return; + } +#endif + + /* + * set up for the spread and do it... + */ + dc.sprdir = ~dc.sprdir; +#ifdef OLD_WAY + ne = nextra; +#else + ne = nextra + escapes; +#endif + nholes = outwds - 1; /* holes between words */ + i = outp - 1; /* last non-blank character */ + j = MIN(MAXLINE - 3, i + ne); /* leave room for CR,LF,EOS */ +#if 0 + j += escapes; + if (p[i-1] == 27) { + j += 2; + } + j = MIN(j, MAXLINE - 3); +#endif + while (i < j) { + p[j] = p[i]; + if (p[i] == ' ') { + if (dc.sprdir == 0) { + nb = (ne - 1) / nholes + 1; + } else { + nb = ne / nholes; + } + ne -= nb; + --nholes; + for (; nb > 0; --nb) { + --j; + p[j] = ' '; + } + } + --i; + --j; + } +} + + +/* + * strkovr + * split overstrikes (backspaces) into seperate buffer + */ +int +strkovr (char *p, char *q) { + register char *pp; + int bsflg; + + bsflg = FALSE; + pp = p; + while (*p != EOS) { + *q = ' '; + *pp = *p; + ++p; + if (*p == '\b') { + if (*pp >= ' ' && *pp <= '~') { + bsflg = TRUE; + *q = *pp; + ++p; + *pp = *p; + ++p; + } + } + ++q; + ++pp; + } + *q++ = NEWLINE; + *q = *pp = EOS; + + return bsflg; +} + + +/* + * underl + * underline a line + */ +static void +underl (register char *p0, register char *p1, int size) { + register int i; + register int j; + + j = 0; + for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i) { + if (p0[i] >= ' ' && + p0[i] <= '~' && + (isalpha (p0[i]) || isdigit (p0[i]) || dc.cuval > 0)) + { + p1[j++] = '_'; + p1[j++] = '\b'; + } + p1[j++] = p0[i]; + } + p1[j++] = '\n'; + p1[j] = EOS; + while (*p1 != EOS) { + *p0++ = *p1++; + } + *p0 = EOS; +} + +/* + * width + * compute width of character string + */ +static int +width (char *s) { + register int w; + + w = 0; + for (; *s != '\0'; s++) { + ASSERT((*s != '\n' && *s != '\r'), ("\n")); + if ((*s >= 32) && (*s < 127)) { + ++w; + } else if (*s == '\b' || *s == 128) { + --w; + } + /* ignore high-bit chars and other control chars */ + } + return w; +} + + +/* + * do_mc + * add margin char (change bar) for .nf and .ce lines. + * + * filled lines handled in robrk(). blank lines (.sp) handled in skip(). + * note: robrk() calls this routine, too. + */ +static void +do_mc (char *p) { + register char *ps; + register int nspaces; + register int i; + register int has_cr; + register int has_lf; + int len; + int nesc; + + if (mc_ing == FALSE) { + return; + } + + len = strlen (p); + + /* + * get to the end... + */ + ps = p; + while (*ps) { + ps++; + } + + /* + * check for cr and lf + */ + ps--; + has_lf = 0; + has_cr = 0; + while (ps >= p && (*ps == '\r' || *ps == '\n')) { + if (*ps == '\n') { + has_lf++; + } else { + has_cr++; + } + len--; + ps--; + } + if (has_lf < has_cr) { + has_lf = has_cr; + } else if (has_cr < has_lf) { + has_cr = has_lf; + } + + /* + * remove any trailing blanks here + */ + while (ps >= p && *ps == ' ') { + ps--; + len--; + } + *++ps = EOS; + + + /* + * add trailing spaces for short lines. count escapes, subtract + * from len. use rmval for rigth margin (minus tival which is + * added later in put). + */ + nesc = countesc (p); + len -= nesc; + nspaces = dc.rmval - dc.tival - len; + for (i = 0; i < nspaces; i++, ps++) { + *ps = ' '; + } + + /* + * add the bar... + */ + for (i = 0; i < mc_space; i++, ps++) { + *ps = ' '; + } + *ps++ = mc_char; + + /* + * replace cr, lf, and EOS + */ + while (has_lf--) { + *ps++ = '\r'; + *ps++ = '\n'; + } + *ps = EOS; + + return; +} + +void +initOutbuf (void) { + co.outp = 0; + co.outw = 0; + co.outwds = 0; + co.lpr = FALSE; + co.outesc = 0; + memset(co.outbuf, EOS, MAXLINE); +#if 0 + for (i = 0; i < MAXLINE; ++i) { + co.outbuf[i] = EOS; + } +#endif +} + + +/* + * robrk + * + * End current filled line. References and modifies globals: + * co + */ +void +robrk (void) { + if (co.outp > 0) { + /* + * handle margin char (change bar) here for all filled lines + */ + ASSERT(MAXLINE - co.outp > 2, ("output buffer overrun: >%d:%d:%d<\n", + MAXLINE, co.outp, MAXLINE- co.outp)); + co.outbuf[co.outp] = '\r'; + co.outbuf[co.outp+1] = '\n'; + co.outbuf[co.outp+2] = EOS; + + do_mc (co.outbuf); + + put (co.outbuf); + } + co.outp = 0; + co.outw = 0; + co.outwds = 0; + co.outesc = 0; +} + +void +setPrinting(int val) { + co.lpr = val; +} + diff --git a/usr.bin/nroff/tmac.an b/usr.bin/nroff/tmac.an new file mode 100644 index 0000000..9a51c6c --- /dev/null +++ b/usr.bin/nroff/tmac.an @@ -0,0 +1,335 @@ +.\" set this non-zero to turn on debugging +.nr Z 1 +.\" ************************************************************************** +.\" +.\" -man package for nroff. not quite unix(tm), but adequate/working... +.\" +.\" usage: nroff -man file [...] +.\" +.\" included here are: TH, Th, SH, SS, IP, PP, LP, RS, RP, RE, I, B +.\" +.\" v1.10 7/22/90 rosenkra@convex.com (Bill Rosenkranz) +.\" freely distributable (no copyright, etc.) +.\" +.\" ************************************************************************** +.\" +.\" some perdefined strings (quotes, etc) +.\" +.ds S s +.ds ` "` +.ds ' "' +.ds lq "" +.ds rq "" +.\" +.\" these are various predefined date and time strings +.\" +.\" DW day-of-week: +.if \n(dw=1 .ds DW "Sun +.if \n(dw=2 .ds DW "Mon +.if \n(dw=3 .ds DW "Tue +.if \n(dw=4 .ds DW "Wed +.if \n(dw=5 .ds DW "Thu +.if \n(dw=6 .ds DW "Fri +.if \n(dw=7 .ds DW "Sat +.\" Dy month day: +.if \n(mo=1 .ds Dy "Jan \n(dy +.if \n(mo=2 .ds Dy "Feb \n(dy +.if \n(mo=3 .ds Dy "Mar \n(dy +.if \n(mo=4 .ds Dy "Apr \n(dy +.if \n(mo=5 .ds Dy "May \n(dy +.if \n(mo=6 .ds Dy "Jun \n(dy +.if \n(mo=7 .ds Dy "Jul \n(dy +.if \n(mo=8 .ds Dy "Aug \n(dy +.if \n(mo=9 .ds Dy "Sep \n(dy +.if \n(mo=10 .ds Dy "Oct \n(dy +.if \n(mo=11 .ds Dy "Nov \n(dy +.if \n(mo=12 .ds Dy "Dec \n(dy +.ds Da "\n(hh:\n(mm:\n(ss \n(mo/\n(dy/\n(yr +.ds Yr "19\n(yr +.ds DY "\*(Dy, \*(Yr +.ds TM "\n(hh:\n(mm:\n(ss +.ds DA "\*(TM \*(DY +.ds CT "\*(DW \*(Dy \*(TM 19\n(yr +.\" +.\" they look like this: +.\" +.\" DW Sun +.\" Dy Mar 4 +.\" DY Mar 4, 1990 +.\" Yr 1990 +.\" TM 16:34:00 +.\" DA 16:34:00 Mar 4, 1990 +.\" Da 16:34:00 2/4/90 +.\" CT Sun Mar 4 16:34:00 1990 like ctime(2) +.\" +.\" ************************************************************************** +.\" +.\" startup stuff... +.\" +.\" X is number register used internally here. it is initially 0. it gets +.\" set to 1 in TH if ONLINE is set. it is used in the EX macro to force +.\" an immediate exit at the end. +.\" +.in 0.0i +.po 0.0i +.lt 7.2i +.ll 7.2i +.m1 3 +.m2 3 +.m3 3 +.m4 3 +.nr X 0 +.\" +.\" ************************************************************************** +.\" +.\" MACROS... +.\" +.\" ----------------------------------------------------------------------- TH +.\" main page heading +.\" +.\" fields are usually: 1-name, 2-section, 3-section name, 4-version, 5-date +.\" 1,2,3 are on header, 4,5 and page on footer. empty strings are skipped +.\" by making the arg "". this must be first! there is an extra field at the +.\" end ($6) which, if "ONLINE", prints the page without page breaks (i.e. +.\" headers/footers). +.\" +.\" $1 $2 $3 +.\" | | | +.\" v v v +.\" NAME (1) Section NAME (1) +.\" ... +.\" Version Date Page n +.\" ^ ^ +.\" | | +.\" $4 $5 +.\" +.\" .TH NAME 1 "Commands" "Version 1.0" "7 March 1990" ["ONLINE"] +.\" +.\" there is an extension here: if the 6th argument is "ONLINE" then the +.\" resultant output does not have any headers/footers. this is useful for +.\" making manpages for online use. +.\" +.de TH +.\" define Se as default chapter name based on input chapter number +.if $2=0 .ds Se "General Information +.if $2=1 .ds Se "Commands and Applications +.if $2=2 .ds Se "System Calls +.if $2=3 .ds Se "Library Calls +.if $2=4 .ds Se "Hardware and Special Files +.if $2=5 .ds Se "File Formats +.if $2=6 .ds Se "Games +.if $2=7 .ds Se "Miscellaneous +.if $2=8 .ds Se "Administation Commands +.\" if the 6th arg is "ONLINE", set up for online docs output (no head/foot) +.if !"$6"ONLINE" .pl 66 +.if "$6"ONLINE" .m1 0 +.if "$6"ONLINE" .m2 0 +.if "$6"ONLINE" .m3 0 +.if "$6"ONLINE" .m4 0 +.if !"$6"ONLINE" .tl |$1 ($2)|$3|$1 ($2)| +.if !"$6"ONLINE" .if "$3"" .tl |$1 ($2)|\*(Se|$1 ($2)| +.if !"$6"ONLINE" .fo |$4|$5|Page %| +.if !"$6"ONLINE" .if "$4"" .fo |\*(CT|$5|Page %| +.\" this is used by macro EX (exit) +.if "$6"ONLINE" .nr X 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.. +.\" ----------------------------------------------------------------------- Th +.\" alternate main page heading +.\" +.\" this prints no header/footer so it is good for creating online docs +.\" for man(1). it ignores all args. +.\" +.\" .Th NAME 1 +.\" +.de Th +.m1 0 +.m2 0 +.m3 0 +.m4 0 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.nr X 1 +.. +.de UC +.if t .ds ]W GNO/ME Version 1.0 +.. +.\" ----------------------------------------------------------------------- EX +.\" exit NOW! (no extra space at end of document) +.\" +.de EX +.if \nX=1 .sp +.if \nX=1 .ex +.. +.\" ----------------------------------------------------------------------- RS +.\" start relative indent +.\" +.de RS +.br +.\" change to 0.5i for "normal" nroff output... +.in +0.8i +.. +.\" ----------------------------------------------------------------------- RE +.\" end relative indent +.\" +.de RE +.br +.\" change to 0.5i for "normal" nroff output... +.in -0.8i +.. +.\" ----------------------------------------------------------------------- TP +.\" indented paragraph with tag (no clue what the difference is) +.\" +.de TP +.IP +.\" .if \n(.$ \{ $1 $2 \} +.\" .if !\n(.$ \{ \fBHAS NO ARGS\fR \} +.. +.\" ----------------------------------------------------------------------- IP +.\" indented paragraph with tag (from this line) +.\" +.de IP +.br +.sp 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +\&$1 $2 $3 $4 $5 $6 $7 $8 $9 +.br +.\" change to 0.5i for "normal" nroff output... +.in +0.8i +.. +.\" ----------------------------------------------------------------------- HP +.\" indented paragraph without tag (from this line) +.\" +.de HP +.br +.sp 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.in +0.8i +.. +.\" ----------------------------------------------------------------------- RP +.\" relative indented paragraph with tag. MUST end with .RE +.\" +.de RP +.br +.sp 1 +.\".if !\\n(.i>8 .in 0.8i +\&$1 $2 $3 $4 $5 $6 $7 $8 $9 +.br +.\" change to 0.5i for "normal" nroff output... +.in +0.8i +.. +.\" ----------------------------------------------------------------------- pp +.\" start a new indented paragraph +.\" +.de pp +.sp 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.ti +0.8i +.. +.\" ----------------------------------------------------------------------- PP +.\" start a new unindented paragraph +.\" +.de PP +.sp 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.. +.\" ----------------------------------------------------------------------- LP +.\" start a new unindented paragraph (same as PP) +.\" +.de LP +.sp 1 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.. +.\" ----------------------------------------------------------------------- SH +.\" main section heading +.\" +.de SH +.sp 1 +.ne 3 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.ti -0.8i +.\".bo +\&$1 $2 $3 $4 $5 $6 $7 $8 $9 +.br +.. +.\" ----------------------------------------------------------------------- SS +.\" subsection heading, same indent +.\" +.de SS +.sp 1 +.ne 3 +.\" change to 0.5i for "normal" nroff output... +.in 0.8i +.\".bo +\&$1 $2 $3 $4 $5 $6 $7 $8 $9 +.sp +.. +.\" ----------------------------------------------------------------------- I +.\" italic text (must handle at least 2 args) +.\" +.de I +\&\fI$1\fR$2 +.. +.\" ----------------------------------------------------------------------- B +.\" bold text (must handle at least 2 args) +.\" +.de B +\&\fB$1\fR$2 +.. +.\" ----------------------------------------------------------------------- R +.\" Roman text +.\" +.de R +\&\fR$1$2 +.. +.\" ----------------------------------------------------------------------- IR +.\" alternate italic and Roman text (must handle at least 6 args) +.\" +.de IR +\&\fI$1\fR$2\fI$3\fR$4\fI$5\fR$6 +.. +.\" ----------------------------------------------------------------------- RI +.\" alternate Roman and italic text (must handle at least 6 args) +.\" +.de RI +\&\fR$1\fI$2\fR$3\fI$4\fR$5\fI$6\fR +.. +.\" ----------------------------------------------------------------------- BR +.\" alternate bold and Roman text (must handle at least 6 args) +.\" +.de BR +\&\fB$1\fR$2\fB$3\fR$4\fB$5\fR$6 +.. +.\" ----------------------------------------------------------------------- RB +.\" alternate Roman and bold text (must handle at least 6 args) +.\" +.de RB +\&\fR$1\fB$2\fR$3\fB$4\fR$5\fB$6\fR +.. +.\" ----------------------------------------------------------------------- SM +.\" small text +.\" +.de SM +\&\fB$1\fR +.. +.\" ----------------------------------------------------------------------- IX +.\" make index entry (ignored by this nroff...) +.\" +.de IX +.. +.\" ----------------------------------------------------------------------- }D +.\" debug. use (e.g. print current indent): +.\" +.\" .}D .br +.\" .}D "** DEBUG ** before RS \n(.i" +.\" +.de }D +.if \nZ>0 \&$1 +.. diff --git a/usr.bin/nroff/tmac.s b/usr.bin/nroff/tmac.s new file mode 100644 index 0000000..e2df828 --- /dev/null +++ b/usr.bin/nroff/tmac.s @@ -0,0 +1,406 @@ +.\" set this non-zero to turn on debugging +.nr Z 0 +.\" ************************************************************************** +.\" +.\" partial -ms package for nroff. macros for simple paper/report formats +.\" +.\" usage: nroff -ms file [...] +.\" +.\" included here are: +.\" +.\" TL, AU, AI, AB, AE, SH, NH, PP, LP, QP, XP, RS, RE, IP, I, B, R +.\" +.\" extensions include: +.\" +.\" TI (temp indent), EX (exit NOW) +.\" +.\" includes somewhat kludgy support for XS, XA, XE, PX (table of contents) +.\" +.\" v1.10 7/22/90 rosenkra@convex.com (Bill Rosenkranz) +.\" freely distributable (no copyright, etc.) +.\" +.\" ************************************************************************** +.\" +.\" some perdefined strings (Quote, Unquote, dash, footer parts, etc): +.\" +.ds Q "" +.ds U "" +.ds - -- +.ds CF "ImPoSsIbLe +.ds LF "\0 +.ds RF "\0 +.\" +.\" these are various predefined date and time strings +.\" +.\" DW day-of-week: +.if \n(dw=1 .ds DW "Sun +.if \n(dw=2 .ds DW "Mon +.if \n(dw=3 .ds DW "Tue +.if \n(dw=4 .ds DW "Wed +.if \n(dw=5 .ds DW "Thu +.if \n(dw=6 .ds DW "Fri +.if \n(dw=7 .ds DW "Sat +.\" MO month: +.if \n(mo=1 .ds MO "January +.if \n(mo=2 .ds MO "February +.if \n(mo=3 .ds MO "March +.if \n(mo=4 .ds MO "April +.if \n(mo=5 .ds MO "May +.if \n(mo=6 .ds MO "June +.if \n(mo=7 .ds MO "July +.if \n(mo=8 .ds MO "August +.if \n(mo=9 .ds MO "September +.if \n(mo=10 .ds MO "October +.if \n(mo=11 .ds MO "November +.if \n(mo=12 .ds MO "December +.\" make some composites: +.ds Dy "\*(MO \n(dy +.ds Da "\n(hh:\n(mm:\n(ss \n(mo/\n(dy/\n(yr +.ds Yr "19\n(yr +.ds dY "\*(Dy, \*(Yr +.ds DY "\n(dy \*(MO \*(Yr +.ds TM "\n(hh:\n(mm:\n(ss +.ds DA "\*(TM \*(DY +.ds CT "\*(DW \*(Dy \*(TM 19\n(yr +.\" +.\" they look like this: +.\" +.\" DW Sun +.\" MO March +.\" Dy March 4 +.\" dY March 4, 1990 +.\" DY 4 March 1990 <--- "normal" nroff form +.\" Yr 1990 +.\" TM 16:34:00 +.\" DA 16:34:00 March 4, 1990 +.\" Da 16:34:00 2/4/90 +.\" CT Sun March 4 16:34:00 1990 almost like ctime(2) +.\" +.\" ************************************************************************** +.\" +.\" startup stuff... +.\" +.pl 66 +.ll 6.0i +.lt 6.0i +.m1 3 +.m2 2 +.m3 3 +.m4 3 +.\" no header line on first page! (set back in AB, SH, NH, LP, PP, QP) +.tl |||| +.\" this is the default footer (date, centered) unless string CF is defined +.fo ||\*(DY|| +.\" these are for NH numbering (up to 5 levels, a la sun, X holds level) +.nr A 0 1 +.af A 1 +.nr B 0 1 +.af B 1 +.nr C 0 1 +.af C 1 +.nr D 0 1 +.af D 1 +.nr E 0 1 +.af E 1 +.nr X 1 1 +.\" +.\" ************************************************************************** +.\" +.\" MACROS... +.\" +.\" ---------------------------------------------------------------------- TL +.\" title for document (optional) +.\" +.de TL +.sp 4 +.ce 1000 +.\" reset footer. you MUST define CF, even to blank, to get the others! +.if !"\*(CF"ImPoSsIbLe" .fo |\*(LF|\*(CF|\*(RF| +.. +.\" ---------------------------------------------------------------------- AU +.\" author(s) (optional, requires .TL) +.\" +.de AU +.sp 2 +.. +.\" ---------------------------------------------------------------------- AI +.\" author's institution (optional, requires .TL) +.\" +.de AI +.sp 1 +.. +.\" ---------------------------------------------------------------------- AB +.\" abstract (optional, requires .TL, .AE) +.\" +.de AB +.br +.sp 2 +.\" check for arg to AB. can be "no" or something like "SUMMARY". if "no", +.\" no title above the abstract +.if !"$1"no" .if "$1"" ABSTRACT +.if !"$1"no" .if !"$1"" $1 +.if !"$1"no" .sp 1 +.\" set new line length... +.ce 0 +.ll 5.5i +.in 0.5i +.tl ||- % -|| +.. +.\" ---------------------------------------------------------------------- AE +.\" abstract end (optional, requires .TL) +.\" +.de AE +.br +.sp 1 +.\" reset... +.ce 0 +.in 0.0i +.ll 6.0i +.. +.\" ----------------------------------------------------------------------- SH +.\" section heading, no number (optional) +.\" +.de SH +.\" reset... +.ll 6.0i +.in 0.0i +.tl ||- % -|| +.\" see note in TL +.if !"\*(CF"ImPoSsIbLe" .fo |\*(LF|\*(CF|\*(RF| +.br +.ce 0 +.sp 2 +.ne 4 +.\" section title goes here, fill mode only so far... +.. +.\" ---------------------------------------------------------------------- NH +.\" numbered section heading. arg (required) is the section level. +.\" this would be MUCH simpler if the .if command supported "{...}". there is +.\" a bug in nroff. i does not set the .$ number register correctly (number of +.\" args for the current macro). that is the reason why level 1 must be set. +.\" +.de NH +.\" do everything from SH... +.SH +.\" if ".NH 0", reset numbering +.if $1=0 .nr A 1 1 +.if $1=0 .nr B 0 1 +.if $1=0 .nr C 0 1 +.if $1=0 .nr D 0 1 +.if $1=0 .nr E 0 1 +.if $1=0 .nr X 1 1 +.\" level 1 (two types here: ".NH" and ".NH 1"): +.\" once .$ num reg is fixed, these 5 should be: .if \n(.$=0 .nr A +1 etc. +.if "$1"" .nr A +1 +.if "$1"" .nr B 0 1 +.if "$1"" .nr C 0 1 +.if "$1"" .nr D 0 1 +.if "$1"" .nr E 0 1 +.if "$1"" .nr X 1 1 +.if "$1"1" .nr A +1 +.if "$1"1" .nr B 0 1 +.if "$1"1" .nr C 0 1 +.if "$1"1" .nr D 0 1 +.if "$1"1" .nr E 0 1 +.if "$1"1" .nr X 1 1 +.\" level 2 (increment B, reset lower levels): +.if "$1"2" .nr B +1 +.if "$1"2" .nr C 0 1 +.if "$1"2" .nr D 0 1 +.if "$1"2" .nr E 0 1 +.if "$1"2" .nr X 2 1 +.\" level 3 (increment C, reset lower levels): +.if "$1"3" .nr C +1 +.if "$1"3" .nr D 0 1 +.if "$1"3" .nr E 0 1 +.if "$1"3" .nr X 3 1 +.\" level 4 (increment D, reset lower levels): +.if "$1"4" .nr D +1 +.if "$1"4" .nr E 0 1 +.if "$1"4" .nr X 4 1 +.\" level 5 (increment E, no more lower levels!): +.if "$1"5" .nr E +1 +.if "$1"5" .nr X 5 1 +.\" print out the section number now, depending on current level... +.if \nX=1 \nA. +.if \nX=2 \nA.\nB. +.if \nX=3 \nA.\nB.\nC. +.if \nX=4 \nA.\nB.\nC.\nD. +.if \nX=5 \nA.\nB.\nC.\nD.\nE. +.\" section title goes here... +.. +.\" ----------------------------------------------------------------------- LP +.\" start a new left block paragraph (either .LP or .PP required) +.\" +.de LP +.br +.\" reset... +.tl ||- % -|| +.ce 0 +.sp 1 +.ll 6.0i +.in 0.0i +.. +.\" ----------------------------------------------------------------------- PP +.\" start a new indented paragraph (either .LP or .PP required) +.\" +.de PP +.\" do everything for LP, then make a temp indent... +.LP +.ti +0.5i +.. +.\" ----------------------------------------------------------------------- XP +.\" start a new extended paragraph (bibliography) +.\" +.de XP +.br +.\" reset... +.tl ||- % -|| +.ce 0 +.sp 1 +.ll 6.0i +.in 0.5i +.ti -0.5i +.. +.\" ----------------------------------------------------------------------- QP +.\" start a new quoted paragraph (indented and shorter) +.\" +.de QP +.br +.tl ||- % -|| +.ce 0 +.sp 1 +.\" set new line length, indent. PP, LP, SH, and NH reset +.ll 6.0i +.in 0.0i +.ll -0.5i +.in +0.5i +.. +.\" ----------------------------------------------------------------------- IP +.\" indented paragraph with tag (relative) +.\" +.de IP +.br +.tl ||- % -|| +.ce 0 +.sp 1 +.if \n(.i>4 .in -0.5i +.in +0.5i +.}D "***DEBUG IP: indent before tag is: \n(.i" +.}D .br +.if !"$1"" .ti -0.5i +.if !"$1"" \&$1 +.if !"$1"" .br +.}D "***DEBUG IP: indent after tag is: \n(.i" +.. +.\" ----------------------------------------------------------------------- RS +.\" start relative indent (requires .RE) +.\" +.de RS +.ce 0 +.br +.\" if there is arg, use that as indent, otherwise use +5 +.if \n(.$>0 .in +$1 +.if \n(.$=0 .in +0.5i +.}D "***DEBUG RS: indent after RS is: \n(.i" +.}D .br +.. +.\" ----------------------------------------------------------------------- RE +.\" end relative indent +.\" +.de RE +.ce 0 +.br +.\" if there is arg, use that as unindent, otherwise use -5 +.if \n(.$>0 .in -$1 +.if \n(.$=0 .in -0.5i +.if \n(.i<5 .in 0.0i +.}D "***DEBUG RE: indent after RE is: \n(.i" +.}D .br +.. +.\" ----------------------------------------------------------------------- XS +.\" table of contents start +.\" +.de XS +.bp +.ce 1 +Table of Contents +.ce 0 +.ll 8.0i +.sp 1 +.\" \&123456789012345678901234567890123456789012345678901234567890 +\&NOTE: add/del "dots" until line ends here ---------------->| (del this line) +.br +.\" save the page number... +.ds Xx "$1 +.\" first entry goes here... +.. +.\" ----------------------------------------------------------------------- XE +.\" table of contents end +.\" +.de XE +.\" dump last page number... +\&\0........................... \*(Xx +.br +.. +.\" ----------------------------------------------------------------------- XA +.\" subsequent table of contents entry +.\" +.de XA +.\" dump last page number... +\&\0........................... \*(Xx +.br +.\" save next page number... +.ds Xx "$1 +.\" next entry goes here... +.. +.\" ----------------------------------------------------------------------- PX +.\" print table of contents +.\" +.de PX +.\" this is a NOP without diversions... +.ll 6.0i +.. +.\" ----------------------------------------------------------------------- TI +.\" temporary indent +.\" +.de TI +.ce 0 +.ti +0.5i +.. +.\" ----------------------------------------------------------------------- EX +.\" exit NOW! (no extra space at end of document) +.\" +.de EX +.sp +.ex +.. +.\" ----------------------------------------------------------------------- I +.\" italic text +.\" +.de I +\&\fI +.if !"$1"" $1\fR$2 +.. +.\" ----------------------------------------------------------------------- B +.\" bold text +.\" +.de B +\&\fB +.if !"$1"" $1\fR$2 +.. +.\" ----------------------------------------------------------------------- R +.\" Roman (normal) text +.\" +.de R +\&\fR +.. +.\" ----------------------------------------------------------------------- }D +.\" debug. use (e.g. print current indent): +.\" +.\" .}D .br +.\" .}D "** DEBUG ** before RS \n(.i" +.\" +.de }D +.if \nZ>0 \&$1 +.. diff --git a/usr.bin/nroff/unix/err.c b/usr.bin/nroff/unix/err.c new file mode 100644 index 0000000..7107254 --- /dev/null +++ b/usr.bin/nroff/unix/err.c @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + + +#include +#include +#include +#include +#include + +#include "err.h" + +#if 0 +extern char *__progname; /* Program name, from crt0. */ +#else +static char *__progname = "nroff"; +#endif + +static FILE *err_file; /* file to use for error output */ +static void (*err_exit)(int); + +extern void iic_error(int, const char *, ...); + +void +err_set_file(void *fp) +{ + if (fp) + err_file = fp; + else + err_file = stderr; +} + +void +err_set_exit(void (*ef)(int)) +{ + err_exit = ef; +} + +void +err(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); +} + +void +verr(int eval, const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + if (! err_file) + err_set_file((FILE *)0); + (void)fprintf(err_file, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(err_file, fmt, ap); + (void)fprintf(err_file, ": "); + } + (void)fprintf(err_file, "%s\n", strerror(sverrno)); + if(err_exit) + err_exit(eval); + exit(eval); +} + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} + +void +verrx(int eval, const char *fmt, va_list ap) +{ + if (! err_file) + err_set_file((FILE *)0); + (void)fprintf(err_file, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(err_file, fmt, ap); + (void)fprintf(err_file, "\n"); + if (err_exit) + err_exit(eval); + exit(eval); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void +vwarn(const char *fmt, va_list ap) +{ + int sverrno; + + sverrno = errno; + if (! err_file) + err_set_file((FILE *)0); + (void)fprintf(err_file, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(err_file, fmt, ap); + (void)fprintf(err_file, ": "); + } + (void)fprintf(err_file, "%s\n", strerror(sverrno)); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +void +vwarnx(const char *fmt, va_list ap) +{ + if (! err_file) + err_set_file((FILE *)0); + (void)fprintf(err_file, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(err_file, fmt, ap); + (void)fprintf(err_file, "\n"); +} diff --git a/usr.bin/nroff/unix/err.h b/usr.bin/nroff/unix/err.h new file mode 100644 index 0000000..9abfda3 --- /dev/null +++ b/usr.bin/nroff/unix/err.h @@ -0,0 +1,12 @@ +#include + +void err_set_file(void *fp); +void err_set_exit(void (*ef)(int)); +void err(int eval, const char *fmt, ...); +void verr(int eval, const char *fmt, va_list ap); +void errx(int eval, const char *fmt, ...); +void verrx(int eval, const char *fmt, va_list ap); +void warn(const char *fmt, ...); +void vwarn(const char *fmt, va_list ap); +void warnx(const char *fmt, ...); +void vwarnx(const char *fmt, va_list ap); diff --git a/usr.bin/nroff/unix/int.c b/usr.bin/nroff/unix/int.c new file mode 100644 index 0000000..5ae7527 --- /dev/null +++ b/usr.bin/nroff/unix/int.c @@ -0,0 +1,38 @@ +/* + * This is an interface file for use with Insight. + * + * $Id: int.c,v 1.1 1997/03/14 06:22:27 gdr Exp $ + */ + +#include +#include "err.h" + +void +verr(int eval, const char *fmt, va_list ap) +{ + iic_error(USER_ERROR, "verr traceback"); + verr(eval, fmt, ap); +} + + +void +verrx(int eval, const char *fmt, va_list ap) +{ + iic_error(USER_ERROR, "verrx traceback"); + verrx(eval, fmt, ap); +} + +void +vwarn(const char *fmt, va_list ap) +{ + iic_error(USER_ERROR, "dummy traceback"); + vwarn(fmt, ap); +} + + +void +vwarnx(const char *fmt, va_list ap) +{ + iic_error(USER_ERROR, "dummy traceback"); + vwarnx(fmt, ap); +} diff --git a/usr.bin/nroff/unix/sunos.h b/usr.bin/nroff/unix/sunos.h new file mode 100644 index 0000000..098fd9c --- /dev/null +++ b/usr.bin/nroff/unix/sunos.h @@ -0,0 +1,19 @@ +#ifdef SUNOS4 + +#ifdef FILE +int _filbuf(FILE *); +int _flsbuf(unsigned char, FILE *); +int fclose (FILE *); +int fflush (FILE *); +int fprintf(FILE *, const char *, ...); +#endif + +#ifdef ITIMER_REAL +time_t time (time_t *); +#endif + +int printf(const char *, ...); +int tolower (int); + +#endif /* SUNOS4 */ + diff --git a/usr.bin/nroff/unix/termcap.h b/usr.bin/nroff/unix/termcap.h new file mode 100644 index 0000000..ae57c82 --- /dev/null +++ b/usr.bin/nroff/unix/termcap.h @@ -0,0 +1,10 @@ + +extern char PC, *BC, *UP; +extern short ospeed; + +int tgetent (char *bp, char *name); +int tgetnum (char *id); +int tgetflag (char *id); +char * tgetstr (char *id, char **area); +char * tgoto (char *cm, int destcol, int destline); +int tputs (char *cp, int affcnt, int (*outc)(char));