4 * consume options, initialization, main loop,
5 * input routines, escape function calling
16 char *Version = "March 11, 1994";
19 #define DWBVERSION "???"
22 char *DWBfontdir = FONTDIR;
23 char *DWBntermdir = NTERMDIR;
24 char *DWBalthyphens = ALTHYPHENS;
25 char *DWBhomedir = "";
27 dwbinit dwbpaths[] = {
29 &DWBntermdir, NULL, 0,
30 &DWBalthyphens, NULL, 0,
36 int TROFF = 1; /* assume we started in troff... */
42 static FILE *ifl[NSO]; /* open input file pointers */
43 char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
44 int cfline[NSO]; /* input line count stack */
45 char *progname; /* program name (troff or nroff) */
47 int trace = 0; /* tracing mode: default off */
51 main(int argc, char *argv[])
58 ifile = stdin; /* gcc */
61 buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
63 if ((p = strrchr(progname, '/')) == NULL)
67 DWBinit(progname, dwbpaths);
68 if (strcmp(p, "nroff") == 0)
71 alphabet = 128; /* unicode for plan 9 */
79 while (--argc > 0 && (++argv)[0][0] == '-')
82 case 'N': /* ought to be used first... */
86 fprintf(stderr, "troff/nroff version %s\n", Version);
88 case 'F': /* switch font tables from default */
89 if (argv[0][2] != '\0') {
90 strcpy(termtab, &argv[0][2]);
91 strcpy(fontdir, &argv[0][2]);
94 strcpy(termtab, argv[0]);
95 strcpy(fontdir, argv[0]);
104 npn = atoi(&argv[0][2]);
106 case 'u': /* set emboldening amount */
107 bdtab[3] = atoi(&argv[0][2]);
108 if (bdtab[3] < 0 || bdtab[3] > 50)
112 if (!(stop = atoi(&argv[0][2])))
116 sprintf(buf + strlen(buf), ".nr %c %s\n",
117 argv[0][2], &argv[0][3]);
118 /* not yet cpushback(buf);*/
119 /* dotnr(&argv[0][2], &argv[0][3]); */
123 ERROR "Too many macro packages: %s", argv[0] WARN;
126 strcpy(mfiles[nmfi], nextf);
127 strcat(mfiles[nmfi++], &argv[0][2]);
133 strcpy(devname, &argv[0][2]);
150 fprintf(stdout, "%croff: DWB %s\n",
151 TROFF ? 't' : 'n', DWBVERSION);
154 if (argv[0][2] != '\0')
155 trace = trace1 = argv[0][2];
156 break; /* for the sake of compatibility */
158 ERROR "unknown option %s", argv[0] WARN;
164 * cpushback maintains a LIFO, so push pack the -r arguments
165 * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
172 while(strncmp(p, ".nr", 3) != 0)
184 copyf = lgf = nb = nflush = nlflg = 0;
185 if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
194 if ((j = cbits(i)) == XPAR) {
197 while (cbits(i) != '\n')
203 if (j == cc || j == c2) {
207 while ((j = cbits(i = getch())) == ' ' || j == '\t')
230 for (i = NTRTAB; --i; )
241 numtabp[PID].val = getpid();
242 numtabp[HP].val = init = 0;
243 numtabp[NL].val = -1;
246 sprintf(buf, ".ds .T %s\n", devname);
248 sprintf(buf, ".ds .P %s\n", DWBhomedir);
250 numtabp[CD].val = -1; /* compensation */
252 frame = stk = (Stack *)setbrk(STACKSIZE);
255 for (i = 1; i < NEV; i++) /* propagate the environment */
256 envcopy(&env[i], &env[0]);
257 for (i = 0; i < NEV; i++) {
258 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
259 ERROR "not enough room for word buffers" WARN;
262 env[i]._word._size = WDSIZE;
263 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
264 ERROR "not enough room for line buffers" WARN;
267 env[i]._line._size = LNSIZE;
269 if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
270 ERROR "not enough room for line buffers" WARN;
284 ltime = localtime(&tt);
285 numtabp[YR].val = ltime->tm_year % 100;
287 numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
288 numtabp[DY].val = ltime->tm_mday;
289 numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
296 void errprint(void) /* error message printer */
298 int savecd = numtabp[CD].val;
303 fprintf(stderr, "%s: ", progname);
304 fputs(errbuf, stderr);
306 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
310 numtabp[CD].val = savecd;
314 int control(int a, int b)
317 extern Contab *contabp;
321 if (a == 0 || (j = findmn(a)) == -1)
323 if (contabp[j].f == 0) {
325 fprintf(stderr, "invoke macro %s\n", unpair(a));
327 for (k = dilev; k; k--)
328 if (d[k].curd == a) {
329 ERROR "diversion %s invokes itself during diversion",
337 return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
341 fprintf(stderr, "invoke request %s\n", unpair(a));
355 i = max(inumb(&trace), 0);
369 if ((i = getach()) == 0 || (j = getach()) == 0)
377 * table encodes some special characters, to speed up tests
378 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
381 char gchtab[NCHARS] = {
382 000,004,000,000,010,000,000,000, /* fc, ldr */
383 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
384 000,000,000,000,000,000,000,000,
385 000,001,000,001,000,000,000,000, /* FLSS, ESC */
386 000,000,000,000,000,000,000,000,
387 000,000,000,000,000,000,000,000,
388 000,000,000,000,000,000,000,000,
389 000,000,000,000,000,000,000,000,
390 000,000,000,000,000,000,000,000,
391 000,000,000,000,000,000,000,000,
392 000,000,000,000,000,000,000,000,
393 000,000,000,000,000,000,000,000,
394 000,000,000,000,000,000,001,000, /* f */
395 000,000,000,000,000,000,000,000,
396 000,000,000,000,000,000,000,000,
397 000,000,000,000,000,000,000,000,
400 int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
416 if (cbits(i) == '\n')
428 if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
434 numtabp[CD].val++; /* line number */
452 if (k == 'f' && lg && !lgf) {
456 if (k == fc || k == tabch || k == ldrch) {
457 if ((i = setfield(k)) == 0)
463 i = makem(-width(' ' | chbits));
470 k = cbits(j = getch0());
475 case 'n': /* number register */
478 case '$': /* argument indicator */
481 case '*': /* string indicator */
487 case '}': /* RIGHT */
490 case '"': /* comment */
491 while (cbits(i = getch0()) != '\n')
494 numtabp[CD].val++; /* line number */
498 /* experiment: put it here instead of copy mode */
499 case '(': /* special char name \(xx */
500 case 'C': /* \C'...' */
501 if ((i = setch(k)) == 0)
505 case ESC: /* double backslash */
508 case 'e': /* printable version of current eschar */
511 case '\n': /* concealed newline */
514 case ' ': /* unpaddable space */
517 case '\'': /* \(aa */
526 case '-': /* current font minus */
529 case '&': /* filler */
532 case 'c': /* to be continued */
535 case '!': /* transparent indicator */
541 case 'a': /* leader (SOH) */
542 /* old: *pbp++ = LEADER; goto g0; */
548 case 'g': /* return format of a number register */
549 setaf(); /* should this really be in copy mode??? */
554 setsfbits(i, sfbits(j));
563 case 'f': /* font indicator */
566 case 's': /* size indicator */
569 case 'v': /* vert mot */
570 numerr.type = numerr.escarg = 0; numerr.esc = k;
575 case 'h': /* horiz mot */
576 numerr.type = numerr.escarg = 0; numerr.esc = k;
580 case '|': /* narrow space */
583 return(makem((int)(EM)/6));
584 case '^': /* half narrow space */
587 return(makem((int)(EM)/12));
588 case 'w': /* width function */
591 case 'p': /* spread */
594 case 'N': /* absolute character number */
595 numerr.type = numerr.escarg = 0; numerr.esc = k;
596 if ((i = setabs()) == 0)
599 case 'H': /* character height */
600 numerr.type = numerr.escarg = 0; numerr.esc = k;
602 case 'S': /* slant */
603 numerr.type = numerr.escarg = 0; numerr.esc = k;
605 case 'z': /* zero with char */
607 case 'l': /* hor line */
608 numerr.type = numerr.escarg = 0; numerr.esc = k;
611 case 'L': /* vert line */
612 numerr.type = numerr.escarg = 0; numerr.esc = k;
615 case 'D': /* drawing function */
616 numerr.type = numerr.escarg = 0; numerr.esc = k;
619 case 'X': /* \X'...' for copy through */
622 case 'b': /* bracket */
625 case 'o': /* overstrike */
628 case 'k': /* mark hor place */
629 if ((k = findr(getsn())) != -1) {
630 numtabp[k].val = numtabp[HP].val;
633 case '0': /* number space */
634 return(makem(width('0' | chbits)));
635 case 'x': /* extra line space */
636 numerr.type = numerr.escarg = 0; numerr.esc = k;
640 case 'u': /* half em up */
641 case 'r': /* full em up */
642 case 'd': /* half em down */
650 void setxon(void) /* \X'...' for copy through */
657 if (ismot(c = getch()))
662 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
667 *i++ = XOFF | chbits;
673 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
697 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
699 ERROR "in getch0, nfo = %d", nfo WARN;
720 if (i >= 040) /* zapped: && i < 0177 */
724 if (cbits(i) == IMP && !raw)
726 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
732 if (copyf == 0 && sfbits(i) == 0)
734 if (cbits(i) == eschar && !raw)
741 Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */
747 for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
748 if ((c = getc(fp)) == EOF)
751 if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
755 if (n == 1) /* real ascii, presumably */
758 return p[-1]; /* illegal, but what else to do? */
762 return chadd(buf, MBchar, Install); /* add name even if haven't seen it */
766 void pushback(Tchar *b)
773 while (b > ob && pbp < &pbbuf[NC-3])
775 if (pbp >= &pbbuf[NC-3]) {
776 ERROR "pushback overflow" WARN;
781 void cpushback(char *b)
788 while (b > ob && pbp < &pbbuf[NC-3])
790 if (pbp >= &pbbuf[NC-3]) {
791 ERROR "cpushback overflow" WARN;
803 if (ifi > 0 && !nx) {
805 goto n0; /* popf error */
806 return(1); /* popf ok */
808 if (nx || nmfi < mflg) {
814 if ((nfo -= mflg) && !stdi) {
818 numtabp[CD].val = stdi = mflg = 0;
820 strcpy(cfname[ifi], "stdin");
828 if (p[0] == '-' && p[1] == 0) {
830 strcpy(cfname[ifi], "stdin");
831 } else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
832 ERROR "cannot open file %s", p WARN;
836 strcpy(cfname[ifi],p);
846 ERROR "popf went negative" WARN;
849 numtabp[CD].val = cfline[ifi]; /* restore line counter */
850 ip = ipl[ifi]; /* input pointer */
851 ifile = ifl[ifi]; /* input FILE * */
863 if (donef && frame == stk)
871 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
872 * (internal names), spaces and special cookies (below 040).
873 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
882 j = cbits(i = getch());
885 || (j <= 040 && j != 002 /*STX*/
889 && j != 007)) { /*BELL*/
906 strcpy(mfiles[nmfi], nextf);
921 for (k = 0; k < NS - 1; k++) {
939 if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
940 ERROR "can't open file %s", nextf WARN;
943 strcpy(cfname[ifi+1], nextf);
944 cfline[ifi] = numtabp[CD].val; /*hold line counter*/
956 void caself(void) /* set line number and file */
964 cfline[ifi] = numtabp[CD].val = n - 1;
966 if (getname()) { /* eats '\n' ? */
967 strcpy(cfname[ifi], nextf);
973 void cpout(FILE *fin, char *token)
978 if (token) { /* BUG: There should be no NULL bytes in input */
980 while ((fgets(buf, sizeof buf, fin)) != NULL) {
982 numtabp[CD].val++; /* line number */
983 if (strcmp(token, buf) == 0)
986 newl = strchr(buf, '\n');
990 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
991 fwrite(buf, n, 1, ptid);
997 { /* copy file without change */
1000 extern int hpos, esc, po;
1002 /* this may not make much sense in nroff... */
1006 if (!skip() && getname()) {
1007 if (strncmp("<<", nextf, 2) != 0) {
1008 if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
1009 ERROR "can't open file %s", nextf WARN;
1012 eof = (char *) NULL;
1013 } else { /* current file */
1014 if (pbp > lastpbp || ip) {
1015 ERROR "casecf: not reading from file" WARN;
1020 ERROR "casecf: missing end of input token" WARN;
1031 ERROR "casecf: no argument" WARN;
1037 /* make it into a clean state, be sure that everything is out */
1041 ptesc(); /* to left margin */
1053 void getline(char *s, int n) /* get rest of input line into s */
1060 for (i = 0; i < n-1; i++)
1061 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
1068 void casesy(void) /* call system */
1072 getline(sybuf, NTM);
1096 n = 10 * n + *a++ - '0';
1097 while (isdigit(*a));
1101 *pnp++ = neg ? -n : n;
1103 if (pnp >= &pnlist[NPN-2]) {
1104 ERROR "too many page numbers" WARN;
1113 if (*pnp != -INT_MAX)
1127 if ((long) i < 0 || cbits(j = getch0()) == RPT)
1129 while (i > 0 && pbp < &pbbuf[NC-3]) {