]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/troff/n1.c
ip/ipconfig: format ipmask with %M instead of %I
[plan9front.git] / sys / src / cmd / troff / n1.c
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
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--;
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
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
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
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
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
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
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
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
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
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
671 Tchar getch0(void)
672 {
673         int j;
674         Tchar i;
675
676 again:
677         if (pbp > lastpbp)
678                 i = *--pbp;
679         else if (ip) {
680                 /* i = rbf(); */
681                 i = rbf0(ip);
682                 if (i == 0)
683                         i = rbf();
684                 else {
685                         ++ip;
686                         if (pastend(ip)) {
687                                 --ip;
688                                 rbf();
689                         }
690                 }
691         } else {
692                 if (donef || ndone)
693                         done(0);
694                 if (nx || 1) {  /* BUG: was ibufp >= eibuf, so EOF test is wrong */
695                         if (nfo < 0)
696                                 ERROR "in getch0, nfo = %d", nfo WARN;
697                         if (nfo == 0) {
698 g0:
699                                 if (nextfile()) {
700                                         if (ip)
701                                                 goto again;
702                                 }
703                         }
704                         nx = 0;
705 #ifdef UNICODE
706                         if (MB_CUR_MAX > 1)
707                                 i = get1ch(ifile);
708                         else
709 #endif  /*UNICODE*/
710                                 i = getc(ifile);
711                         if (i == EOF)
712                                 goto g0;
713                         if (ip)
714                                 goto again;
715                 }
716 g2:
717                 if (i >= 040)                   /* zapped: && i < 0177 */
718                         goto g4;
719                 i = ifilt[i];
720         }
721         if (cbits(i) == IMP && !raw)
722                 goto again;
723         if (i == 0 && !init && !raw) {          /* zapped:  || i == 0177 */
724                 goto again;
725         }
726 g4:
727         if (ismot(i))
728                 return i;
729         if (copyf == 0 && sfbits(i) == 0)
730                 i |= chbits;
731         if (cbits(i) == eschar && !raw)
732                 setcbits(i, ESC);
733         return(i);
734 }
735
736
737 #ifdef UNICODE
738 Tchar get1ch(FILE *fp)  /* get one "character" from input, figure out what alphabet */
739 {
740         wchar_t wc;
741         char buf[100], *p;
742         int i, n, c;
743
744         for (i = 0, p = buf; i < MB_CUR_MAX; i++) {
745                 if ((c = getc(fp)) == EOF)
746                         return c;
747                 *p++ = c;
748                 if ((n = mbtowc(&wc, buf, p-buf)) >= 0)
749                         break;
750         }
751         if (n == 1)     /* real ascii, presumably */
752                 return wc;
753         if (n == 0)
754                 return p[-1];   /* illegal, but what else to do? */
755         if (c == EOF)
756                 return EOF;
757         *p = 0;
758         return chadd(buf, MBchar, Install);     /* add name even if haven't seen it */
759 }
760 #endif  /*UNICODE*/
761
762 void pushback(Tchar *b)
763 {
764         Tchar *ob = b;
765
766         while (*b++)
767                 ;
768         b--;
769         while (b > ob && pbp < &pbbuf[NC-3])
770                 *pbp++ = *--b;
771         if (pbp >= &pbbuf[NC-3]) {
772                 ERROR "pushback overflow" WARN;
773                 done(2);
774         }
775 }
776
777 void cpushback(char *b)
778 {
779         char *ob = b;
780
781         while (*b++)
782                 ;
783         b--;
784         while (b > ob && pbp < &pbbuf[NC-3])
785                 *pbp++ = *--b;
786         if (pbp >= &pbbuf[NC-3]) {
787                 ERROR "cpushback overflow" WARN;
788                 done(2);
789         }
790 }
791
792 int nextfile(void)
793 {
794         char *p;
795
796 n0:
797         if (ifile != stdin)
798                 fclose(ifile);
799         if (ifi > 0 && !nx) {
800                 if (popf())
801                         goto n0; /* popf error */
802                 return(1);       /* popf ok */
803         }
804         if (nx || nmfi < mflg) {
805                 p = mfiles[nmfi++];
806                 if (*p != 0)
807                         goto n1;
808         }
809         if (rargc-- <= 0) {
810                 if ((nfo -= mflg) && !stdi) {
811                         done(0);
812 }
813                 nfo++;
814                 numtabp[CD].val = stdi = mflg = 0;
815                 ifile = stdin;
816                 strcpy(cfname[ifi], "stdin");
817                 return(0);
818         }
819         p = (argp++)[0];
820         if (rargc >= 0)
821                 cfname[ifi][0] = 0;
822 n1:
823         numtabp[CD].val = 0;
824         if (p[0] == '-' && p[1] == 0) {
825                 ifile = stdin;
826                 strcpy(cfname[ifi], "stdin");
827         } else if ((ifile = fopen(p, "r")) == NULL) {
828                 ERROR "cannot open file %s", p WARN;
829                 nfo -= mflg;
830                 done(02);
831         } else
832                 strcpy(cfname[ifi],p);
833         nfo++;
834         return(0);
835 }
836
837
838 popf(void)
839 {
840         --ifi;
841         if (ifi < 0) {
842                 ERROR "popf went negative" WARN;
843                 return 1;
844         }
845         numtabp[CD].val = cfline[ifi];  /* restore line counter */
846         ip = ipl[ifi];                  /* input pointer */
847         ifile = ifl[ifi];               /* input FILE * */
848         return(0);
849 }
850
851
852 void flushi(void)
853 {
854         if (nflush)
855                 return;
856         ch = 0;
857         copyf++;
858         while (!nlflg) {
859                 if (donef && frame == stk)
860                         break;
861                 getch();
862         }
863         copyf--;
864 }
865
866 /*
867  * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
868  * (internal names), spaces and special cookies (below 040).
869  * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
870  */
871 getach(void)
872 {
873         Tchar i;
874         int j;
875
876         lgf++;
877         j = cbits(i = getch());
878         if (ismot(i)
879             || j > SHORTMASK
880             || (j <= 040 && j != 002    /*STX*/
881                         && j != 003     /*ETX*/
882                         && j != 005     /*ENQ*/
883                         && j != 006     /*ACK*/
884                         && j != 007)) { /*BELL*/
885                 ch = i;
886                 j = 0;
887         }
888         lgf--;
889         return j;
890 }
891
892
893 void casenx(void)
894 {
895         lgf++;
896         skip();
897         getname();
898         nx++;
899         if (nmfi > 0)
900                 nmfi--;
901         strcpy(mfiles[nmfi], nextf);
902         nextfile();
903         nlflg++;
904         ip = 0;
905         pendt = 0;
906         frame = stk;
907         nxf = frame + 1;
908 }
909
910
911 getname(void)
912 {
913         int j, k;
914         Tchar i;
915
916         lgf++;
917         for (k = 0; k < NS - 1; k++) {
918                 j = getach();
919                 if (!j)
920                         break;
921                 nextf[k] = j;
922         }
923         nextf[k] = 0;
924         lgf--;
925         return(nextf[0]);
926 }
927
928
929 void caseso(void)
930 {
931         FILE *fp;
932         char *p, *q;
933
934         lgf++;
935         nextf[0] = 0;
936         if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
937                 ERROR "can't open file %s", nextf WARN;
938                 done(02);
939         }
940         strcpy(cfname[ifi+1], nextf);
941         cfline[ifi] = numtabp[CD].val;          /*hold line counter*/
942         numtabp[CD].val = 0;
943         flushi();
944         ifl[ifi] = ifile;
945         ifile = fp;
946         ipl[ifi] = ip;
947         ip = 0;
948         nx++;
949         nflush++;
950         ifi++;
951 }
952
953 void caself(void)       /* set line number and file */
954 {
955         int n;
956
957         if (skip())
958                 return;
959         n = atoi0();
960         if (!nonumb)
961                 cfline[ifi] = numtabp[CD].val = n - 1;
962         if (!skip())
963                 if (getname()) {        /* eats '\n' ? */
964                         strcpy(cfname[ifi], nextf);
965                         if (!nonumb)
966                                 numtabp[CD].val--;
967                 }
968 }
969
970 void cpout(FILE *fin, char *token)
971 {
972         int n;
973         char buf[1024];
974
975         if (token) {    /* BUG: There should be no NULL bytes in input */
976                 char *newl = buf;
977                 while ((fgets(buf, sizeof buf, fin)) != NULL) {
978                         if (newl) {
979                                 numtabp[CD].val++; /* line number */
980                                 if (strcmp(token, buf) == 0)
981                                         return;
982                         }
983                         newl = strchr(buf, '\n');
984                         fputs(buf, ptid);
985                 }
986         } else {
987                 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
988                         fwrite(buf, n, 1, ptid);
989                 fclose(fin);
990         }
991 }
992
993 void casecf(void)
994 {       /* copy file without change */
995         FILE *fd;
996         char *eof, *p;
997         extern int hpos, esc, po;
998
999         /* this may not make much sense in nroff... */
1000
1001         lgf++;
1002         nextf[0] = 0;
1003         if (!skip() && getname()) {
1004                 if (strncmp("<<", nextf, 2) != 0) {
1005                         if ((fd = fopen(nextf, "r")) == NULL) {
1006                                 ERROR "can't open file %s", nextf WARN;
1007                                 done(02);
1008                         }
1009                         eof = (char *) NULL;
1010                 } else {        /* current file */
1011                         if (pbp > lastpbp || ip) {
1012                                 ERROR "casecf: not reading from file" WARN;
1013                                 done(02);
1014                         }
1015                         eof = &nextf[2];
1016                         if (!*eof)  {
1017                                 ERROR "casecf: missing end of input token" WARN;
1018                                 done(02);
1019                         }
1020                         p = eof;
1021                         while(*++p)
1022                                 ;
1023                         *p++ = '\n';
1024                         *p = 0;
1025                         fd = ifile;
1026                 }
1027         } else {
1028                 ERROR "casecf: no argument" WARN;
1029                 lgf--;
1030                 return;
1031         }
1032         lgf--;
1033
1034         /* make it into a clean state, be sure that everything is out */
1035         tbreak();
1036         hpos = po;
1037         esc = 0;
1038         ptesc();        /* to left margin */
1039         esc = un;
1040         ptesc();
1041         ptlead();
1042         ptps();
1043         ptfont();
1044         flusho();
1045         cpout(fd, eof);
1046         ptps();
1047         ptfont();
1048 }
1049
1050 void getline(char *s, int n)    /* get rest of input line into s */
1051 {
1052         int i;
1053
1054         lgf++;
1055         copyf++;
1056         skip();
1057         for (i = 0; i < n-1; i++)
1058                 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
1059                         break;
1060         s[i] = 0;
1061         copyf--;
1062         lgf--;
1063 }
1064
1065 void casesy(void)       /* call system */
1066 {
1067         char sybuf[NTM];
1068
1069         getline(sybuf, NTM);
1070         system(sybuf);
1071 }
1072
1073
1074 void getpn(char *a)
1075 {
1076         int n, neg;
1077
1078         if (*a == 0)
1079                 return;
1080         neg = 0;
1081         for ( ; *a; a++)
1082                 switch (*a) {
1083                 case '+':
1084                 case ',':
1085                         continue;
1086                 case '-':
1087                         neg = 1;
1088                         continue;
1089                 default:
1090                         n = 0;
1091                         if (isdigit(*a)) {
1092                                 do
1093                                         n = 10 * n + *a++ - '0';
1094                                 while (isdigit(*a));
1095                                 a--;
1096                         } else
1097                                 n = 9999;
1098                         *pnp++ = neg ? -n : n;
1099                         neg = 0;
1100                         if (pnp >= &pnlist[NPN-2]) {
1101                                 ERROR "too many page numbers" WARN;
1102                                 done3(-3);
1103                         }
1104                 }
1105         if (neg)
1106                 *pnp++ = -9999;
1107         *pnp = -INT_MAX;
1108         print = 0;
1109         pnp = pnlist;
1110         if (*pnp != -INT_MAX)
1111                 chkpn();
1112 }
1113
1114
1115 void setrpt(void)
1116 {
1117         Tchar i, j;
1118
1119         copyf++;
1120         raw++;
1121         i = getch0();
1122         copyf--;
1123         raw--;
1124         if ((long) i < 0 || cbits(j = getch0()) == RPT)
1125                 return;
1126         while (i > 0 && pbp < &pbbuf[NC-3]) {
1127                 i--;
1128                 *pbp++ = j;
1129         }
1130 }