initial port of plan9 troff to linux
[troff.git] / troff / n1.c
blob37333d71c604589ad64c33af2715f01606ec040c
1 /*
2 * n1.c
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 #define MAXCBYTES 6
15 #include <setjmp.h>
16 #include <time.h>
18 char *Version = "March 11, 1994";
20 #ifndef DWBVERSION
21 #define DWBVERSION "???"
22 #endif
24 char *DWBfontdir = FONTDIR;
25 char *DWBntermdir = NTERMDIR;
26 char *DWBalthyphens = ALTHYPHENS;
27 char *DWBhomedir = "";
29 dwbinit dwbpaths[] = {
30 &DWBfontdir, NULL, 0,
31 &DWBntermdir, NULL, 0,
32 &DWBalthyphens, NULL, 0,
33 &DWBhomedir, NULL, 0,
34 NULL, nextf, NS,
35 NULL, NULL, 0
38 int TROFF = 1; /* assume we started in troff... */
40 jmp_buf sjbuf;
41 Offset ipl[NSO];
43 static FILE *ifile;
44 static FILE *ifl[NSO]; /* open input file pointers */
45 char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
46 int cfline[NSO]; /* input line count stack */
47 char *progname; /* program name (troff or nroff) */
49 int trace = 0; /* tracing mode: default off */
50 int trace1 = 0;
52 int main(int argc, char *argv[])
54 char *p;
55 int j;
56 Tchar i;
57 char buf[100];
59 buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
60 ifile = stdin;
61 ptid = stdout;
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]);
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:
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
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;
216 ch = i;
217 text();
218 if (nlflg)
219 numtabp[HP].val = 0;
220 goto loop;
221 return 0;
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 long 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);
378 * table encodes some special characters, to speed up tests
379 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
382 char gchtab[NCHARS] = {
383 000,004,000,000,010,000,000,000, /* fc, ldr */
384 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
385 000,000,000,000,000,000,000,000,
386 000,001,000,001,000,000,000,000, /* FLSS, ESC */
387 000,000,000,000,000,000,000,000,
388 000,000,000,000,000,000,000,000,
389 000,000,000,000,000,000,000,000,
390 000,000,000,000,000,000,000,000,
391 000,000,000,000,000,000,000,000,
392 000,000,000,000,000,000,000,000,
393 000,000,000,000,000,000,000,000,
394 000,000,000,000,000,000,000,000,
395 000,000,000,000,000,000,001,000, /* f */
396 000,000,000,000,000,000,000,000,
397 000,000,000,000,000,000,000,000,
398 000,000,000,000,000,000,000,000,
401 int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
403 if (ismot(c))
404 return MOTCH;
405 else
406 return c & 0xFFFF;
409 Tchar getch(void)
411 int k;
412 Tchar i, j;
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 ' ': /* unpaddable space */
516 i = UNPAD;
517 goto gx;
518 case '\'': /* \(aa */
519 i = ACUTE;
520 goto gx;
521 case '`': /* \(ga */
522 i = GRAVE;
523 goto gx;
524 case '_': /* \(ul */
525 i = UNDERLINE;
526 goto gx;
527 case '-': /* current font minus */
528 i = MINUS;
529 goto gx;
530 case '&': /* filler */
531 i = FILLER;
532 goto gx;
533 case 'c': /* to be continued */
534 i = CONT;
535 goto gx;
536 case '!': /* transparent indicator */
537 i = XPAR;
538 goto gx;
539 case 't': /* tab */
540 i = '\t';
541 return(i);
542 case 'a': /* leader (SOH) */
543 /* old: *pbp++ = LEADER; goto g0; */
544 i = LEADER;
545 return i;
546 case '%': /* ohc */
547 i = OHC;
548 return(i);
549 case 'g': /* return format of a number register */
550 setaf(); /* should this really be in copy mode??? */
551 goto g0;
552 case '.': /* . */
553 i = '.';
555 setsfbits(i, sfbits(j));
556 return(i);
558 if (copyf) {
559 *pbp++ = j;
560 return(eschar);
562 switch (k) {
564 case 'f': /* font indicator */
565 setfont(0);
566 goto g0;
567 case 's': /* size indicator */
568 setps();
569 goto g0;
570 case 'v': /* vert mot */
571 numerr.type = numerr.escarg = 0; numerr.esc = k;
572 if (i = vmot()) {
573 return(i);
575 goto g0;
576 case 'h': /* horiz mot */
577 numerr.type = numerr.escarg = 0; numerr.esc = k;
578 if (i = hmot())
579 return(i);
580 goto g0;
581 case '|': /* narrow space */
582 if (NROFF)
583 goto g0;
584 return(makem((int)(EM)/6));
585 case '^': /* half narrow space */
586 if (NROFF)
587 goto g0;
588 return(makem((int)(EM)/12));
589 case 'w': /* width function */
590 setwd();
591 goto g0;
592 case 'p': /* spread */
593 spread++;
594 goto g0;
595 case 'N': /* absolute character number */
596 numerr.type = numerr.escarg = 0; numerr.esc = k;
597 if ((i = setabs()) == 0)
598 goto g0;
599 return i;
600 case 'H': /* character height */
601 numerr.type = numerr.escarg = 0; numerr.esc = k;
602 return(setht());
603 case 'S': /* slant */
604 numerr.type = numerr.escarg = 0; numerr.esc = k;
605 return(setslant());
606 case 'z': /* zero with char */
607 return(setz());
608 case 'l': /* hor line */
609 numerr.type = numerr.escarg = 0; numerr.esc = k;
610 setline();
611 goto g0;
612 case 'L': /* vert line */
613 numerr.type = numerr.escarg = 0; numerr.esc = k;
614 setvline();
615 goto g0;
616 case 'D': /* drawing function */
617 numerr.type = numerr.escarg = 0; numerr.esc = k;
618 setdraw();
619 goto g0;
620 case 'X': /* \X'...' for copy through */
621 setxon();
622 goto g0;
623 case 'b': /* bracket */
624 setbra();
625 goto g0;
626 case 'o': /* overstrike */
627 setov();
628 goto g0;
629 case 'k': /* mark hor place */
630 if ((k = findr(getsn())) != -1) {
631 numtabp[k].val = numtabp[HP].val;
633 goto g0;
634 case '0': /* number space */
635 return(makem(width('0' | chbits)));
636 case 'x': /* extra line space */
637 numerr.type = numerr.escarg = 0; numerr.esc = k;
638 if (i = xlss())
639 return(i);
640 goto g0;
641 case 'u': /* half em up */
642 case 'r': /* full em up */
643 case 'd': /* half em down */
644 return(sethl(k));
645 default:
646 return(j);
648 /* NOTREACHED */
651 void setxon(void) /* \X'...' for copy through */
653 Tchar xbuf[NC];
654 Tchar *i;
655 Tchar c;
656 int delim, k;
658 if (ismot(c = getch()))
659 return;
660 delim = cbits(c);
661 i = xbuf;
662 *i++ = XON | chbits;
663 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
664 if (k == ' ')
665 setcbits(c, WORDSP);
666 *i++ = c | ZBIT;
668 *i++ = XOFF | chbits;
669 *i = 0;
670 pushback(xbuf);
674 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
676 Tchar getch0(void)
678 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) {
702 if (nextfile()) {
703 if (ip)
704 goto again;
707 nx = 0;
708 #ifdef UNICODE
709 if (MAXCBYTES > 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 if (i >= 040) /* zapped: && i < 0177 */
720 goto g4;
721 i = ifilt[i];
723 if (cbits(i) == IMP && !raw)
724 goto again;
725 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
726 goto again;
729 if (ismot(i))
730 return i;
731 if (copyf == 0 && sfbits(i) == 0)
732 i |= chbits;
733 if (cbits(i) == eschar && !raw)
734 setcbits(i, ESC);
735 return(i);
738 #ifdef UNICODE
739 int readutf8(int *dst, char *src)
741 int l = 1;
742 char *s = src;
743 if (~*s & 0xc0) {
744 *dst = *s;
745 return 1;
747 while (l < 6 && *s & (0x40 >> l))
748 l++;
749 *dst = (0x3f >> l) & *s++;
750 while (l--)
751 *dst = (*dst << 6) | (*s++ & 0x3f);
752 return s - src;
755 static int utf8len(int c)
757 int l = 1;
758 if (~c & 0xc0)
759 return 1;
760 while (l < 6 && c & (0x40 >> l))
761 l++;
762 return l + 1;
765 /* get one "character" from input, figure out what alphabet */
766 Tchar get1ch(FILE *fp)
768 int wc;
769 char buf[100];
770 int i, n, c;
772 c = getc(fp);
773 n = utf8len(c);
774 if (c == EOF || n == 1)
775 return c;
776 buf[0] = c;
777 for (i = 1; i < n; i++)
778 buf[i] = getc(fp);
779 buf[n] = '\0';
780 readutf8(&wc, buf);
781 /* add name even if haven't seen it */
782 return chadd(buf, MBchar, Install);
784 #endif /*UNICODE*/
786 void pushback(Tchar *b)
788 Tchar *ob = b;
790 while (*b++)
792 b--;
793 while (b > ob && pbp < &pbbuf[NC-3])
794 *pbp++ = *--b;
795 if (pbp >= &pbbuf[NC-3]) {
796 ERROR "pushback overflow" WARN;
797 done(2);
801 void cpushback(char *b)
803 char *ob = b;
805 while (*b++)
807 b--;
808 while (b > ob && pbp < &pbbuf[NC-3])
809 *pbp++ = *--b;
810 if (pbp >= &pbbuf[NC-3]) {
811 ERROR "cpushback overflow" WARN;
812 done(2);
816 int nextfile(void)
818 char *p;
821 if (ifile != stdin)
822 fclose(ifile);
823 if (ifi > 0 && !nx) {
824 if (popf())
825 goto n0; /* popf error */
826 return(1); /* popf ok */
828 if (nx || nmfi < mflg) {
829 p = mfiles[nmfi++];
830 if (*p != 0)
831 goto n1;
833 if (rargc-- <= 0) {
834 if ((nfo -= mflg) && !stdi) {
835 done(0);
837 nfo++;
838 numtabp[CD].val = stdi = mflg = 0;
839 ifile = stdin;
840 strcpy(cfname[ifi], "stdin");
841 return(0);
843 p = (argp++)[0];
844 if (rargc >= 0)
845 cfname[ifi][0] = 0;
847 numtabp[CD].val = 0;
848 if (p[0] == '-' && p[1] == 0) {
849 ifile = stdin;
850 strcpy(cfname[ifi], "stdin");
851 } else if ((ifile = fopen(p, "r")) == NULL) {
852 ERROR "cannot open file %s", p WARN;
853 nfo -= mflg;
854 done(02);
855 } else
856 strcpy(cfname[ifi],p);
857 nfo++;
858 return(0);
862 popf(void)
864 --ifi;
865 if (ifi < 0) {
866 ERROR "popf went negative" WARN;
867 return 1;
869 numtabp[CD].val = cfline[ifi]; /* restore line counter */
870 ip = ipl[ifi]; /* input pointer */
871 ifile = ifl[ifi]; /* input FILE * */
872 return(0);
876 void flushi(void)
878 if (nflush)
879 return;
880 ch = 0;
881 copyf++;
882 while (!nlflg) {
883 if (donef && frame == stk)
884 break;
885 getch();
887 copyf--;
891 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
892 * (internal names), spaces and special cookies (below 040).
893 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
895 int getach(void)
897 Tchar i;
898 int j;
900 lgf++;
901 j = cbits(i = getch());
902 if (ismot(i) || j > SHORTMASK
903 || (j <= 040 && j != 002 /*STX*/
904 && j != 003 /*ETX*/
905 && j != 005 /*ENQ*/
906 && j != 006 /*ACK*/
907 && j != 007)) { /*BELL*/
908 ch = i;
909 j = 0;
911 lgf--;
912 return j;
916 void casenx(void)
918 lgf++;
919 skip();
920 getname();
921 nx++;
922 if (nmfi > 0)
923 nmfi--;
924 strcpy(mfiles[nmfi], nextf);
925 nextfile();
926 nlflg++;
927 ip = 0;
928 pendt = 0;
929 frame = stk;
930 nxf = frame + 1;
934 int getname(void)
936 int j, k;
938 lgf++;
939 for (k = 0; k < NS - 1; k++) {
940 j = getach();
941 if (!j)
942 break;
943 nextf[k] = j;
945 nextf[k] = 0;
946 lgf--;
947 return nextf[0];
951 void caseso(void)
953 FILE *fp;
955 lgf++;
956 nextf[0] = 0;
957 if (skip() || !getname() || (fp = fopen(nextf, "r")) == NULL || ifi >= NSO) {
958 ERROR "can't open file %s", nextf WARN;
959 done(02);
961 strcpy(cfname[ifi+1], nextf);
962 cfline[ifi] = numtabp[CD].val; /*hold line counter*/
963 numtabp[CD].val = 0;
964 flushi();
965 ifl[ifi] = ifile;
966 ifile = fp;
967 ipl[ifi] = ip;
968 ip = 0;
969 nx++;
970 nflush++;
971 ifi++;
974 void caself(void) /* set line number and file */
976 int n;
978 if (skip())
979 return;
980 n = atoi0();
981 if (!nonumb)
982 cfline[ifi] = numtabp[CD].val = n - 1;
983 if (!skip())
984 if (getname()) { /* eats '\n' ? */
985 strcpy(cfname[ifi], nextf);
986 if (!nonumb)
987 numtabp[CD].val--;
991 void cpout(FILE *fin, char *token)
993 int n;
994 char buf[1024];
996 if (token) { /* BUG: There should be no NULL bytes in input */
997 char *newl = buf;
998 while ((fgets(buf, sizeof buf, fin)) != NULL) {
999 if (newl) {
1000 numtabp[CD].val++; /* line number */
1001 if (strcmp(token, buf) == 0)
1002 return;
1004 newl = strchr(buf, '\n');
1005 fputs(buf, ptid);
1007 } else {
1008 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
1009 fwrite(buf, n, 1, ptid);
1010 fclose(fin);
1014 void casecf(void)
1015 { /* copy file without change */
1016 FILE *fd;
1017 char *eof, *p;
1018 extern int hpos, esc, po;
1020 /* this may not make much sense in nroff... */
1022 lgf++;
1023 nextf[0] = 0;
1024 if (!skip() && getname()) {
1025 if (strncmp("<<", nextf, 2) != 0) {
1026 if ((fd = fopen(nextf, "r")) == NULL) {
1027 ERROR "can't open file %s", nextf WARN;
1028 done(02);
1030 eof = (char *) NULL;
1031 } else { /* current file */
1032 if (pbp > lastpbp || ip) {
1033 ERROR "casecf: not reading from file" WARN;
1034 done(02);
1036 eof = &nextf[2];
1037 if (!*eof) {
1038 ERROR "casecf: missing end of input token" WARN;
1039 done(02);
1041 p = eof;
1042 while(*++p)
1044 *p++ = '\n';
1045 *p = 0;
1046 fd = ifile;
1048 } else {
1049 ERROR "casecf: no argument" WARN;
1050 lgf--;
1051 return;
1053 lgf--;
1055 /* make it into a clean state, be sure that everything is out */
1056 tbreak();
1057 hpos = po;
1058 esc = 0;
1059 ptesc(); /* to left margin */
1060 esc = un;
1061 ptesc();
1062 ptlead();
1063 ptps();
1064 ptfont();
1065 flusho();
1066 cpout(fd, eof);
1067 ptps();
1068 ptfont();
1071 void getline(char *s, int n) /* get rest of input line into s */
1073 int i;
1075 lgf++;
1076 copyf++;
1077 skip();
1078 for (i = 0; i < n-1; i++)
1079 if ((s[i] = cbits(getch())) == '\n' || s[i] == RIGHT)
1080 break;
1081 s[i] = 0;
1082 copyf--;
1083 lgf--;
1086 void casesy(void) /* call system */
1088 char sybuf[NTM];
1090 getline(sybuf, NTM);
1091 system(sybuf);
1095 void getpn(char *a)
1097 int n, neg;
1099 if (*a == 0)
1100 return;
1101 neg = 0;
1102 for ( ; *a; a++)
1103 switch (*a) {
1104 case '+':
1105 case ',':
1106 continue;
1107 case '-':
1108 neg = 1;
1109 continue;
1110 default:
1111 n = 0;
1112 if (isdigit(*a)) {
1114 n = 10 * n + *a++ - '0';
1115 while (isdigit(*a));
1116 a--;
1117 } else
1118 n = 9999;
1119 *pnp++ = neg ? -n : n;
1120 neg = 0;
1121 if (pnp >= &pnlist[NPN-2]) {
1122 ERROR "too many page numbers" WARN;
1123 done3(-3);
1126 if (neg)
1127 *pnp++ = -9999;
1128 *pnp = -INT_MAX;
1129 print = 0;
1130 pnp = pnlist;
1131 if (*pnp != -INT_MAX)
1132 chkpn();
1136 void setrpt(void)
1138 Tchar i, j;
1140 copyf++;
1141 raw++;
1142 i = getch0();
1143 copyf--;
1144 raw--;
1145 if ((long) i < 0 || cbits(j = getch0()) == RPT)
1146 return;
1147 while (i > 0 && pbp < &pbbuf[NC-3]) {
1148 i--;
1149 *pbp++ = j;