-h- ROFCMD.C Tue Jun 22 10:55:20 1982 _DRA0:ROFCMD.C;1 # /* * Command parser */ #include #include "roff.h" /* * Definitions for roff commands. * * To add a new command: * Add a #define statement at the end of the following list * Add the command name (two lower-case ascii bytes) at * the end of the cmdname[] vector (before EOS,EOS). * Add a processing routine to the case statement in command() * * Note: the command structure should probably be extended with * a data structure such as: * * struct command { * char *name; -- command name * int (*func)(); -- command handler * }; * * This will simplify user-defined commands * */ #define UNKNOWN 0 /* Unknown command */ #define FI 1 #define NF 2 #define BR 3 #define LS 4 #define BP 5 #define SP 6 #define IN 7 #define RM 8 #define TI 9 #define CE 10 #define UL 11 #define HE 12 #define FO 13 #define PL 14 #define PO 15 #define BD 16 #define M1 17 #define M2 18 #define M3 19 #define M4 20 #define EH 21 #define OH 22 #define EF 23 #define OF 24 #define CC 25 #define NE 26 #define BS 27 #define JU 28 #define NJ 29 #define SO 30 /* * This vector is used to search for the various commands. The order * of the entries is significant, following the command name definitions * given above. */ static struct cmdname { char n1; char n2; } cmdname[] { { 'f','i' }, { 'n','f' }, { 'b','r' }, { 'l','s' }, { 'b','p' }, { 's','p' }, { 'i','n' }, { 'r','m' }, { 't','i' }, { 'c','e' }, { 'u','l' }, { 'h','e' }, { 'f','o' }, { 'p','l' }, { 'p','o' }, { 'b','d' }, { 'm','1' }, { 'm','2' }, { 'm','3' }, { 'm','4' }, { 'e','h' }, { 'o','h' }, { 'e','f' }, { 'o','f' }, { 'c','c' }, { 'n','e' }, { 'b','s' }, { 'j','u' }, { 'n','j' }, { 's','o' }, { EOS,EOS }, }; /* * Locally global values * * WARNING: the use of the static definitions makes the code non-recursive. */ static int cmd_argtype; static int cmd_val; command(buf) char *buf; /* Contains the command */ /* * Process the current command in buf. Note buf[0] has '.', buf[1] has * the first actual command byte. Also, note that a numeric qualifier * must be seperated from the command name by at least one blank: * "rm 80", not "rm80". */ { register int ct; if ((ct = comtype(buf)) == UNKNOWN) { bug("", "Unknown command", buf); return; } cmd_val = getval(buf, &cmd_argtype); switch (ct) { case FI: brk(); fill = TRUE; break; case NF: brk(); fill = FALSE; break; case BR: brk(); break; case LS: setit(&lscmd); break; case CE: brk(); setit(&cecmd); break; case UL: setit(&ulcmd); break; case BD: setit(&bocmd); break; case HE: getttl(buf, &ehead); getttl(buf, &ohead); break; case FO: getttl(buf, &efoot); getttl(buf, &ofoot); break; case BP: brk(); if (lineno > 0) space(HUGE); set(&curpage, curpage+1, -HUGE, HUGE); newpage = curpage; break; case SP: setit(&spcmd); space(spval); break; case IN: brk(); set(&inval, 0, 0, rmval - 1); tival = inval; break; case RM: set(&rmval, PAGEWIDTH, tival + 1, HUGE); break; case TI: brk(); set(&tival, 0, 0, rmval); break; case PL: set(&plval, PAGELEN, m1val + m2val + m3val + m4val + 1, HUGE); bottom = plval - m3val - m4val; break; case PO: set(&offset, 0, 0, rmval - 1); break; case M1: set(&m1val, 3, 0, plval - m2val - m3val - m4val - 1); break; case M2: set(&m2val, 2, 0, plval - m1val - m3val - m4val - 1); break; case M3: set(&m3val, 2, 0, plval - m1val - m2val - m4val - 1); bottom = plval - m3val - m4val; break; case M4: set(&m4val, 3, 0, plval - m1val - m2val - m3val - 1); bottom = plval - m3val - m4val; break; case EH: getttl(buf, &ehead); break; case OH: getttl(buf, &ohead); break; case EF: getttl(buf, &efoot); break; case OF: getttl(buf, &ofoot); break; case CC: cchar = cmd_argtype; break; case NE: if ((lineno + cmd_val) > bottom && lineno <= bottom) { space(cmd_val); lineno = 0; } break; case BS: setit(&bscmd); break; case JU: rjust = TRUE; break; case NJ: rjust = FALSE; break; case SO: newfile(buf); break; default: bug("F", "Bad command value", buf); } } static setit(cp) register CMD *cp; /* Pointer to the command buffer */ /* * Set values for a normal command */ { set(&cp->c_val, cp->c_default, cp->c_minimum, cp->c_maximum); } static set(valp, defval, minimum, maximum) register int *valp; /* Value to be changed */ int defval; /* Default for the value */ int minimum; /* Minimum valid value */ int maximum; /* Maximum valid value */ /* * Change *valp as needed. */ { switch (cmd_argtype) { case EOS: case NEWLINE: *valp = defval; break; case '+': *valp += cmd_val; break; case '-': *valp -= cmd_val; break; default: *valp = cmd_val; break; } if (*valp > maximum) *valp = maximum; if (*valp < minimum) *valp = minimum; } static comtype(buf) char *buf; /* Buffer to check */ /* * Return the index of this command (or UNKNOWN) * * Note: buffer format is ".rm ...", for example. */ { register struct cmdname *cp; register char c1; register char c2; c1 = tolower(buf[1]); c2 = tolower(buf[2]); for (cp = cmdname; cp->n1 != EOS; cp++) { if (c1 == cp->n1 && c2 == cp->n2) { return((cp - cmdname) + 1); } } return(UNKNOWN); } static getttl(buf, titlep) char *buf; /* Input buffer */ register HEAD *titlep; /* Title buffer pointer */ { cpystr(&titlep->h_head, spanbl(findbl(buf))); titlep->h_left = inval; titlep->h_right = rmval; } -h- ROFF.C Tue Jun 22 10:55:20 1982 _DRA0:ROFF.C;1 /* * R O F F . C * * * Usage * * roff [-endpage] [+startpage] [-poN] [-uZZ] files * * -endpage Stop after printing this page * * +startpage Start at this page * * -poN Initially execute ".po N" Note: no space * between "po" and its argument value. * * -u? Underline and bold overprint flag: * -ul Overstrike by overprints * -ub Overstrike by overprints * -un Supress overstrike (default) * */ #include #include "roff.h" main(argc, argv) int argc; /* Number of arguments */ char *argv[]; /* Argument buffer pointer */ { register char *argp; /* Argument pointer */ register char c; /* Temp character */ int i; /* Argv[] index */ int nfiles; /* Number of files */ nfiles = 0; /* Assume all pmtr's are files */ if (argc > 1 && argv[1][0] == '?') { help(); exit(); } for (i = 1; i < argc; i++) { argp = argv[i]; switch (c = *argp) { case '+': frstpg = atoi(argp + 1); break; case '-': if (isdigit((c = argp[1]))) lstpag = atoi(argp + 1); else { switch(tolower(c)) { case 'd': debug++; verbose++; break; case 's': stopx++; break; case 'v': verbose++; break; case 'p': if (tolower(argp[2]) == 'o') { cpystr(tbuf1, ".po "); cpystr(&tbuf1[4], &argp[3]); command(tbuf1); break; } else goto nogood; case 'u': switch(tolower(argp[2])) { case 'n': osflag = 0; break; case 'b': osflag = 1; break; case 'l': osflag = 2; break; default: goto nogood; } break; default: nogood: bug("W", "Unknown option", argp); } break; } default: nfiles++; /* A file argument */ continue; /* Don't erase it */ } argv[i] = NULL; } if (nfiles == 0) { curfil->fd = stdin; roff(); } else { for (i = 1; i < argc; i++) { if (argv[i] != NULL) { bug("D", "argv[i]", argv[i]); if ((curfil->fd = fopen(argv[i], "r")) == NULL) bug("E", "Can't open", argv[i]); else { bug("", "Current file", argv[i]); roff(); fclose(curfil->fd); } } } } if (lineno > 0 || outp > outbuf) space(HUGE); putchar(NEWLINE); } roff() /* * Roff driver */ { char inbuf[INSIZE]; for (;;) { while (fgets(inbuf, sizeof inbuf, curfil->fd) != NULL) { curfil->linect++; if (debug > 1) { bug("D", "input", inbuf); } if (inbuf[0] == cchar) command(inbuf); else text(inbuf); } /* * If we're in a .so (included) file, unwind to * the previous level. If at the top level, exit. */ if (curfil == &files[0]) break; else { fclose(curfil->fd); curfil--; } } } newfile(buf) char *buf; /* .so command */ /* * Called from command() this routine opens an included file. * Note the possible syntax: * .so foo open file "foo" * .so "foo" open file "foo" * .so open file "C:foo" */ { register char *bp; register char *start; register FILE *fd; char match; if (curfil >= &files[MAXFILE]) { bug("E", "Too many .so files", buf); return; } bp = spanbl(findbl(buf)); switch (*bp) { case '"': start = ++bp; match = '"'; break; case '<': *bp = ':'; *--bp = 'C'; start = bp; match = '>'; break; default: start = bp; match = NEWLINE; break; } while (*bp != match && *bp != EOS) bp++; if (*bp == EOS) { bug("E", "No match in", buf); return; } *bp = EOS; ++curfil; if ((curfil->fd = fopen(start, "r")) == NULL) { --curfil; bug("E", "Can't open .so file", start); return; } curfil->linect = 0; } help() /* * Give good help */ { register char **dp; fprintf(stderr, "roff: Usage roff [-endpage] [+startpage] [-poN] [-uZZ] files\n"); } bug(severity, s, arg) char *severity; char *s; char *arg; /* * Error message of some sort: * severity == "D" Debugging * severity == "" Verbose documentation * severity == "F" Crash */ { register FILEBUF *fbp; char work[40]; if (*severity == EOS && (!debug && !verbose)) return; if (!debug && *severity == 'D') return; if (ftty(stdout)) { putchar(NEWLINE); fflush(stdout); } fprintf(stderr, "%cROFF-%s-%s", (*severity == EOS || *severity == 'D') ? '-' : (*severity == 'W') ? '%' : '?', severity, s); if (arg != NULL) fprintf(stderr, ": \"%s\"", arg); fprintf(stderr, "\n"); for (fbp = &files[0]; fbp <= curfil; fbp++) { fgetname(fbp->fd, work); fprintf(stderr, " %5d: %s\n", fbp->linect, work); } if (*severity == 'F') error("?ROFF-F-Can't continue\n"); } dumproff(s) register char *s; /* * Dump it visibly */ { register char c; fprintf(stderr, "\ndump of %d bytes, width = %d\n\"", strlen(s), width(s)); while ((c = (*s++ & 0377)) != EOS) { switch (c) { case '\n': fprintf(stderr, "\\n\n"); break; case '\b': fprintf(stderr, "\\b"); break; case '\r': fprintf(stderr, "\\r\n"); break; case '\f': fprintf(stderr, "\\f\n"); break; case '\t': fprintf(stderr, "\t"); break; default: if (c < ' ' || c > 0200) fprintf(stderr, "\\%o", c); else fprintf(stderr, "%c", c); break; } } fprintf(stderr, "\"\n"); } -h- ROFF.H Tue Jun 22 10:55:20 1982 _DRA0:ROFF.H;1 # /* * Global symbols and definitions for roff */ #define TRUE 1 /* YES */ #define FALSE 0 /* NO */ #define EOS 0 /* End of string marker */ #define NEWLINE ('\n') /* Newline character */ #define BACKSPACE ('\b') /* Backspace character */ #define TAB ('\t') /* Tab character */ #define FORMFEED ('\f') /* Form feed */ #define COMPUTE 0 /* Command value computed by command() */ #define MAXFILE 6 /* Number of files (from .so command) */ #define MAXLINE 133 /* Maximum print line length */ #define INSIZE 400 /* Maximum buffer size */ #define MAXOUT 400 /* outbuf[] dimension */ #define PAGENUM ('#') /* Gets "Page nn" in title */ #define DATECHAR ('%') /* Gets "Date" in title */ #define PAGEWIDTH 65 /* Default page width */ #define PAGELEN 65 /* Default page length */ #define MAXCHARS 10 /* ?? */ #define UNKNOWN 0 /* Unknown command */ #define HUGE 1000 /* Very large number for command max. */ /* * Define structures */ typedef struct cmd { /* Commands and their values */ int c_val; /* Current value */ int c_default; /* Default value */ int c_minimum; /* Minimum valid value */ int c_maximum; /* Maximum valid value */ } CMD; typedef struct head { /* Heading buffer */ int h_left; /* Left margin for head/foot */ int h_right; /* Right margin for head/foot */ char h_head[MAXLINE]; /* Current head/foot datum */ } HEAD; /* * Define command buffers for command that take values * (Note: some commands, such as .br, don't have CMD entries. */ extern CMD lscmd; extern CMD cecmd; extern CMD ulcmd; extern CMD bocmd; extern CMD pgcmd; extern CMD spcmd; extern CMD incmd; extern CMD rmcmd; extern CMD ticmd; extern CMD plcmd; extern CMD pocmd; extern CMD m1cmd; extern CMD m2cmd; extern CMD m3cmd; extern CMD m4cmd; extern CMD bscmd; /* * Define command values */ #define lsval (lscmd.c_val) /* Current line spacing */ #define ceval (cecmd.c_val) /* Number of lines to center */ #define ulval (ulcmd.c_val) /* Number of lines to underline */ #define boval (bocmd.c_val) /* Number of lines to boldface */ #define curpage (pgcmd.c_val) /* Current output page number */ #define spval (spcmd.c_val) /* Number of lines to skip */ #define inval (incmd.c_val) /* Current indentation */ #define rmval (rmcmd.c_val) /* Current right margin */ #define tival (ticmd.c_val) /* Indent for this line */ #define plval (plcmd.c_val) /* Page length in lines */ #define offset (pocmd.c_val) /* Page offset (left margin 0) */ #define m1val (m1cmd.c_val) /* Margin before, incl. header */ #define m2val (m2cmd.c_val) /* Margin after header */ #define m3val (m3cmd.c_val) /* Margin after last text line */ #define m4val (m4cmd.c_val) /* Bottom margin, incl. footer */ #define bsval (bscmd.c_val) /* Lines to blank supress */ /* * The following globals are used to define the output buffer */ extern char outbuf[MAXOUT]; /* Current line being filled */ extern char *outp; /* Free byte in outbuf[] */ extern char *prep; /* Last byte of previous word */ extern int outw; /* Width of text in outbuf[] */ extern int outwds; /* Number of words in outbuf[] */ /* * The following globals are used to define the title buffer */ extern char ttl[MAXOUT]; /* The title line */ extern char tbuf1[MAXOUT]; /* Work area */ extern char tbuf2[MAXOUT]; /* Work area */ /* * The following globals are used to define the input file buffer */ typedef struct filebuf { FILE *fd; int linect; } FILEBUF; extern FILEBUF *curfil; extern FILEBUF files[MAXFILE]; /* * Other global values */ extern int fill; /* Fill if TRUE */ extern int rjust; /* Right-justify if TRUE */ extern int prflag; /* Print if TRUE */ extern int cchar; /* Command character "." def. */ extern int newpage; /* Next output page number */ extern int lineno; /* Next line to be printed */ extern int bottom; /* Last live line on the page */ extern int frstpg; /* First page to print */ extern int lstpag; /* Last page to print */ extern int stopx; /* If set, pause between pages */ extern int osflag; /* Overstrike flag */ extern HEAD ehead; /* Even page heading */ extern HEAD ohead; /* Odd page heading */ extern HEAD efoot; /* Even page footing */ extern HEAD ofoot; /* Odd page footing */ extern int verbose; /* -v for babbling */ extern int debug; /* -d for disasters */ /* * Character functions */ extern char *spanbl(); /* Skip over blank/tab */ extern char *findbl(); /* Skip to blank/tab */ -h- ROFFOS.C Tue Jun 22 10:55:20 1982 _DRA0:ROFFOS.C;1 # /* * Overstrike and blank/tab manager * * Note that the algorithm is independent of roff * * This module converts lines with backspace into lines with overstrike. * * Calling sequence: * * extern int osflag; * * osput(c, fd) * char c; -- Character to output * FILE *fd; -- File to write to * * Osflag decides what style of overstriking. It should be set before * calling osput for the first time and then not changed. * * 0 None -- remove overstrikes * 1 Backspace (osput does nothing) * 2 Overprint line * * Note: before closing the file, you must flush internal status by * calling osput(NEWLINE, fd) * * This module does not handle wierd cases like "backspace tab" * and is not optimized for "backspace space". * * If "no overstrike" is selected, the routine will try to get rid * of underlines, rather than "real" characters. */ #include #define EOS (0) #define RETURN ('\r') #define NEWLINE ('\n') #define TAB ('\t') #define BACKSPACE ('\b') #define FORMFEED ('\f') #define BLANK (' ') #define MAXLINE 256 /* * External storage for overstrike */ int osflag = 0; /* * Local storage for overstrike */ typedef struct os { struct os *o_next; /* Chain of overstrike buffers */ int o_edge; /* Rightmost position in this */ char o_buf[MAXLINE]; /* Print line buffer */ } OS; static char os_buf[MAXLINE]; static int os_col = 0; /* Current printhead position */ static int os_edge = 0; /* Rightmost printhead position */ static OS *os_base = NULL; /* Base of overstrike chain */ osput(c, fd) char c; /* Print this character */ FILE *fd; /* On this file */ /* * Overstrike output routine */ { register OS *osp; /* Overstrike buffer pointer */ register char *bp; /* Buffer pointer */ register char *be; /* Buffer end */ switch (osflag) { case 0: case 4: /* * No overstrike */ switch (c) { case BACKSPACE: /* * Move printhead back (os_col < os_edge) */ if (os_col > 0) os_col--; break; case FORMFEED: case NEWLINE: /* * Terminate the line, output, and reinitialize */ bp = os_buf; os_buf[os_edge] = c; os_buf[os_edge + 1] = EOS; fputs(os_buf, fd); os_edge = os_col = 0; break; default: /* * Plant the character unless underline overwrites * a "real" datum. Then move the printhead * forward, updating the right edge as needed. */ if (os_col >= os_edge || c != '_' || os_buf[os_col] == BLANK) os_buf[os_col] = c; os_col++; if (os_col > os_edge) os_edge = os_col; break; } return; default: /* * Backspace overstriking */ putc(c, fd); return; case 1: case 5: /* * Newline overstriking */ switch (c) { case FORMFEED: case NEWLINE: /* * Newline, dump all (any) overstrike buffers, then * output a newline and initialize everything. */ for (osp = os_base; osp != NULL;) { bp = &osp->o_buf; putc(RETURN, fd); /* * Output the overstrike buffer, then point * osp to the next buffer. Finally free the * current buffer. */ bp[osp->o_edge] = EOS; fputs(bp, fd); bp = (char *) osp; osp = osp->o_next; free(bp); } /* * All overstrike buffers are empty, initialize for * the next line. */ os_base = NULL; putc(c, fd); os_edge = os_col = 0; break; case BACKSPACE: /* * Back up the printhead (leave high-water mark alone) */ if (os_col > 0) os_col--; break; default: /* * A printing character. If at right margin, just * output it and update the margins. */ if (os_col >= os_edge) { putc(c, fd); ++os_col; os_edge = os_col; } else { /* * Overstruck character. Locate a buffer * to remember it in. */ osp = os_base; while (osp != NULL && (osp->o_buf)[os_col] != BLANK) osp = osp->o_next; if (osp == NULL) { /* * A new buffer is needed */ osp = malloc(sizeof (OS)); if (osp == NULL) { error("Can't overstrike\n"); return; } osp->o_next = os_base; os_base = osp; osp->o_edge = 0; bp = &(osp->o_buf); be = &bp[MAXLINE]; while (bp < be) *bp++ = BLANK; } (osp->o_buf)[os_col] = c; os_col++; if (osp->o_edge < os_col) osp->o_edge = os_col; } break; } } } -h- ROFFUN.C Tue Jun 22 10:55:20 1982 _DRA0:ROFFUN.C;1 # /* * Simple stuff (somewhat unspecific to roff) */ #include #include "roff.h" /* * These should really be macros */ max(i, j) int i; int j; /* * return max of the args */ { return((i >= j) ? i : j); } min(i, j) int i; int j; /* * Return min of the args */ { return((i <= j) ? i : j); } even(i) int i; /* * Return TRUE if i is even */ { return((i & 1) == 0); } char * spanbl(buf) register char *buf; /* * Skip over blanks, return -> to first non-blank */ { register char *c; while ((c = *buf) == ' ' || c == TAB) *buf++; return(buf); } char * findbl(buf) register char *buf; /* * Skip to the first blank or tab, return -> to first blank, or to EOS. */ { register char *c; while ((c = *buf) != EOS && c != ' ' && c != TAB && c != NEWLINE) buf++; return(buf); } jcopy(to, from) register char *to; /* Output */ register char *from; /* Input */ /* * Copy from => to. Don't copy end of string. Used to put data into a field. * * NOTE: order of arg's reversed from ratfor. (matches standard library) */ { while (*from != EOS) *to++ = *from++; } substitute(out, in, what, repl, size) register char *out; /* Output */ register char *in; /* Input */ char what; /* Substitution character */ char *repl; /* Replacement string */ int size; /* Repl. string size. */ /* * Copy in => out. If byte "what" seen, replace with the repl. string. * Size is the maximum length of the repl. string. (To copy the whole * thing, use 32767 as repl. will terminate at the trailing null. * * Note: the order of arguments is somewhat different from roff in ratfor. */ { int count; register char *rp; while (*in != EOS) { if (*in == what) { rp = repl; for (count = size; *rp != EOS && --count >= 0;) *out++ = *rp++; } else { *out++ = *in; } in++; } *out = EOS; } gfield(out, in, newin, maximum, delim) char *out; /* Output buffer */ register char *in; /* Input argument */ char **newin; /* On return newin -> past delim in buf */ int maximum; /* Out field bytes to do */ char delim; /* Field delimiter */ /* * Get next tab or title field */ { register char *oend; register char *op; op = out; if (maximum > 0) { oend = &out[maximum]; if (*in == delim) in++; while (*in != delim && *in != NEWLINE && *in != EOS && op < oend) { *op++ = *in++; } } *op = EOS; /* * Skip to delimiter or end of string */ while (*in != EOS && *in != delim) in++; *newin = in; /* Stopped here */ return (op - out); /* Number of bytes done */ } getval(buf, argtype) char *buf; /* Input argument */ int *argtype; /* Return argument type */ /* * Evaluate an argument of the format "[a-z][ ]+[-+]?[0-9]*" * Return the argument value (zero if none) * Return, in argtype, the type parameter: * '+' '-' digit */ { register char *bp; /* Buffer pointer */ bp = spanbl(findbl(buf)); *argtype = *bp; if (*bp == '+' || *bp == '-') bp++; return(atoi(bp)); } -h- ROFINI.C Tue Jun 22 10:55:20 1982 _DRA0:ROFINI.C;1 # /* * Data initialization and allocation for roff */ #include #include "roff.h" /* * Define command current, default, minimum, maximum * * Current Default Minimum Maximum */ CMD lscmd { 1, 1, 1, HUGE }; CMD cecmd { 0, 1, 0, HUGE }; CMD ulcmd { 0, 1, 0, HUGE }; CMD bocmd { 0, 0, 0, HUGE }; CMD pgcmd { 0, COMPUTE, -HUGE, HUGE }; CMD spcmd { 1, 1, 0, HUGE }; CMD incmd { 0, 0, 0, COMPUTE }; CMD rmcmd { PAGEWIDTH, PAGEWIDTH, COMPUTE, HUGE }; CMD ticmd { 0, 0, 0, HUGE }; CMD plcmd { PAGELEN, PAGELEN, COMPUTE, HUGE }; CMD pocmd { 0, 0, 0, COMPUTE }; CMD m1cmd { 3, 3, 0, COMPUTE }; CMD m2cmd { 2, 2, 0, COMPUTE }; CMD m3cmd { 2, 2, 0, COMPUTE }; CMD m4cmd { 3, 3, 0, COMPUTE }; CMD bscmd { 0, 1, 0, HUGE }; /* * The following globals are used to define the output buffer * Note that "true" data includes outp and that outp may be < outbuf * This matches the Ratfor source (which does not imply approval). */ char outbuf[MAXOUT]; /* Current line being filled */ char *outp = &outbuf[-1]; /* Last real byte in outbuf[] */ char *prep = &outbuf[-1]; /* Last byte of previous word */ int outw = 0; /* Width of text in outbuf[] */ int outwds = 0; /* Number of words in outbuf[] */ /* * The following globals are used to define the title buffer */ char ttl[MAXOUT]; /* The title line */ char tbuf1[MAXOUT]; /* Work area */ char tbuf2[MAXOUT]; /* Work area */ /* * The following globals are used to define the input files */ FILEBUF files[MAXFILE]; FILEBUF *curfil = &files[0]; /* * Other globals */ int verbose = FALSE; /* -v flag */ int debug = FALSE; /* -d flag */ int fill = TRUE; /* Fill if TRUE */ int rjust = TRUE; /* Right-justify if TRUE */ int prflag = TRUE; /* Print if TRUE */ int cchar = '.'; /* Command character "." def. */ int newpage = 1; /* Next output page number */ int lineno = 0; /* Next line to be printed */ int bottom = PAGELEN - 3 - 3; /* Last live line on the page */ int frstpg = 0; /* First page to print */ int lstpag = 32767; /* Last page to print */ int stopx = FALSE; /* If set, pause between pages */ HEAD ehead = { 0, PAGEWIDTH, "" }; /* Even page heading */ HEAD ohead = { 0, PAGEWIDTH, "" }; /* Odd page heading */ HEAD efoot = { 0, PAGEWIDTH, "" }; /* Even page footing */ HEAD ofoot = { 0, PAGEWIDTH, "" }; /* Odd page footing */ /* * The following is defined in roffos.c * * int osflag = 0; -- do overstrikes if non-zero */ -h- ROFJUS.C Tue Jun 22 10:55:20 1982 _DRA0:ROFJUS.C;1 # /* * Roff justification */ #include #include "roff.h" text(in) register char *in; /* Input text line */ /* * Process text -- Note, modifies in[] */ { char wrdbuf[INSIZE]; char *newin; int bsflag; /* Blank supress flag */ int bsfirst; /* Blank supress first flag */ if (*in == ' ' || *in == NEWLINE) leadbl(in); /* Do leading blanks */ if (ulval > 0) { underl(in, wrdbuf, INSIZE); /* Underline */ ulval--; } if (boval > 0) { bold(in, wrdbuf, INSIZE); /* Boldface overprint */ boval--; } if (ceval > 0) { center(in); /* Center this line */ put(in); ceval--; } else if (*in == NEWLINE) put(in); /* Explicit blank line */ else if (fill == FALSE) put(in); /* Unfilled text */ else { bsfirst = TRUE; while (getwrd(wrdbuf, in, &newin) > 0) { in = newin; if (bsval > 0 && bsfirst) { bsflag = TRUE; bsfirst = FALSE; bsval--; } else bsflag = FALSE; putwrd(wrdbuf, bsflag); } } } static leadbl(buf) register char *buf; /* * Delete leading blanks, set tival */ { register char *bp; brk(); for (bp = buf; *bp == ' '; bp++); /* Find first non-blank */ if (*bp != NEWLINE && *bp != EOS) tival = bp - buf; /* * If there were leading blanks, move the line to the left. */ if (bp > buf) cpystr(buf, bp); } center(buf) char *buf; /* * Center a line by setting tival */ { tival = max((rmval + tival - width(buf)) / 2, 0); } underl(buf, work, size) char *buf; /* Work buffer */ char *work; /* Where to get/put it */ int size; /* Maximum size */ /* * Underline the buffer contents */ { register char *bp; register char *wp; register char c; char workend; bp = buf; wp = work; workend = &wp[size-2]; while ((c = *bp++) != EOS && c != NEWLINE && wp < workend) { if (c != ' ' && c != TAB && c != BACKSPACE) { *wp++ = '_'; *wp++ = BACKSPACE; } *wp++ = c; } *wp++ = NEWLINE; *wp = EOS; cpystr(buf, work); } bold(buf, work, size) char *buf; /* Work buffer */ char *work; /* Where to get/put it */ int size; /* Maximum size */ /* * Boldface the buffer contents */ { register char *bp; register char *wp; register char c; char workend; bp = buf; wp = work; workend = &wp[size-4]; while ((c = *bp++) != EOS && c != NEWLINE && wp < workend) { *wp++ = c; if (c != ' ' && c != TAB && c != BACKSPACE) { *wp++ = BACKSPACE; *wp++ = c; *wp++ = BACKSPACE; *wp++ = c; } } *wp++ = NEWLINE; *wp = EOS; cpystr(buf, work); } width(buf) register char *buf; /* * Compute the width of a character string */ { register int i; register char c; for (i = 0; (c = *buf++) != EOS;) { if (c == BACKSPACE) i--; else if (c != NEWLINE) i++; } return(i); } brk() /* * End the current filled line. */ { if (outp >= outbuf) { *outp++ = NEWLINE; *outp = EOS; put(outbuf); } outp = &outbuf[-1]; /* Last char on line */ outw = 0; /* Width of text in outbuf */ outwds = 0; /* Number of words in outbuf */ prep = &outbuf[-1]; /* last byte of previous word */ } static getwrd(out, in, newin) char *out; /* Where it goes */ register char *in; /* Where it comes from */ char **newin; /* *newin set to where we stopped */ { register char *op; register char *ip; /* * Skip over leading blanks, then count and copy non-blank char's */ op = out; ip = spanbl(in); while (*ip != EOS && *ip != ' ' && *ip != TAB && *ip != NEWLINE) *op++ = *ip++; /* * Count and copy trailing blanks until non-blank is seen */ do { while (*ip == ' ') *op++ = *ip++; /* * If trailing blanks are followed by a standard * punctuation mark, tack it on, too. */ for (;;) { switch (*ip) { case '.': case ',': case ':': case '}': case ']': case ')': case ';': case BACKSPACE: *op++ = *ip++; continue; /* to for(;;) */ } break; /* Exit for(;;) */ } } while (*ip == ' '); *newin = ip; /* * If the last character in out[] is blank, drop it. */ if (op[-1] == ' ') op--; *op = EOS; return(op - out); } putwrd(buf, bsflag) char *buf; /* Word to output */ int bsflag; /* Blank supress flag */ /* * Put a word in outbuf. Includes right-margin justification */ { register char *ip; register char *tp; int nb; /* Number of blanks betw. word */ int nextra; int last; int llval; int wwidth; int w; prep = outp; /* Set end of last word */ if (outp >= outbuf && bsflag) nb = 0; else nb = 1; /* * Calculate the input width and the number of char's we will * stuff in outbuf */ w = width(buf); last = strlen(buf) + (outp - outbuf) + nb; llval = rmval - tival; wwidth = outw + w + nb - 1; if (prep >= outbuf && (wwidth > llval || last > MAXOUT)) { /* * The new word won't fit on the current line */ last = last - (prep - outbuf) - 1; /* * If the word last put into the buffer should be * followed by the current word without blanks between, * copy them both back into the input text. */ if (nb == 0) { /* * Copy entire compressed word into buf */ tp = tbuf1; for (ip = prep + 1; ip < outp;) *tp++ = *ip++; cpystr(tp, buf); cpystr(buf, tbuf1); outwds--; } outp = prep; w = width(buf); nextra = llval - wwidth + w + 1; nb = 1; /* * If the last word in outbuf is the end of a sentence, * ask for another blank */ if (outp[-2] == '.' && outp[-1] == ' ') { outp--; nextra++; } if (rjust) { spread(outbuf, outp, nextra, outwds); if (nextra > 0 && outwds > 1) outp += nextra; } brk(); } cpystr(outp+nb, buf); outp = &outbuf[last]; *outp = ' '; outw += w + nb; outwds = outwds + nb; } static int sp_flag = 0; /* Spread left/right */ spread(buf, ebuf, nextra, words) char *buf; /* buffer to justify */ char *ebuf; /* End (last real) in buf */ int nextra; /* How far to right margin */ int words; /* How many words in buf */ /* * Spread out a line to justify it. */ { register char *ip; register char *op; register int nb; int nholes; /* * Can't spread one word, nor if it's already spread out */ if (nextra <= 0 || words <= 1) return; sp_flag = 1 - sp_flag; /* Flip direction */ nholes = words - 1; if (tival != inval && nholes > 1) nholes--; /* * This is really a bug fix -- redo putwrd someday */ if (*ebuf == ' ') ebuf--; ip = ebuf; /* ip -> last true char in line */ op = ip + nextra; /* op -> where it spreads to */ /* * Make sure there's room for the NEWLINE and EOS */ if (op > &outbuf[MAXOUT - 2]) op = &outbuf[MAXOUT - 2]; while (ip < op) { *op = *ip; /* * Check for a blank following a non-blank */ if (*ip == ' ' && ip[-1] != ' ') { if (sp_flag) nb = nextra / nholes; else nb = ((nextra - 1) / nholes) + 1; nextra -= nb; nholes--; while (--nb >= 0) *--op = ' '; } op--; ip--; } } -h- ROFOUT.C Tue Jun 22 10:55:20 1982 _DRA0:ROFOUT.C;1 # /* * Roff output routines */ #include #include "roff.h" put(buf) char *buf; /* * Put out the line with proper spacing and indenting */ { if (lineno == 0 || lineno > bottom) phead(); putout(offset + tival, buf); tival = inval; skip(min(lsval - 1, bottom - lineno)); lineno += lsval; if (lineno > bottom) pfoot(); } putout(line_offset, buf) register int line_offset; /* Left margin value */ register char *buf; /* What to output */ /* * Output the string with any necessary leading blanks. */ { if (prflag) { while (--line_offset >= 0) osput(' ', stdout); while (*buf) osput(*buf++, stdout); } } skip(nlines) register int nlines; /* Number of lines to skip */ /* * Skip blank lines */ { if (prflag) { while(--nlines >= 0) osput(NEWLINE, stdout); } } space(nlines) register int nlines; /* Number of lines to skip */ /* * Skip blank lines. Stop at the bottom of the page */ { brk(); if (lineno > bottom) return; if (lineno == 0) phead(); skip(min(nlines, bottom + 1 - lineno)); lineno += nlines; if (lineno > bottom) pfoot(); } pfoot() /* * Output at end of page */ { skip(m3val); putttl((even(curpage)) ? &efoot : &ofoot, curpage); if (prflag) osput(FORMFEED, stdout); } static int ph_first = TRUE; phead() /* * Output at top of page */ { curpage = newpage; /* * Should we print the current page? */ prflag = (curpage >= frstpg && curpage <= lstpag); if (prflag) { if (ph_first) { if (stopx && ftty(stdout)) { puts("Position paper, to continue"); } ph_first = FALSE; if (ftty(stdout) == FALSE) osput(FORMFEED, stdout); } if (stopx && ftty(stdout)) gets(tbuf1); } newpage++; skip(m1val - 1); lineno = max(m1val - 1, 0); putttl((even(curpage)) ? &ehead : &ohead, curpage); skip(m2val); lineno += max(m2val, 0); } static int pt_first = TRUE; static char pt_date[30]; static putttl(head, pageno) HEAD *head; int pageno; /* * Put out a heading or footing with optional page number. */ { register char *buf; register char *ep; int temp; int pnsize; int n; char delim; char *newbuf; char page_number[MAXCHARS]; extern char *ctime(); extern time(); int tvec[2]; if (!prflag || head->h_head[0] == EOS) return; if (pt_first) { time(&tvec); buf = ctime(&tvec); copy(pt_date, buf, 10); pt_date[10] = ','; cpystr(&pt_date[11], &buf[19]); pt_first = FALSE; } lineno++; itoa(pageno, page_number); pnsize = strlen(page_number); /* * Clear out the title */ ep = &ttl[head->h_right]; for (buf = ttl; buf < ep;) *buf++ = ' '; buf = &head->h_head[0]; delim = *buf; n = 0; do { temp = gfield(tbuf1, buf, &newbuf, head->h_right - head->h_left, delim); buf = newbuf; if (temp) { substitute(tbuf2, tbuf1, PAGENUM, page_number, pnsize); substitute(tbuf1, tbuf2, DATECHAR, pt_date, 24); justify(ttl, tbuf1, head->h_left, head->h_right, n); } n++; } while (*buf != EOS && *buf != NEWLINE && n < 3); ttl[head->h_right] = NEWLINE; ttl[head->h_right + 1] = EOS; putout(offset, ttl); } justify(out, in, left, right, how) char *out; /* Output buffer */ char *in; /* Input buffer */ int left; /* Left index */ int right; /* Right index */ int how; /* How to justify it */ /* * Justify a string in it's tab column. How = 0,1,2 for left/center/right */ { int n; n = width(in); switch (how) { case 0: jcopy(&out[left], in); /* Left */ break; case 1: jcopy(&out[max((right + left - n)/2, left)], in); break; case 2: jcopy(&out[right-n], in); /* Right */ break; } }