Blob


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