aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/troff/n1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/troff/n1.c')
-rw-r--r--src/cmd/troff/n1.c1136
1 files changed, 1136 insertions, 0 deletions
diff --git a/src/cmd/troff/n1.c b/src/cmd/troff/n1.c
new file mode 100644
index 00000000..d0949fe2
--- /dev/null
+++ b/src/cmd/troff/n1.c
@@ -0,0 +1,1136 @@
+/*
+ * n1.c
+ *
+ * consume options, initialization, main loop,
+ * input routines, escape function calling
+ */
+
+#include "tdef.h"
+#include "fns.h"
+#include "ext.h"
+#include "dwbinit.h"
+
+#undef MB_CUR_MAX
+#define MB_CUR_MAX 3
+
+#include <setjmp.h>
+#include <time.h>
+
+char *Version = "March 11, 1994";
+
+#ifndef DWBVERSION
+#define DWBVERSION "???"
+#endif
+
+char *DWBfontdir = FONTDIR;
+char *DWBntermdir = NTERMDIR;
+char *DWBalthyphens = ALTHYPHENS;
+char *DWBhomedir = "";
+
+dwbinit dwbpaths[] = {
+ &DWBfontdir, NULL, 0,
+ &DWBntermdir, NULL, 0,
+ &DWBalthyphens, NULL, 0,
+ &DWBhomedir, NULL, 0,
+ NULL, nextf, NS,
+ NULL, NULL, 0
+};
+
+int TROFF = 1; /* assume we started in troff... */
+
+jmp_buf sjbuf;
+Offset ipl[NSO];
+
+static FILE *ifile;
+static FILE *ifl[NSO]; /* open input file pointers */
+char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
+int cfline[NSO]; /* input line count stack */
+char *progname; /* program name (troff or nroff) */
+
+int trace = 0; /* tracing mode: default off */
+int trace1 = 0;
+
+main(int argc, char *argv[])
+{
+ char *p;
+ int j;
+ Tchar i;
+ char buf[100];
+
+ ifile = stdin;
+ ptid = stdout;
+
+ buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
+ progname = argv[0];
+ if ((p = strrchr(progname, '/')) == NULL)
+ p = progname;
+ else
+ p++;
+ DWBinit(progname, dwbpaths);
+ if (strcmp(p, "nroff") == 0)
+ TROFF = 0;
+#ifdef UNICODE
+ alphabet = 128; /* unicode for plan 9 */
+#endif /*UNICODE*/
+ mnspace();
+ nnspace();
+ mrehash();
+ nrehash();
+ numtabp[NL].val = -1;
+
+ while (--argc > 0 && (++argv)[0][0] == '-')
+ switch (argv[0][1]) {
+
+ case 'N': /* ought to be used first... */
+ TROFF = 0;
+ break;
+ case 'd':
+ fprintf(stderr, "troff/nroff version %s\n", Version);
+ break;
+ case 'F': /* switch font tables from default */
+ if (argv[0][2] != '\0') {
+ strcpy(termtab, &argv[0][2]);
+ strcpy(fontdir, &argv[0][2]);
+ } else {
+ argv++; argc--;
+ strcpy(termtab, argv[0]);
+ strcpy(fontdir, argv[0]);
+ }
+ break;
+ case 0:
+ goto start;
+ case 'i':
+ stdi++;
+ break;
+ case 'n':
+ npn = atoi(&argv[0][2]);
+ break;
+ case 'u': /* set emboldening amount */
+ bdtab[3] = atoi(&argv[0][2]);
+ if (bdtab[3] < 0 || bdtab[3] > 50)
+ bdtab[3] = 0;
+ break;
+ case 's':
+ if (!(stop = atoi(&argv[0][2])))
+ stop++;
+ break;
+ case 'r':
+ sprintf(buf + strlen(buf), ".nr %c %s\n",
+ argv[0][2], &argv[0][3]);
+ /* not yet cpushback(buf);*/
+ /* dotnr(&argv[0][2], &argv[0][3]); */
+ break;
+ case 'm':
+ if (mflg++ >= NMF) {
+ ERROR "Too many macro packages: %s", argv[0] WARN;
+ break;
+ }
+ strcpy(mfiles[nmfi], nextf);
+ strcat(mfiles[nmfi++], &argv[0][2]);
+ break;
+ case 'o':
+ getpn(&argv[0][2]);
+ break;
+ case 'T':
+ strcpy(devname, &argv[0][2]);
+ dotT++;
+ break;
+ case 'a':
+ ascii = 1;
+ break;
+ case 'h':
+ hflg++;
+ break;
+ case 'e':
+ eqflg++;
+ break;
+ case 'q':
+ quiet++;
+ save_tty();
+ break;
+ case 'V':
+ fprintf(stdout, "%croff: DWB %s\n",
+ TROFF ? 't' : 'n', DWBVERSION);
+ exit(0);
+ case 't':
+ if (argv[0][2] != '\0')
+ trace = trace1 = argv[0][2];
+ break; /* for the sake of compatibility */
+ default:
+ ERROR "unknown option %s", argv[0] WARN;
+ done(02);
+ }
+
+start:
+ /*
+ * cpushback maintains a LIFO, so push pack the -r arguments
+ * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
+ */
+ if (buf[0]) {
+ char *p = buf;
+ while(*p++)
+ ;
+ while(p > buf) {
+ while(strncmp(p, ".nr", 3) != 0)
+ p--;
+ cpushback(p);
+ *p-- = '\0';
+ }
+ }
+ argp = argv;
+ rargc = argc;
+ nmfi = 0;
+ init2();
+ setjmp(sjbuf);
+loop:
+ copyf = lgf = nb = nflush = nlflg = 0;
+ if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
+ nflush++;
+ trap = 0;
+ eject((Stack *)0);
+ goto loop;
+ }
+ i = getch();
+ if (pendt)
+ goto Lt;
+ if ((j = cbits(i)) == XPAR) {
+ copyf++;
+ tflg++;
+ while (cbits(i) != '\n')
+ pchar(i = getch());
+ tflg = 0;
+ copyf--;
+ goto loop;
+ }
+ if (j == cc || j == c2) {
+ if (j == c2)
+ nb++;
+ copyf++;
+ while ((j = cbits(i = getch())) == ' ' || j == '\t')
+ ;
+ ch = i;
+ copyf--;
+ control(getrq(), 1);
+ flushi();
+ goto loop;
+ }
+Lt:
+ ch = i;
+ text();
+ if (nlflg)
+ numtabp[HP].val = 0;
+ goto loop;
+}
+
+
+
+void init2(void)
+{
+ int i;
+ char buf[100];
+
+ for (i = NTRTAB; --i; )
+ trtab[i] = i;
+ trtab[UNPAD] = ' ';
+ iflg = 0;
+ obufp = obuf;
+ if (TROFF)
+ t_ptinit();
+ else
+ n_ptinit();
+ mchbits();
+ cvtime();
+ numtabp[PID].val = getpid();
+ numtabp[HP].val = init = 0;
+ numtabp[NL].val = -1;
+ nfo = 0;
+ copyf = raw = 0;
+ sprintf(buf, ".ds .T %s\n", devname);
+ cpushback(buf);
+ sprintf(buf, ".ds .P %s\n", DWBhomedir);
+ cpushback(buf);
+ numtabp[CD].val = -1; /* compensation */
+ nx = mflg;
+ frame = stk = (Stack *)setbrk(STACKSIZE);
+ dip = &d[0];
+ nxf = frame + 1;
+ for (i = 1; i < NEV; i++) /* propagate the environment */
+ envcopy(&env[i], &env[0]);
+ for (i = 0; i < NEV; i++) {
+ if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for word buffers" WARN;
+ done2(1);
+ }
+ env[i]._word._size = WDSIZE;
+ if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for line buffers" WARN;
+ done2(1);
+ }
+ env[i]._line._size = LNSIZE;
+ }
+ if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
+ ERROR "not enough room for line buffers" WARN;
+ done2(1);
+ }
+ olinep = oline;
+ olnsize = OLNSIZE;
+ blockinit();
+}
+
+void cvtime(void)
+{
+ long tt;
+ struct tm *ltime;
+
+ time(&tt);
+ ltime = localtime(&tt);
+ numtabp[YR].val = ltime->tm_year % 100;
+ numtabp[YR].fmt = 2;
+ numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
+ numtabp[DY].val = ltime->tm_mday;
+ numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
+}
+
+
+
+char errbuf[200];
+
+void errprint(void) /* error message printer */
+{
+ int savecd = numtabp[CD].val;
+
+ if (!nlflg)
+ numtabp[CD].val++;
+
+ fprintf(stderr, "%s: ", progname);
+ fputs(errbuf, stderr);
+ if (cfname[ifi][0])
+ fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
+ fputs("\n", stderr);
+ if (cfname[ifi][0])
+ stackdump();
+ numtabp[CD].val = savecd;
+}
+
+
+int control(int a, int b)
+{
+ int j, k;
+ extern Contab *contabp;
+
+ numerr.type = RQERR;
+ numerr.req = a;
+ if (a == 0 || (j = findmn(a)) == -1)
+ return(0);
+ if (contabp[j].f == 0) {
+ if (trace & TRMAC)
+ fprintf(stderr, "invoke macro %s\n", unpair(a));
+ if (dip != d)
+ for (k = dilev; k; k--)
+ if (d[k].curd == a) {
+ ERROR "diversion %s invokes itself during diversion",
+ unpair(a) WARN;
+ edone(0100);
+ }
+ nxf->nargs = 0;
+ if (b)
+ collect();
+ flushi();
+ return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
+ }
+ if (b) {
+ if (trace & TRREQ)
+ fprintf(stderr, "invoke request %s\n", unpair(a));
+ (*contabp[j].f)();
+ }
+ return(0);
+}
+
+void casept(void)
+{
+ int i;
+
+ noscale++;
+ if (skip())
+ i = trace1;
+ else {
+ i = max(inumb(&trace), 0);
+ if (nonumb)
+ i = trace1;
+ }
+ trace1 = trace;
+ trace = i;
+ noscale = 0;
+}
+
+
+int getrq(void)
+{
+ int i, j;
+
+ if ((i = getach()) == 0 || (j = getach()) == 0)
+ goto rtn;
+ i = PAIR(i, j);
+rtn:
+ return(i);
+}
+
+/*
+ * table encodes some special characters, to speed up tests
+ * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
+ */
+
+char gchtab[NCHARS] = {
+ 000,004,000,000,010,000,000,000, /* fc, ldr */
+ 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
+ 000,000,000,000,000,000,000,000,
+ 000,001,000,001,000,000,000,000, /* FLSS, ESC */
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,001,000, /* f */
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+ 000,000,000,000,000,000,000,000,
+};
+
+int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
+{
+ if (ismot(c))
+ return MOTCH;
+ else
+ return c & 0xFFFF;
+}
+
+Tchar getch(void)
+{
+ int k;
+ Tchar i, j;
+
+g0:
+ if (ch) {
+ i = ch;
+ if (cbits(i) == '\n')
+ nlflg++;
+ ch = 0;
+ return(i);
+ }
+
+ if (nlflg)
+ return('\n');
+ i = getch0();
+ if (ismot(i))
+ return(i);
+ k = cbits(i);
+ if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
+ return(i);
+ if (k != ESC) {
+ if (k == '\n') {
+ nlflg++;
+ if (ip == 0)
+ numtabp[CD].val++; /* line number */
+ return(k);
+ }
+ if (k == FLSS) {
+ copyf++;
+ raw++;
+ i = getch0();
+ if (!fi)
+ flss = i;
+ copyf--;
+ raw--;
+ goto g0;
+ }
+ if (k == RPT) {
+ setrpt();
+ goto g0;
+ }
+ if (!copyf) {
+ if (k == 'f' && lg && !lgf) {
+ i = getlg(i);
+ return(i);
+ }
+ if (k == fc || k == tabch || k == ldrch) {
+ if ((i = setfield(k)) == 0)
+ goto g0;
+ else
+ return(i);
+ }
+ if (k == '\b') {
+ i = makem(-width(' ' | chbits));
+ return(i);
+ }
+ }
+ return(i);
+ }
+
+ k = cbits(j = getch0());
+ if (ismot(j))
+ return(j);
+
+ switch (k) {
+ case 'n': /* number register */
+ setn();
+ goto g0;
+ case '$': /* argument indicator */
+ seta();
+ goto g0;
+ case '*': /* string indicator */
+ setstr();
+ goto g0;
+ case '{': /* LEFT */
+ i = LEFT;
+ goto gx;
+ case '}': /* RIGHT */
+ i = RIGHT;
+ goto gx;
+ case '"': /* comment */
+ while (cbits(i = getch0()) != '\n')
+ ;
+ if (ip == 0)
+ numtabp[CD].val++; /* line number */
+ nlflg++;
+ return(i);
+
+/* experiment: put it here instead of copy mode */
+ case '(': /* special char name \(xx */
+ case 'C': /* \C'...' */
+ if ((i = setch(k)) == 0)
+ goto g0;
+ goto gx;
+
+ case ESC: /* double backslash */
+ i = eschar;
+ goto gx;
+ case 'e': /* printable version of current eschar */
+ i = PRESC;
+ goto gx;
+ case '\n': /* concealed newline */
+ numtabp[CD].val++;
+ goto g0;
+ case ' ': /* unpaddable space */
+ i = UNPAD;
+ goto gx;
+ case '\'': /* \(aa */
+ i = ACUTE;
+ goto gx;
+ case '`': /* \(ga */
+ i = GRAVE;
+ goto gx;
+ case '_': /* \(ul */
+ i = UNDERLINE;
+ goto gx;
+ case '-': /* current font minus */
+ i = MINUS;
+ goto gx;
+ case '&': /* filler */
+ i = FILLER;
+ goto gx;
+ case 'c': /* to be continued */
+ i = CONT;
+ goto gx;
+ case '!': /* transparent indicator */
+ i = XPAR;
+ goto gx;
+ case 't': /* tab */
+ i = '\t';
+ return(i);
+ case 'a': /* leader (SOH) */
+/* old: *pbp++ = LEADER; goto g0; */
+ i = LEADER;
+ return i;
+ case '%': /* ohc */
+ i = OHC;
+ return(i);
+ case 'g': /* return format of a number register */
+ setaf(); /* should this really be in copy mode??? */
+ goto g0;
+ case '.': /* . */
+ i = '.';
+gx:
+ setsfbits(i, sfbits(j));
+ return(i);
+ }
+ if (copyf) {
+ *pbp++ = j;
+ return(eschar);
+ }
+ switch (k) {
+
+ case 'f': /* font indicator */
+ setfont(0);
+ goto g0;
+ case 's': /* size indicator */
+ setps();
+ goto g0;
+ case 'v': /* vert mot */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = vmot()) {
+ return(i);
+ }
+ goto g0;
+ case 'h': /* horiz mot */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = hmot())
+ return(i);
+ goto g0;
+ case '|': /* narrow space */
+ if (NROFF)
+ goto g0;
+ return(makem((int)(EM)/6));
+ case '^': /* half narrow space */
+ if (NROFF)
+ goto g0;
+ return(makem((int)(EM)/12));
+ case 'w': /* width function */
+ setwd();
+ goto g0;
+ case 'p': /* spread */
+ spread++;
+ goto g0;
+ case 'N': /* absolute character number */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if ((i = setabs()) == 0)
+ goto g0;
+ return i;
+ case 'H': /* character height */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ return(setht());
+ case 'S': /* slant */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ return(setslant());
+ case 'z': /* zero with char */
+ return(setz());
+ case 'l': /* hor line */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setline();
+ goto g0;
+ case 'L': /* vert line */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setvline();
+ goto g0;
+ case 'D': /* drawing function */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ setdraw();
+ goto g0;
+ case 'X': /* \X'...' for copy through */
+ setxon();
+ goto g0;
+ case 'b': /* bracket */
+ setbra();
+ goto g0;
+ case 'o': /* overstrike */
+ setov();
+ goto g0;
+ case 'k': /* mark hor place */
+ if ((k = findr(getsn())) != -1) {
+ numtabp[k].val = numtabp[HP].val;
+ }
+ goto g0;
+ case '0': /* number space */
+ return(makem(width('0' | chbits)));
+ case 'x': /* extra line space */
+ numerr.type = numerr.escarg = 0; numerr.esc = k;
+ if (i = xlss())
+ return(i);
+ goto g0;
+ case 'u': /* half em up */
+ case 'r': /* full em up */
+ case 'd': /* half em down */
+ return(sethl(k));
+ default:
+ return(j);
+ }
+ /* NOTREACHED */
+}
+
+void setxon(void) /* \X'...' for copy through */
+{
+ Tchar xbuf[NC];
+ Tchar *i;
+ Tchar c;
+ int delim, k;
+
+ if (ismot(c = getch()))
+ return;
+ delim = cbits(c);
+ i = xbuf;
+ *i++ = XON | chbits;
+ while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
+ if (k == ' ')
+ setcbits(c, WORDSP);
+ *i++ = c | ZBIT;
+ }
+ *i++ = XOFF | chbits;
+ *i = 0;
+ pushback(xbuf);
+}
+
+
+char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
+
+Tchar getch0(void)
+{
+ int j;
+ Tchar i;
+
+again:
+ if (pbp > lastpbp)
+ i = *--pbp;
+ else if (ip) {
+ /* i = rbf(); */
+ i = rbf0(ip);
+ if (i == 0)
+ i = rbf();
+ else {
+ ++ip;
+ if (pastend(ip)) {
+ --ip;
+ rbf();
+ }
+ }
+ } else {
+ if (donef || ndone)
+ done(0);
+ if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
+ if (nfo < 0)
+ ERROR "in getch0, nfo = %d", nfo WARN;
+ if (nfo == 0) {
+g0:
+ if (nextfile()) {
+ if (ip)
+ goto again;
+ }
+ }
+ nx = 0;
+#ifdef UNICODE
+ if (MB_CUR_MAX > 1)
+ i = get1ch(ifile);
+ else
+#endif /*UNICODE*/
+ i = getc(ifile);
+ if (i == EOF)
+ goto g0;
+ if (ip)
+ goto again;
+ }
+g2:
+ if (i >= 040) /* zapped: && i < 0177 */
+ goto g4;
+ i = ifilt[i];
+ }
+ if (cbits(i) == IMP && !raw)
+ goto again;
+ if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
+ goto again;
+ }
+g4:
+ if (ismot(i))
+ return i;
+ if (copyf == 0 && sfbits(i) == 0)
+ i |= chbits;
+ if (cbits(i) == eschar && !raw)
+ setcbits(i, ESC);
+ return(i);
+}
+
+
+#ifdef UNICODE
+Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */
+{
+ wchar_t wc;
+ char buf[100], *p;
+ int i, n, c;
+
+ for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
+ if ((c = getc(fp)) == EOF)
+ return c;
+ *p++ = c;
+ if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
+ break;
+ }
+ if (n == 1) /* real ascii, presumably */
+ return wc;
+ if (n == 0)
+ return p[-1]; /* illegal, but what else to do? */
+ if (c == EOF)
+ return EOF;
+ *p = 0;
+ return chadd(buf, MBchar, Install); /* add name even if haven't seen it */
+}
+#endif /*UNICODE*/
+
+void pushback(Tchar *b)
+{
+ Tchar *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob && pbp < &pbbuf[NC-3])
+ *pbp++ = *--b;
+ if (pbp >= &pbbuf[NC-3]) {
+ ERROR "pushback overflow" WARN;
+ done(2);
+ }
+}
+
+void cpushback(char *b)
+{
+ char *ob = b;
+
+ while (*b++)
+ ;
+ b--;
+ while (b > ob && pbp < &pbbuf[NC-3])
+ *pbp++ = *--b;
+ if (pbp >= &pbbuf[NC-3]) {
+ ERROR "cpushback overflow" WARN;
+ done(2);
+ }
+}
+
+int nextfile(void)
+{
+ char *p;
+
+n0:
+ if (ifile != stdin)
+ fclose(ifile);
+ if (ifi > 0 && !nx) {
+ if (popf())
+ goto n0; /* popf error */
+ return(1); /* popf ok */
+ }
+ if (nx || nmfi < mflg) {
+ p = mfiles[nmfi++];
+ if (*p != 0)
+ goto n1;
+ }
+ if (rargc-- <= 0) {
+ if ((nfo -= mflg) && !stdi) {
+ done(0);
+}
+ nfo++;
+ numtabp[CD].val = stdi = mflg = 0;
+ ifile = stdin;
+ strcpy(cfname[ifi], "stdin");
+ return(0);
+ }
+ p = (argp++)[0];
+ if (rargc >= 0)
+ cfname[ifi][0] = 0;
+n1:
+ numtabp[CD].val = 0;
+ if (p[0] == '-' && p[1] == 0) {
+ ifile = stdin;
+ strcpy(cfname[ifi], "stdin");
+ } else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
+ ERROR "cannot open file %s", p WARN;
+ nfo -= mflg;
+ done(02);
+ } else
+ strcpy(cfname[ifi],p);
+ nfo++;
+ return(0);
+}
+
+
+popf(void)
+{
+ --ifi;
+ if (ifi < 0) {
+ ERROR "popf went negative" WARN;
+ return 1;
+ }
+ numtabp[CD].val = cfline[ifi]; /* restore line counter */
+ ip = ipl[ifi]; /* input pointer */
+ ifile = ifl[ifi]; /* input FILE * */
+ return(0);
+}
+
+
+void flushi(void)
+{
+ if (nflush)
+ return;
+ ch = 0;
+ copyf++;
+ while (!nlflg) {
+ if (donef && frame == stk)
+ break;
+ getch();
+ }
+ copyf--;
+}
+
+/*
+ * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
+ * (internal names), spaces and special cookies (below 040).
+ * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
+ */
+getach(void)
+{
+ Tchar i;
+ int j;
+
+ lgf++;
+ j = cbits(i = getch());
+ if (ismot(i)
+ || j > SHORTMASK
+ || (j <= 040 && j != 002 /*STX*/
+ && j != 003 /*ETX*/
+ && j != 005 /*ENQ*/
+ && j != 006 /*ACK*/
+ && j != 007)) { /*BELL*/
+ ch = i;
+ j = 0;
+ }
+ lgf--;
+ return j;
+}
+
+
+void casenx(void)
+{
+ lgf++;
+ skip();
+ getname();
+ nx++;
+ if (nmfi > 0)
+ nmfi--;
+ strcpy(mfiles[nmfi], nextf);
+ nextfile();
+ nlflg++;
+ ip = 0;
+ pendt = 0;
+ frame = stk;
+ nxf = frame + 1;
+}
+
+
+getname(void)
+{
+ int j, k;
+ Tchar i;
+
+ lgf++;
+ for (k = 0; k < NS - 1; k++) {
+ j = getach();
+ if (!j)
+ break;
+ nextf[k] = j;
+ }
+ nextf[k] = 0;
+ lgf--;
+ return(nextf[0]);
+}
+
+
+void caseso(void)
+{
+ FILE *fp;
+ char *p, *q;
+
+ lgf++;
+ nextf[0] = 0;
+ if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
+ ERROR "can't open file %s", nextf WARN;
+ done(02);
+ }
+ strcpy(cfname[ifi+1], nextf);
+ cfline[ifi] = numtabp[CD].val; /*hold line counter*/
+ numtabp[CD].val = 0;
+ flushi();
+ ifl[ifi] = ifile;
+ ifile = fp;
+ ipl[ifi] = ip;
+ ip = 0;
+ nx++;
+ nflush++;
+ ifi++;
+}
+
+void caself(void) /* set line number and file */
+{
+ int n;
+
+ if (skip())
+ return;
+ n = atoi0();
+ if (!nonumb)
+ cfline[ifi] = numtabp[CD].val = n - 1;
+ if (!skip())
+ if (getname()) { /* eats '\n' ? */
+ strcpy(cfname[ifi], nextf);
+ if (!nonumb)
+ numtabp[CD].val--;
+ }
+}
+
+void cpout(FILE *fin, char *token)
+{
+ int n;
+ char buf[1024];
+
+ if (token) { /* BUG: There should be no NULL bytes in input */
+ char *newl = buf;
+ while ((fgets(buf, sizeof buf, fin)) != NULL) {
+ if (newl) {
+ numtabp[CD].val++; /* line number */
+ if (strcmp(token, buf) == 0)
+ return;
+ }
+ newl = strchr(buf, '\n');
+ fputs(buf, ptid);
+ }
+ } else {
+ while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
+ fwrite(buf, n, 1, ptid);
+ fclose(fin);
+ }
+}
+
+void casecf(void)
+{ /* copy file without change */
+ FILE *fd;
+ char *eof, *p;
+ extern int hpos, esc, po;
+
+ /* this may not make much sense in nroff... */
+
+ lgf++;
+ nextf[0] = 0;
+ if (!skip() && getname()) {
+ if (strncmp("<<", nextf, 2) != 0) {
+ if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
+ ERROR "can't open file %s", nextf WARN;
+ done(02);
+ }
+ eof = (char *) NULL;
+ } else { /* current file */
+ if (pbp > lastpbp || ip) {
+ ERROR "casecf: not reading from file" WARN;
+ done(02);
+ }
+ eof = &nextf[2];
+ if (!*eof) {
+ ERROR "casecf: missing end of input token" WARN;
+ done(02);
+ }
+ p = eof;
+ while(*++p)
+ ;
+ *p++ = '\n';
+ *p = 0;
+ fd = ifile;
+ }
+ } else {
+ ERROR "casecf: no argument" WARN;
+ lgf--;
+ return;
+ }
+ lgf--;
+
+ /* make it into a clean state, be sure that everything is out */
+ tbreak();
+ hpos = po;
+ esc = 0;
+ ptesc(); /* to left margin */
+ esc = un;
+ ptesc();
+ ptlead();
+ ptps();
+ ptfont();
+ flusho();
+ cpout(fd, eof);
+ ptps();
+ ptfont();
+}
+
+void getline(char *s, int n) /* get rest of input line into s */
+{
+ int i;
+
+ lgf++;
+ copyf++;
+ skip();
+ for (i = 0; i < n-1; i++)
+ if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
+ break;
+ s[i] = 0;
+ copyf--;
+ lgf--;
+}
+
+void casesy(void) /* call system */
+{
+ char sybuf[NTM];
+
+ getline(sybuf, NTM);
+ system(sybuf);
+}
+
+
+void getpn(char *a)
+{
+ int n, neg;
+
+ if (*a == 0)
+ return;
+ neg = 0;
+ for ( ; *a; a++)
+ switch (*a) {
+ case '+':
+ case ',':
+ continue;
+ case '-':
+ neg = 1;
+ continue;
+ default:
+ n = 0;
+ if (isdigit(*a)) {
+ do
+ n = 10 * n + *a++ - '0';
+ while (isdigit(*a));
+ a--;
+ } else
+ n = 9999;
+ *pnp++ = neg ? -n : n;
+ neg = 0;
+ if (pnp >= &pnlist[NPN-2]) {
+ ERROR "too many page numbers" WARN;
+ done3(-3);
+ }
+ }
+ if (neg)
+ *pnp++ = -9999;
+ *pnp = -INT_MAX;
+ print = 0;
+ pnp = pnlist;
+ if (*pnp != -INT_MAX)
+ chkpn();
+}
+
+
+void setrpt(void)
+{
+ Tchar i, j;
+
+ copyf++;
+ raw++;
+ i = getch0();
+ copyf--;
+ raw--;
+ if ((long) i < 0 || cbits(j = getch0()) == RPT)
+ return;
+ while (i > 0 && pbp < &pbbuf[NC-3]) {
+ i--;
+ *pbp++ = j;
+ }
+}