4 * consume options, initialization, main loop,
5 * input routines, escape function calling
18 char *Version
= "March 11, 1994";
21 #define DWBVERSION "???"
24 char *DWBfontdir
= FONTDIR
;
25 char *DWBntermdir
= NTERMDIR
;
26 char *DWBalthyphens
= ALTHYPHENS
;
27 char *DWBhomedir
= "";
29 dwbinit dwbpaths
[] = {
31 &DWBntermdir
, NULL
, 0,
32 &DWBalthyphens
, NULL
, 0,
38 int TROFF
= 1; /* assume we started in troff... */
44 static FILE *ifl
[NSO
]; /* open input file pointers */
45 char cfname
[NSO
+1][NS
] = { "stdin" }; /* file name stack */
46 int cfline
[NSO
]; /* input line count stack */
47 char *progname
; /* program name (troff or nroff) */
49 int trace
= 0; /* tracing mode: default off */
52 int main(int argc
, char *argv
[])
59 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')
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 };
697 if (nx
|| 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
699 ERROR
"in getch0, nfo = %d", nfo WARN
;
719 if (i
>= 040) /* zapped: && i < 0177 */
723 if (cbits(i
) == IMP
&& !raw
)
725 if (i
== 0 && !init
&& !raw
) { /* zapped: || i == 0177 */
731 if (copyf
== 0 && sfbits(i
) == 0)
733 if (cbits(i
) == eschar
&& !raw
)
739 int readutf8(int *dst
, char *src
)
747 while (l
< 6 && *s
& (0x40 >> l
))
749 *dst
= (0x3f >> l
) & *s
++;
751 *dst
= (*dst
<< 6) | (*s
++ & 0x3f);
755 static int utf8len(int c
)
760 while (l
< 6 && c
& (0x40 >> l
))
765 /* get one "character" from input, figure out what alphabet */
766 Tchar
get1ch(FILE *fp
)
774 if (c
== EOF
|| n
== 1)
777 for (i
= 1; i
< n
; i
++)
781 /* add name even if haven't seen it */
782 return chadd(buf
, MBchar
, Install
);
786 void pushback(Tchar
*b
)
793 while (b
> ob
&& pbp
< &pbbuf
[NC
-3])
795 if (pbp
>= &pbbuf
[NC
-3]) {
796 ERROR
"pushback overflow" WARN
;
801 void cpushback(char *b
)
808 while (b
> ob
&& pbp
< &pbbuf
[NC
-3])
810 if (pbp
>= &pbbuf
[NC
-3]) {
811 ERROR
"cpushback overflow" WARN
;
823 if (ifi
> 0 && !nx
) {
825 goto n0
; /* popf error */
826 return(1); /* popf ok */
828 if (nx
|| nmfi
< mflg
) {
834 if ((nfo
-= mflg
) && !stdi
) {
838 numtabp
[CD
].val
= stdi
= mflg
= 0;
840 strcpy(cfname
[ifi
], "stdin");
848 if (p
[0] == '-' && p
[1] == 0) {
850 strcpy(cfname
[ifi
], "stdin");
851 } else if ((ifile
= fopen(p
, "r")) == NULL
) {
852 ERROR
"cannot open file %s", p WARN
;
856 strcpy(cfname
[ifi
],p
);
866 ERROR
"popf went negative" WARN
;
869 numtabp
[CD
].val
= cfline
[ifi
]; /* restore line counter */
870 ip
= ipl
[ifi
]; /* input pointer */
871 ifile
= ifl
[ifi
]; /* input FILE * */
883 if (donef
&& frame
== stk
)
891 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
892 * (internal names), spaces and special cookies (below 040).
893 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
901 j
= cbits(i
= getch());
902 if (ismot(i
) || j
> SHORTMASK
903 || (j
<= 040 && j
!= 002 /*STX*/
907 && j
!= 007)) { /*BELL*/
924 strcpy(mfiles
[nmfi
], nextf
);
939 for (k
= 0; k
< NS
- 1; k
++) {
957 if (skip() || !getname() || (fp
= fopen(nextf
, "r")) == NULL
|| ifi
>= NSO
) {
958 ERROR
"can't open file %s", nextf WARN
;
961 strcpy(cfname
[ifi
+1], nextf
);
962 cfline
[ifi
] = numtabp
[CD
].val
; /*hold line counter*/
974 void caself(void) /* set line number and file */
982 cfline
[ifi
] = numtabp
[CD
].val
= n
- 1;
984 if (getname()) { /* eats '\n' ? */
985 strcpy(cfname
[ifi
], nextf
);
991 void cpout(FILE *fin
, char *token
)
996 if (token
) { /* BUG: There should be no NULL bytes in input */
998 while ((fgets(buf
, sizeof buf
, fin
)) != NULL
) {
1000 numtabp
[CD
].val
++; /* line number */
1001 if (strcmp(token
, buf
) == 0)
1004 newl
= strchr(buf
, '\n');
1008 while ((n
= fread(buf
, sizeof *buf
, sizeof buf
, fin
)) > 0)
1009 fwrite(buf
, n
, 1, ptid
);
1015 { /* copy file without change */
1018 extern int hpos
, esc
, po
;
1020 /* this may not make much sense in nroff... */
1024 if (!skip() && getname()) {
1025 if (strncmp("<<", nextf
, 2) != 0) {
1026 if ((fd
= fopen(nextf
, "r")) == NULL
) {
1027 ERROR
"can't open file %s", nextf WARN
;
1030 eof
= (char *) NULL
;
1031 } else { /* current file */
1032 if (pbp
> lastpbp
|| ip
) {
1033 ERROR
"casecf: not reading from file" WARN
;
1038 ERROR
"casecf: missing end of input token" WARN
;
1049 ERROR
"casecf: no argument" WARN
;
1055 /* make it into a clean state, be sure that everything is out */
1059 ptesc(); /* to left margin */
1071 void getline(char *s
, int n
) /* get rest of input line into s */
1078 for (i
= 0; i
< n
-1; i
++)
1079 if ((s
[i
] = cbits(getch())) == '\n' || s
[i
] == RIGHT
)
1086 void casesy(void) /* call system */
1090 getline(sybuf
, NTM
);
1114 n
= 10 * n
+ *a
++ - '0';
1115 while (isdigit(*a
));
1119 *pnp
++ = neg
? -n
: n
;
1121 if (pnp
>= &pnlist
[NPN
-2]) {
1122 ERROR
"too many page numbers" WARN
;
1131 if (*pnp
!= -INT_MAX
)
1145 if ((long) i
< 0 || cbits(j
= getch0()) == RPT
)
1147 while (i
> 0 && pbp
< &pbbuf
[NC
-3]) {