1 /*
2 * n1.c
3 *
4 * consume options, initialization, main loop,
5 * input routines, escape function calling
6 */
7
8 #include "tdef.h"
9 #include "fns.h"
10 #include "ext.h"
11 #include "dwbinit.h"
12
13 #include <setjmp.h>
14 #include <time.h>
15
16 char *Version = "March 11, 1994";
17
18 #ifndef DWBVERSION
19 #define DWBVERSION "???"
20 #endif
21
22 char *DWBfontdir = FONTDIR;
23 char *DWBntermdir = NTERMDIR;
24 char *DWBalthyphens = ALTHYPHENS;
25 char *DWBhomedir = "";
26
27 dwbinit dwbpaths[] = {
28 &DWBfontdir, NULL, 0,
29 &DWBntermdir, NULL, 0,
30 &DWBalthyphens, NULL, 0,
31 &DWBhomedir, NULL, 0,
32 NULL, nextf, NS,
33 NULL, NULL, 0
34 };
35
36 int TROFF = 1; /* assume we started in troff... */
37
38 jmp_buf sjbuf;
39 Offset ipl[NSO];
40
41 static FILE *ifile = stdin;
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) */
46
47 int trace = 0; /* tracing mode: default off */
48 int trace1 = 0;
49
main(int argc,char * argv[])50 main(int argc, char *argv[])
51 {
52 char *p;
53 int j;
54 Tchar i;
55 char buf[100];
56
57 buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
58 progname = argv[0];
59 if ((p = strrchr(progname, '/')) == NULL)
60 p = progname;
61 else
62 p++;
63 DWBinit(progname, dwbpaths);
64 if (strcmp(p, "nroff") == 0)
65 TROFF = 0;
66 #ifdef UNICODE
67 alphabet = 128; /* unicode for plan 9 */
68 #endif /*UNICODE*/
69 mnspace();
70 nnspace();
71 mrehash();
72 nrehash();
73 numtabp[NL].val = -1;
74
75 while (--argc > 0 && (++argv)[0][0] == '-')
76 switch (argv[0][1]) {
77
78 case 'N': /* ought to be used first... */
79 TROFF = 0;
80 break;
81 case 'd':
82 fprintf(stderr, "troff/nroff version %s\n", Version);
83 break;
84 case 'F': /* switch font tables from default */
85 if (argv[0][2] != '\0') {
86 strcpy(termtab, &argv[0][2]);
87 strcpy(fontdir, &argv[0][2]);
88 } else {
89 argv++; argc--;
90 strcpy(termtab, argv[0]);
91 strcpy(fontdir, argv[0]);
92 }
93 break;
94 case 0:
95 goto start;
96 case 'i':
97 stdi++;
98 break;
99 case 'n':
100 npn = atoi(&argv[0][2]);
101 break;
102 case 'u': /* set emboldening amount */
103 bdtab[3] = atoi(&argv[0][2]);
104 if (bdtab[3] < 0 || bdtab[3] > 50)
105 bdtab[3] = 0;
106 break;
107 case 's':
108 if (!(stop = atoi(&argv[0][2])))
109 stop++;
110 break;
111 case 'r':
112 sprintf(buf + strlen(buf), ".nr %c %s\n",
113 argv[0][2], &argv[0][3]);
114 /* not yet cpushback(buf);*/
115 /* dotnr(&argv[0][2], &argv[0][3]); */
116 break;
117 case 'm':
118 if (mflg++ >= NMF) {
119 ERROR "Too many macro packages: %s", argv[0] WARN;
120 break;
121 }
122 strcpy(mfiles[nmfi], nextf);
123 strcat(mfiles[nmfi++], &argv[0][2]);
124 break;
125 case 'o':
126 getpn(&argv[0][2]);
127 break;
128 case 'T':
129 strcpy(devname, &argv[0][2]);
130 dotT++;
131 break;
132 case 'a':
133 ascii = 1;
134 break;
135 case 'h':
136 hflg++;
137 break;
138 case 'e':
139 eqflg++;
140 break;
141 case 'q':
142 quiet++;
143 save_tty();
144 break;
145 case 'V':
146 fprintf(stdout, "%croff: DWB %s\n",
147 TROFF ? 't' : 'n', DWBVERSION);
148 exit(0);
149 case 't':
150 if (argv[0][2] != '\0')
151 trace = trace1 = argv[0][2];
152 break; /* for the sake of compatibility */
153 default:
154 ERROR "unknown option %s", argv[0] WARN;
155 done(02);
156 }
157
158 start:
159 /*
160 * cpushback maintains a LIFO, so push pack the -r arguments
161 * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
162 */
163 if (buf[0]) {
164 char *p = buf;
165 while(*p++)
166 ;
167 while(p > buf) {
168 while(strncmp(p, ".nr", 3) != 0)
169 p--;
170 cpushback(p);
171 *p-- = '\0';
172 }
173 }
174 argp = argv;
175 rargc = argc;
176 nmfi = 0;
177 init2();
178 setjmp(sjbuf);
179 loop:
180 copyf = lgf = nb = nflush = nlflg = 0;
181 if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
182 nflush++;
183 trap = 0;
184 eject((Stack *)0);
185 goto loop;
186 }
187 i = getch();
188 if (pendt)
189 goto Lt;
190 if ((j = cbits(i)) == XPAR) {
191 copyf++;
192 tflg++;
193 while (cbits(i) != '\n')
194 pchar(i = getch());
195 tflg = 0;
196 copyf--; /* pointless */
197 goto loop;
198 }
199 if (j == cc || j == c2) {
200 if (j == c2)
201 nb++;
202 copyf++;
203 while ((j = cbits(i = getch())) == ' ' || j == '\t')
204 ;
205 ch = i;
206 copyf--;
207 control(getrq(), 1);
208 flushi();
209 goto loop;
210 }
211 Lt:
212 ch = i;
213 text();
214 if (nlflg)
215 numtabp[HP].val = 0;
216 goto loop;
217 }
218
219
220
init2(void)221 void init2(void)
222 {
223 int i;
224 char buf[100];
225
226 for (i = NTRTAB; --i; )
227 trtab[i] = i;
228 trtab[UNPAD] = ' ';
229 iflg = 0;
230 obufp = obuf;
231 if (TROFF)
232 t_ptinit();
233 else
234 n_ptinit();
235 mchbits();
236 cvtime();
237 numtabp[PID].val = getpid();
238 numtabp[HP].val = init = 0;
239 numtabp[NL].val = -1;
240 nfo = 0;
241 copyf = raw = 0;
242 sprintf(buf, ".ds .T %s\n", devname);
243 cpushback(buf);
244 sprintf(buf, ".ds .P %s\n", DWBhomedir);
245 cpushback(buf);
246 numtabp[CD].val = -1; /* compensation */
247 nx = mflg;
248 frame = stk = (Stack *)setbrk(STACKSIZE);
249 dip = &d[0];
250 nxf = frame + 1;
251 for (i = 1; i < NEV; i++) /* propagate the environment */
252 envcopy(&env[i], &env[0]);
253 for (i = 0; i < NEV; i++) {
254 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
255 ERROR "not enough room for word buffers" WARN;
256 done2(1);
257 }
258 env[i]._word._size = WDSIZE;
259 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
260 ERROR "not enough room for line buffers" WARN;
261 done2(1);
262 }
263 env[i]._line._size = LNSIZE;
264 }
265 if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
266 ERROR "not enough room for line buffers" WARN;
267 done2(1);
268 }
269 olinep = oline;
270 olnsize = OLNSIZE;
271 blockinit();
272 }
273
cvtime(void)274 void cvtime(void)
275 {
276 long tt;
277 struct tm *ltime;
278
279 time(&tt);
280 ltime = localtime(&tt);
281 numtabp[YR].val = ltime->tm_year % 100;
282 numtabp[YR].fmt = 2;
283 numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
284 numtabp[DY].val = ltime->tm_mday;
285 numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
286 }
287
288
289
290 char errbuf[200];
291
errprint(void)292 void errprint(void) /* error message printer */
293 {
294 int savecd = numtabp[CD].val;
295
296 if (!nlflg)
297 numtabp[CD].val++;
298
299 fprintf(stderr, "%s: ", progname);
300 fputs(errbuf, stderr);
301 if (cfname[ifi][0])
302 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
303 fputs("\n", stderr);
304 if (cfname[ifi][0])
305 stackdump();
306 numtabp[CD].val = savecd;
307 }
308
309
control(int a,int b)310 int control(int a, int b)
311 {
312 int j, k;
313 extern Contab *contabp;
314
315 numerr.type = RQERR;
316 numerr.req = a;
317 if (a == 0 || (j = findmn(a)) == -1)
318 return(0);
319 if (contabp[j].f == 0) {
320 if (trace & TRMAC)
321 fprintf(stderr, "invoke macro %s\n", unpair(a));
322 if (dip != d)
323 for (k = dilev; k; k--)
324 if (d[k].curd == a) {
325 ERROR "diversion %s invokes itself during diversion",
326 unpair(a) WARN;
327 edone(0100);
328 }
329 nxf->nargs = 0;
330 if (b)
331 collect();
332 flushi();
333 return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
334 }
335 if (b) {
336 if (trace & TRREQ)
337 fprintf(stderr, "invoke request %s\n", unpair(a));
338 (*contabp[j].f)();
339 }
340 return(0);
341 }
342
casept(void)343 void casept(void)
344 {
345 int i;
346
347 noscale++;
348 if (skip())
349 i = trace1;
350 else {
351 i = max(inumb(&trace), 0);
352 if (nonumb)
353 i = trace1;
354 }
355 trace1 = trace;
356 trace = i;
357 noscale = 0;
358 }
359
360
getrq(void)361 int getrq(void)
362 {
363 int i, j;
364
365 if ((i = getach()) == 0 || (j = getach()) == 0)
366 goto rtn;
367 i = PAIR(i, j);
368 rtn:
369 return(i);
370 }
371
372 /*
373 * table encodes some special characters, to speed up tests
374 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
375 */
376
377 char gchtab[NCHARS] = {
378 000,004,000,000,010,000,000,000, /* fc, ldr */
379 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
380 000,000,000,000,000,000,000,000,
381 000,001,000,001,000,000,000,000, /* FLSS, ESC */
382 000,000,000,000,000,000,000,000,
383 000,000,000,000,000,000,000,000,
384 000,000,000,000,000,000,000,000,
385 000,000,000,000,000,000,000,000,
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,001,000, /* f */
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 };
395
realcbits(Tchar c)396 int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
397 {
398 if (ismot(c))
399 return MOTCH;
400 else
401 return c & 0xFFFF;
402 }
403
getch(void)404 Tchar getch(void)
405 {
406 int k;
407 Tchar i, j;
408
409 g0:
410 if (ch) {
411 i = ch;
412 if (cbits(i) == '\n')
413 nlflg++;
414 ch = 0;
415 return(i);
416 }
417
418 if (nlflg)
419 return('\n');
420 i = getch0();
421 if (ismot(i))
422 return(i);
423 k = cbits(i);
424 if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
425 return(i);
426 if (k != ESC) {
427 if (k == '\n') {
428 nlflg++;
429 if (ip == 0)
430 numtabp[CD].val++; /* line number */
431 return(k);
432 }
433 if (k == FLSS) {
434 copyf++;
435 raw++;
436 i = getch0();
437 if (!fi)
438 flss = i;
439 copyf--;
440 raw--;
441 goto g0;
442 }
443 if (k == RPT) {
444 setrpt();
445 goto g0;
446 }
447 if (!copyf) {
448 if (k == 'f' && lg && !lgf) {
449 i = getlg(i);
450 return(i);
451 }
452 if (k == fc || k == tabch || k == ldrch) {
453 if ((i = setfield(k)) == 0)
454 goto g0;
455 else
456 return(i);
457 }
458 if (k == '\b') {
459 i = makem(-width(' ' | chbits));
460 return(i);
461 }
462 }
463 return(i);
464 }
465
466 k = cbits(j = getch0());
467 if (ismot(j))
468 return(j);
469
470 switch (k) {
471 case 'n': /* number register */
472 setn();
473 goto g0;
474 case '$': /* argument indicator */
475 seta();
476 goto g0;
477 case '*': /* string indicator */
478 setstr();
479 goto g0;
480 case '{': /* LEFT */
481 i = LEFT;
482 goto gx;
483 case '}': /* RIGHT */
484 i = RIGHT;
485 goto gx;
486 case '"': /* comment */
487 while (cbits(i = getch0()) != '\n')
488 ;
489 if (ip == 0)
490 numtabp[CD].val++; /* line number */
491 nlflg++;
492 return(i);
493
494 /* experiment: put it here instead of copy mode */
495 case '(': /* special char name \(xx */
496 case 'C': /* \C'...' */
497 if ((i = setch(k)) == 0)
498 goto g0;
499 goto gx;
500
501 case ESC: /* double backslash */
502 i = eschar;
503 goto gx;
504 case 'e': /* printable version of current eschar */
505 i = PRESC;
506 goto gx;
507 case '\n': /* concealed newline */
508 numtabp[CD].val++;
509 goto g0;
510 case ' ': /* unpaddable space */
511 i = UNPAD;
512 goto gx;
513 case '\'': /* \(aa */
514 i = ACUTE;
515 goto gx;
516 case '`': /* \(ga */
517 i = GRAVE;
518 goto gx;
519 case '_': /* \(ul */
520 i = UNDERLINE;
521 goto gx;
522 case '-': /* current font minus */
523 i = MINUS;
524 goto gx;
525 case '&': /* filler */
526 i = FILLER;
527 goto gx;
528 case 'c': /* to be continued */
529 i = CONT;
530 goto gx;
531 case '!': /* transparent indicator */
532 i = XPAR;
533 goto gx;
534 case 't': /* tab */
535 i = '\t';
536 return(i);
537 case 'a': /* leader (SOH) */
538 /* old: *pbp++ = LEADER; goto g0; */
539 i = LEADER;
540 return i;
541 case '%': /* ohc */
542 i = OHC;
543 return(i);
544 case 'g': /* return format of a number register */
545 setaf(); /* should this really be in copy mode??? */
546 goto g0;
547 case '.': /* . */
548 i = '.';
549 gx:
550 setsfbits(i, sfbits(j));
551 return(i);
552 }
553 if (copyf) {
554 *pbp++ = j;
555 return(eschar);
556 }
557 switch (k) {
558
559 case 'f': /* font indicator */
560 setfont(0);
561 goto g0;
562 case 's': /* size indicator */
563 setps();
564 goto g0;
565 case 'v': /* vert mot */
566 numerr.type = numerr.escarg = 0; numerr.esc = k;
567 if (i = vmot()) {
568 return(i);
569 }
570 goto g0;
571 case 'h': /* horiz mot */
572 numerr.type = numerr.escarg = 0; numerr.esc = k;
573 if (i = hmot())
574 return(i);
575 goto g0;
576 case '|': /* narrow space */
577 if (NROFF)
578 goto g0;
579 return(makem((int)(EM)/6));
580 case '^': /* half narrow space */
581 if (NROFF)
582 goto g0;
583 return(makem((int)(EM)/12));
584 case 'w': /* width function */
585 setwd();
586 goto g0;
587 case 'p': /* spread */
588 spread++;
589 goto g0;
590 case 'N': /* absolute character number */
591 numerr.type = numerr.escarg = 0; numerr.esc = k;
592 if ((i = setabs()) == 0)
593 goto g0;
594 return i;
595 case 'H': /* character height */
596 numerr.type = numerr.escarg = 0; numerr.esc = k;
597 return(setht());
598 case 'S': /* slant */
599 numerr.type = numerr.escarg = 0; numerr.esc = k;
600 return(setslant());
601 case 'z': /* zero with char */
602 return(setz());
603 case 'l': /* hor line */
604 numerr.type = numerr.escarg = 0; numerr.esc = k;
605 setline();
606 goto g0;
607 case 'L': /* vert line */
608 numerr.type = numerr.escarg = 0; numerr.esc = k;
609 setvline();
610 goto g0;
611 case 'D': /* drawing function */
612 numerr.type = numerr.escarg = 0; numerr.esc = k;
613 setdraw();
614 goto g0;
615 case 'X': /* \X'...' for copy through */
616 setxon();
617 goto g0;
618 case 'b': /* bracket */
619 setbra();
620 goto g0;
621 case 'o': /* overstrike */
622 setov();
623 goto g0;
624 case 'k': /* mark hor place */
625 if ((k = findr(getsn())) != -1) {
626 numtabp[k].val = numtabp[HP].val;
627 }
628 goto g0;
629 case '0': /* number space */
630 return(makem(width('0' | chbits)));
631 case 'x': /* extra line space */
632 numerr.type = numerr.escarg = 0; numerr.esc = k;
633 if (i = xlss())
634 return(i);
635 goto g0;
636 case 'u': /* half em up */
637 case 'r': /* full em up */
638 case 'd': /* half em down */
639 return(sethl(k));
640 default:
641 return(j);
642 }
643 /* NOTREACHED */
644 }
645
setxon(void)646 void setxon(void) /* \X'...' for copy through */
647 {
648 Tchar xbuf[NC];
649 Tchar *i;
650 Tchar c;
651 int delim, k;
652
653 if (ismot(c = getch()))
654 return;
655 delim = cbits(c);
656 i = xbuf;
657 *i++ = XON | chbits;
658 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
659 if (k == ' ')
660 setcbits(c, WORDSP);
661 *i++ = c | ZBIT;
662 }
663 *i++ = XOFF | chbits;
664 *i = 0;
665 pushback(xbuf);
666 }
667
668
669 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
670
getch0(void)671 Tchar getch0(void)
672 {
673 Tchar i;
674
675 again:
676 if (pbp > lastpbp)
677 i = *--pbp;
678 else if (ip) {
679 /* i = rbf(); */
680 i = rbf0(ip);
681 if (i == 0)
682 i = rbf();
683 else {
684 ++ip;
685 if (pastend(ip)) {
686 --ip;
687 rbf();
688 }
689 }
690 } else {
691 if (donef || ndone)
692 done(0);
693 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
694 if (nfo < 0)
695 ERROR "in getch0, nfo = %d", nfo WARN;
696 if (nfo == 0) {
697 g0:
698 if (nextfile()) {
699 if (ip)
700 goto again;
701 }
702 }
703 nx = 0;
704 #ifdef UNICODE
705 if (MB_CUR_MAX > 1)
706 i = get1ch(ifile);
707 else
708 #endif /*UNICODE*/
709 i = getc(ifile);
710 if (i == EOF)
711 goto g0;
712 if (ip)
713 goto again;
714 }
715 if (i >= 040) /* zapped: && i < 0177 */
716 goto g4;
717 i = ifilt[i];
718 }
719 if (cbits(i) == IMP && !raw)
720 goto again;
721 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
722 goto again;
723 }
724 g4:
725 if (ismot(i))
726 return i;
727 if (copyf == 0 && sfbits(i) == 0)
728 i |= chbits;
729 if (cbits(i) == eschar && !raw)
730 setcbits(i, ESC);
731 return(i);
732 }
733
734
735 #ifdef UNICODE
get1ch(FILE * fp)736 Tchar get1ch(FILE *fp) /* get one "character" from input, figure out what alphabet */
737 {
738 wchar_t wc;
739 char buf[100], *p;
740 int i, n, c;
741
742 n = c = 0;
743 for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
744 if ((c = getc(fp)) == EOF)
745 return c;
746 *p++ = c;
747 if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
748 break;
749 }
750 if (n == 1) /* real ascii, presumably */
751 return wc;
752 if (n == 0)
753 return p[-1]; /* illegal, but what else to do? */
754 if (c == EOF)
755 return EOF;
756 *p = 0;
757 return chadd(buf, MBchar, Install); /* add name even if haven't seen it */
758 }
759 #endif /*UNICODE*/
760
pushback(Tchar * b)761 void pushback(Tchar *b)
762 {
763 Tchar *ob = b;
764
765 while (*b++)
766 ;
767 b--;
768 while (b > ob && pbp < &pbbuf[NC-3])
769 *pbp++ = *--b;
770 if (pbp >= &pbbuf[NC-3]) {
771 ERROR "pushback overflow" WARN;
772 done(2);
773 }
774 }
775
cpushback(char * b)776 void cpushback(char *b)
777 {
778 char *ob = b;
779
780 while (*b++)
781 ;
782 b--;
783 while (b > ob && pbp < &pbbuf[NC-3])
784 *pbp++ = *--b;
785 if (pbp >= &pbbuf[NC-3]) {
786 ERROR "cpushback overflow" WARN;
787 done(2);
788 }
789 }
790
nextfile(void)791 int nextfile(void)
792 {
793 char *p;
794
795 n0:
796 if (ifile != stdin)
797 fclose(ifile);
798 if (ifi > 0 && !nx) {
799 if (popf())
800 goto n0; /* popf error */
801 return(1); /* popf ok */
802 }
803 if (nx || nmfi < mflg) {
804 p = mfiles[nmfi++];
805 if (*p != 0)
806 goto n1;
807 }
808 if (rargc-- <= 0) {
809 if ((nfo -= mflg) && !stdi) {
810 done(0);
811 }
812 nfo++;
813 numtabp[CD].val = stdi = mflg = 0;
814 ifile = stdin;
815 strcpy(cfname[ifi], "stdin");
816 return(0);
817 }
818 p = (argp++)[0];
819 if (rargc >= 0)
820 cfname[ifi][0] = 0;
821 n1:
822 numtabp[CD].val = 0;
823 if (p[0] == '-' && p[1] == 0) {
824 ifile = stdin;
825 strcpy(cfname[ifi], "stdin");
826 } else if ((ifile = fopen(p, "r")) == NULL) {
827 ERROR "cannot open file %s", p WARN;
828 nfo -= mflg;
829 done(02);
830 } else
831 strcpy(cfname[ifi],p);
832 nfo++;
833 return(0);
834 }
835
836
popf(void)837 popf(void)
838 {
839 --ifi;
840 if (ifi < 0) {
841 ERROR "popf went negative" WARN;
842 return 1;
843 }
844 numtabp[CD].val = cfline[ifi]; /* restore line counter */
845 ip = ipl[ifi]; /* input pointer */
846 ifile = ifl[ifi]; /* input FILE * */
847 return(0);
848 }
849
850
flushi(void)851 void flushi(void)
852 {
853 if (nflush)
854 return;
855 ch = 0;
856 copyf++;
857 while (!nlflg) {
858 if (donef && frame == stk)
859 break;
860 getch();
861 }
862 copyf--;
863 }
864
865 /*
866 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
867 * (internal names), spaces and special cookies (below 040).
868 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
869 */
getach(void)870 getach(void)
871 {
872 Tchar i;
873 int j;
874
875 lgf++;
876 j = cbits(i = getch());
877 if (ismot(i)
878 || j > SHORTMASK
879 || (j <= 040 && j != 002 /*STX*/
880 && j != 003 /*ETX*/
881 && j != 005 /*ENQ*/
882 && j != 006 /*ACK*/
883 && j != 007)) { /*BELL*/
884 ch = i;
885 j = 0;
886 }
887 lgf--;
888 return j;
889 }
890
891
casenx(void)892 void casenx(void)
893 {
894 lgf++;
895 skip();
896 getname();
897 nx++;
898 if (nmfi > 0)
899 nmfi--;
900 strcpy(mfiles[nmfi], nextf);
901 nextfile();
902 nlflg++;
903 ip = 0;
904 pendt = 0;
905 frame = stk;
906 nxf = frame + 1;
907 }
908
909
getname(void)910 getname(void)
911 {
912 int j, k;
913
914 lgf++;
915 for (k = 0; k < NS - 1; k++) {
916 j = getach();
917 if (!j)
918 break;
919 nextf[k] = j;
920 }
921 nextf[k] = 0;
922 lgf--;
923 return(nextf[0]);
924 }
925
926
caseso(void)927 void caseso(void)
928 {
929 FILE *fp;
930
931 lgf++;
932 nextf[0] = 0;
933 fp = NULL;
934 if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
935 ERROR "can't open file %s", nextf WARN;
936 done(02);
937 }
938 strcpy(cfname[ifi+1], nextf);
939 cfline[ifi] = numtabp[CD].val; /*hold line counter*/
940 numtabp[CD].val = 0;
941 flushi();
942 ifl[ifi] = ifile;
943 ifile = fp;
944 ipl[ifi] = ip;
945 ip = 0;
946 nx++;
947 nflush++;
948 ifi++;
949 }
950
caself(void)951 void caself(void) /* set line number and file */
952 {
953 int n;
954
955 if (skip())
956 return;
957 n = atoi0();
958 if (!nonumb)
959 cfline[ifi] = numtabp[CD].val = n - 1;
960 if (!skip())
961 if (getname()) { /* eats '\n' ? */
962 strcpy(cfname[ifi], nextf);
963 if (!nonumb)
964 numtabp[CD].val--;
965 }
966 }
967
cpout(FILE * fin,char * token)968 void cpout(FILE *fin, char *token)
969 {
970 int n;
971 char buf[1024];
972
973 if (token) { /* BUG: There should be no NULL bytes in input */
974 char *newl = buf;
975 while ((fgets(buf, sizeof buf, fin)) != NULL) {
976 if (newl) {
977 numtabp[CD].val++; /* line number */
978 if (strcmp(token, buf) == 0)
979 return;
980 }
981 newl = strchr(buf, '\n');
982 fputs(buf, ptid);
983 }
984 } else {
985 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
986 fwrite(buf, n, 1, ptid);
987 fclose(fin);
988 }
989 }
990
casecf(void)991 void casecf(void)
992 { /* copy file without change */
993 FILE *fd;
994 char *eof, *p;
995 extern int hpos, esc, po;
996
997 /* this may not make much sense in nroff... */
998
999 lgf++;
1000 nextf[0] = 0;
1001 if (!skip() && getname()) {
1002 if (strncmp("<<", nextf, 2) != 0) {
1003 if ((fd = fopen(nextf, "r")) == NULL) {
1004 ERROR "can't open file %s", nextf WARN;
1005 done(02);
1006 }
1007 eof = (char *) NULL;
1008 } else { /* current file */
1009 if (pbp > lastpbp || ip) {
1010 ERROR "casecf: not reading from file" WARN;
1011 done(02);
1012 }
1013 eof = &nextf[2];
1014 if (!*eof) {
1015 ERROR "casecf: missing end of input token" WARN;
1016 done(02);
1017 }
1018 p = eof;
1019 while(*++p)
1020 ;
1021 *p++ = '\n';
1022 *p = 0;
1023 fd = ifile;
1024 }
1025 } else {
1026 ERROR "casecf: no argument" WARN;
1027 lgf--;
1028 return;
1029 }
1030 lgf--;
1031
1032 /* make it into a clean state, be sure that everything is out */
1033 tbreak();
1034 hpos = po;
1035 esc = 0;
1036 ptesc(); /* to left margin */
1037 esc = un;
1038 ptesc();
1039 ptlead();
1040 ptps();
1041 ptfont();
1042 flusho();
1043 cpout(fd, eof);
1044 ptps();
1045 ptfont();
1046 }
1047
getline(char * s,int n)1048 void getline(char *s, int n) /* get rest of input line into s */
1049 {
1050 int i;
1051
1052 lgf++;
1053 copyf++;
1054 skip();
1055 for (i = 0; i < n-1; i++)
1056 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
1057 break;
1058 s[i] = 0;
1059 copyf--;
1060 lgf--;
1061 }
1062
casesy(void)1063 void casesy(void) /* call system */
1064 {
1065 char sybuf[NTM];
1066
1067 getline(sybuf, NTM);
1068 system(sybuf);
1069 }
1070
1071
getpn(char * a)1072 void getpn(char *a)
1073 {
1074 int n, neg;
1075
1076 if (*a == 0)
1077 return;
1078 neg = 0;
1079 for ( ; *a; a++)
1080 switch (*a) {
1081 case '+':
1082 case ',':
1083 continue;
1084 case '-':
1085 neg = 1;
1086 continue;
1087 default:
1088 n = 0;
1089 if (isdigit(*a)) {
1090 do
1091 n = 10 * n + *a++ - '0';
1092 while (isdigit(*a));
1093 a--;
1094 } else
1095 n = 9999;
1096 *pnp++ = neg ? -n : n;
1097 neg = 0;
1098 if (pnp >= &pnlist[NPN-2]) {
1099 ERROR "too many page numbers" WARN;
1100 done3(-3);
1101 }
1102 }
1103 if (neg)
1104 *pnp++ = -9999;
1105 *pnp = -INT_MAX;
1106 print = 0;
1107 pnp = pnlist;
1108 if (*pnp != -INT_MAX)
1109 chkpn();
1110 }
1111
1112
setrpt(void)1113 void setrpt(void)
1114 {
1115 Tchar i, j;
1116
1117 copyf++;
1118 raw++;
1119 i = getch0();
1120 copyf--;
1121 raw--;
1122 if ((long) i < 0 || cbits(j = getch0()) == RPT)
1123 return;
1124 while (i > 0 && pbp < &pbbuf[NC-3]) {
1125 i--;
1126 *pbp++ = j;
1127 }
1128 }
1129