Blob


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