4
* consume options, initialization, main loop,
5
* input routines, escape function calling
17
char *Version = "March 11, 1994";
20
#define DWBVERSION "???"
23
char *DWBfontdir = FONTDIR;
24
char *DWBntermdir = NTERMDIR;
25
char *DWBalthyphens = ALTHYPHENS;
26
char *DWBhomedir = "";
28
dwbinit dwbpaths[] = {
30
&DWBntermdir, NULL, 0,
31
&DWBalthyphens, NULL, 0,
37
int TROFF = 1; /* assume we started in troff... */
43
static FILE *ifl[NSO]; /* open input file pointers */
44
char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
45
int cfline[NSO]; /* input line count stack */
46
char *progname; /* program name (troff or nroff) */
48
int trace = 0; /* tracing mode: default off */
52
main(int argc, char *argv[])
59
ifile = stdin; /* gcc */
62
buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
64
if ((p = strrchr(progname, '/')) == NULL)
68
DWBinit(progname, dwbpaths);
69
if (strcmp(p, "nroff") == 0)
72
alphabet = 128; /* unicode for plan 9 */
80
while (--argc > 0 && (++argv)[0][0] == '-')
83
case 'N': /* ought to be used first... */
87
fprintf(stderr, "troff/nroff version %s\n", Version);
89
case 'F': /* switch font tables from default */
90
if (argv[0][2] != '\0') {
91
strcpy(termtab, &argv[0][2]);
92
strcpy(fontdir, &argv[0][2]);
95
strcpy(termtab, argv[0]);
96
strcpy(fontdir, argv[0]);
105
npn = atoi(&argv[0][2]);
107
case 'u': /* set emboldening amount */
108
bdtab[3] = atoi(&argv[0][2]);
109
if (bdtab[3] < 0 || bdtab[3] > 50)
113
if (!(stop = atoi(&argv[0][2])))
117
sprintf(buf + strlen(buf), ".nr %c %s\n",
118
argv[0][2], &argv[0][3]);
119
/* not yet cpushback(buf);*/
120
/* dotnr(&argv[0][2], &argv[0][3]); */
124
ERROR "Too many macro packages: %s", argv[0] WARN;
127
strcpy(mfiles[nmfi], nextf);
128
strcat(mfiles[nmfi++], &argv[0][2]);
134
strcpy(devname, &argv[0][2]);
151
fprintf(stdout, "%croff: DWB %s\n",
152
TROFF ? 't' : 'n', DWBVERSION);
155
if (argv[0][2] != '\0')
156
trace = trace1 = argv[0][2];
157
break; /* for the sake of compatibility */
159
ERROR "unknown option %s", argv[0] WARN;
165
* cpushback maintains a LIFO, so push pack the -r arguments
166
* in reverse order to maintain a FIFO in case someone did -rC1 -rC3
173
while(strncmp(p, ".nr", 3) != 0)
185
copyf = lgf = nb = nflush = nlflg = 0;
186
if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
195
if ((j = cbits(i)) == XPAR) {
198
while (cbits(i) != '\n')
204
if (j == cc || j == c2) {
208
while ((j = cbits(i = getch())) == ' ' || j == '\t')
231
for (i = NTRTAB; --i; )
242
numtabp[PID].val = getpid();
243
numtabp[HP].val = init = 0;
244
numtabp[NL].val = -1;
247
sprintf(buf, ".ds .T %s\n", devname);
249
sprintf(buf, ".ds .P %s\n", DWBhomedir);
251
numtabp[CD].val = -1; /* compensation */
253
frame = stk = (Stack *)setbrk(STACKSIZE);
256
for (i = 1; i < NEV; i++) /* propagate the environment */
257
envcopy(&env[i], &env[0]);
258
for (i = 0; i < NEV; i++) {
259
if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
260
ERROR "not enough room for word buffers" WARN;
263
env[i]._word._size = WDSIZE;
264
if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
265
ERROR "not enough room for line buffers" WARN;
268
env[i]._line._size = LNSIZE;
270
if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
271
ERROR "not enough room for line buffers" WARN;
285
ltime = localtime(&tt);
286
numtabp[YR].val = ltime->tm_year % 100;
288
numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
289
numtabp[DY].val = ltime->tm_mday;
290
numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
297
void errprint(void) /* error message printer */
299
int savecd = numtabp[CD].val;
304
fprintf(stderr, "%s: ", progname);
305
fputs(errbuf, stderr);
307
fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
311
numtabp[CD].val = savecd;
315
int control(int a, int b)
318
extern Contab *contabp;
322
if (a == 0 || (j = findmn(a)) == -1)
324
if (contabp[j].f == 0) {
326
fprintf(stderr, "invoke macro %s\n", unpair(a));
328
for (k = dilev; k; k--)
329
if (d[k].curd == a) {
330
ERROR "diversion %s invokes itself during diversion",
338
return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
342
fprintf(stderr, "invoke request %s\n", unpair(a));
356
i = max(inumb(&trace), 0);
370
if ((i = getach()) == 0 || (j = getach()) == 0)
378
* table encodes some special characters, to speed up tests
379
* in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
382
char gchtab[NCHARS] = {
383
000,004,000,000,010,000,000,000, /* fc, ldr */
384
001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
385
000,000,000,000,000,000,000,000,
386
000,001,000,001,000,000,000,000, /* FLSS, ESC */
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,000,000,
395
000,000,000,000,000,000,001,000, /* f */
396
000,000,000,000,000,000,000,000,
397
000,000,000,000,000,000,000,000,
398
000,000,000,000,000,000,000,000
401
int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
417
if (cbits(i) == '\n')
429
if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
435
numtabp[CD].val++; /* line number */
453
if (k == 'f' && lg && !lgf) {
457
if (k == fc || k == tabch || k == ldrch) {
458
if ((i = setfield(k)) == 0)
464
i = makem(-width(' ' | chbits));
471
k = cbits(j = getch0());
476
case 'n': /* number register */
479
case '$': /* argument indicator */
482
case '*': /* string indicator */
488
case '}': /* RIGHT */
491
case '"': /* comment */
492
while (cbits(i = getch0()) != '\n')
495
numtabp[CD].val++; /* line number */
499
/* experiment: put it here instead of copy mode */
500
case '(': /* special char name \(xx */
501
case 'C': /* \C'...' */
502
if ((i = setch(k)) == 0)
506
case ESC: /* double backslash */
509
case 'e': /* printable version of current eschar */
512
case '\n': /* concealed newline */
515
case ' ': /* unpaddable space */
518
case '\'': /* \(aa */
527
case '-': /* current font minus */
530
case '&': /* filler */
533
case 'c': /* to be continued */
536
case '!': /* transparent indicator */
542
case 'a': /* leader (SOH) */
543
/* old: *pbp++ = LEADER; goto g0; */
549
case 'g': /* return format of a number register */
550
setaf(); /* should this really be in copy mode??? */
555
setsfbits(i, sfbits(j));
564
case 'f': /* font indicator */
567
case 's': /* size indicator */
570
case 'v': /* vert mot */
571
numerr.type = numerr.escarg = 0; numerr.esc = k;
576
case 'h': /* horiz mot */
577
numerr.type = numerr.escarg = 0; numerr.esc = k;
581
case '|': /* narrow space */
584
return(makem((int)(EM)/6));
585
case '^': /* half narrow space */
588
return(makem((int)(EM)/12));
589
case 'w': /* width function */
592
case 'p': /* spread */
595
case 'N': /* absolute character number */
596
numerr.type = numerr.escarg = 0; numerr.esc = k;
597
if ((i = setabs()) == 0)
600
case 'H': /* character height */
601
numerr.type = numerr.escarg = 0; numerr.esc = k;
603
case 'S': /* slant */
604
numerr.type = numerr.escarg = 0; numerr.esc = k;
606
case 'z': /* zero with char */
608
case 'l': /* hor line */
609
numerr.type = numerr.escarg = 0; numerr.esc = k;
612
case 'L': /* vert line */
613
numerr.type = numerr.escarg = 0; numerr.esc = k;
616
case 'D': /* drawing function */
617
numerr.type = numerr.escarg = 0; numerr.esc = k;
620
case 'X': /* \X'...' for copy through */
623
case 'b': /* bracket */
626
case 'o': /* overstrike */
629
case 'k': /* mark hor place */
630
if ((k = findr(getsn())) != -1) {
631
numtabp[k].val = numtabp[HP].val;
634
case '0': /* number space */
635
return(makem(width('0' | chbits)));
636
case 'x': /* extra line space */
637
numerr.type = numerr.escarg = 0; numerr.esc = k;
641
case 'u': /* half em up */
642
case 'r': /* full em up */
643
case 'd': /* half em down */
651
void setxon(void) /* \X'...' for copy through */
658
if (ismot(c = getch()))
663
while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
668
*i++ = XOFF | chbits;
674
char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
698
if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
700
ERROR "in getch0, nfo = %d", nfo WARN;
721
if (i >= 040) /* zapped: && i < 0177 */
725
if (cbits(i) == IMP && !raw)
727
if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
733
if (copyf == 0 && sfbits(i) == 0)
735
if (cbits(i) == eschar && !raw)
742
Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */
748
for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
749
if ((c = getc(fp)) == EOF)
752
if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
756
if (n == 1) /* real ascii, presumably */
759
return p[-1]; /* illegal, but what else to do? */
763
return chadd(buf, MBchar, Install); /* add name even if haven't seen it */
767
void pushback(Tchar *b)
774
while (b > ob && pbp < &pbbuf[NC-3])
776
if (pbp >= &pbbuf[NC-3]) {
777
ERROR "pushback overflow" WARN;
782
void cpushback(char *b)
789
while (b > ob && pbp < &pbbuf[NC-3])
791
if (pbp >= &pbbuf[NC-3]) {
792
ERROR "cpushback overflow" WARN;
804
if (ifi > 0 && !nx) {
806
goto n0; /* popf error */
807
return(1); /* popf ok */
809
if (nx || nmfi < mflg) {
815
if ((nfo -= mflg) && !stdi) {
819
numtabp[CD].val = stdi = mflg = 0;
821
strcpy(cfname[ifi], "stdin");
829
if (p[0] == '-' && p[1] == 0) {
831
strcpy(cfname[ifi], "stdin");
832
} else if ((ifile = fopen(unsharp(p), "r")) == NULL) {
833
ERROR "cannot open file %s", p WARN;
837
strcpy(cfname[ifi],p);
847
ERROR "popf went negative" WARN;
850
numtabp[CD].val = cfline[ifi]; /* restore line counter */
851
ip = ipl[ifi]; /* input pointer */
852
ifile = ifl[ifi]; /* input FILE * */
864
if (donef && frame == stk)
872
* return 16-bit, ascii/alphabetic character, ignore chars with more bits,
873
* (internal names), spaces and special cookies (below 040).
874
* Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
883
j = cbits(i = getch());
886
|| (j <= 040 && j != 002 /*STX*/
890
&& j != 007)) { /*BELL*/
907
strcpy(mfiles[nmfi], nextf);
922
for (k = 0; k < NS - 1; k++) {
940
if (skip() || !getname() || (fp = fopen(unsharp(nextf), "r")) == NULL || ifi >= NSO) {
941
ERROR "can't open file %s", nextf WARN;
944
strcpy(cfname[ifi+1], nextf);
945
cfline[ifi] = numtabp[CD].val; /*hold line counter*/
957
void caself(void) /* set line number and file */
965
cfline[ifi] = numtabp[CD].val = n - 1;
967
if (getname()) { /* eats '\n' ? */
968
strcpy(cfname[ifi], nextf);
974
void cpout(FILE *fin, char *token)
979
if (token) { /* BUG: There should be no NULL bytes in input */
981
while ((fgets(buf, sizeof buf, fin)) != NULL) {
983
numtabp[CD].val++; /* line number */
984
if (strcmp(token, buf) == 0)
987
newl = strchr(buf, '\n');
991
while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
992
fwrite(buf, n, 1, ptid);
998
{ /* copy file without change */
1001
extern int hpos, esc, po;
1003
/* this may not make much sense in nroff... */
1007
if (!skip() && getname()) {
1008
if (strncmp("<<", nextf, 2) != 0) {
1009
if ((fd = fopen(unsharp(nextf), "r")) == NULL) {
1010
ERROR "can't open file %s", nextf WARN;
1013
eof = (char *) NULL;
1014
} else { /* current file */
1015
if (pbp > lastpbp || ip) {
1016
ERROR "casecf: not reading from file" WARN;
1021
ERROR "casecf: missing end of input token" WARN;
1032
ERROR "casecf: no argument" WARN;
1038
/* make it into a clean state, be sure that everything is out */
1042
ptesc(); /* to left margin */
1054
void getline(char *s, int n) /* get rest of input line into s */
1061
for (i = 0; i < n-1; i++)
1062
if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
1069
void casesy(void) /* call system */
1073
getline(sybuf, NTM);
1095
if (isdigit((uchar)*a)) {
1097
n = 10 * n + *a++ - '0';
1098
while (isdigit((uchar)*a));
1102
*pnp++ = neg ? -n : n;
1104
if (pnp >= &pnlist[NPN-2]) {
1105
ERROR "too many page numbers" WARN;
1114
if (*pnp != -INT_MAX)
1128
if ((long) i < 0 || cbits(j = getch0()) == RPT)
1130
while (i > 0 && pbp < &pbbuf[NC-3]) {