mkdev: remove devutf/C*
[troff.git] / troff / n1.c
blob51a1f9a16db57f4c1e46d94075a81c90cc95027b
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"
12 #define MAXCBYTES 6
14 #include <setjmp.h>
15 #include <time.h>
17 char *Version = "March 11, 1994";
19 int TROFF = 1; /* assume we started in troff... */
21 jmp_buf sjbuf;
22 Offset ipl[NSO];
24 static FILE *ifile;
25 static FILE *ifl[NSO]; /* open input file pointers */
26 char cfname[NSO+1][NS] = { "stdin" }; /* file name stack */
27 int cfline[NSO]; /* input line count stack */
28 char *progname; /* program name (troff or nroff) */
30 int trace = 0; /* tracing mode: default off */
31 int trace1 = 0;
33 int main(int argc, char *argv[])
35 char *p;
36 int j;
37 Tchar i;
38 char buf[100];
40 buf[0] = '\0'; /* make sure it's empty (silly 3b2) */
41 ifile = stdin;
42 ptid = stdout;
43 progname = argv[0];
44 if ((p = strrchr(progname, '/')) == NULL)
45 p = progname;
46 else
47 p++;
48 if (strcmp(p, "nroff") == 0)
49 TROFF = 0;
50 #ifdef UNICODE
51 alphabet = 128; /* unicode for plan 9 */
52 #endif /*UNICODE*/
53 mnspace();
54 nnspace();
55 mrehash();
56 nrehash();
57 numtabp[NL].val = -1;
59 while (--argc > 0 && (++argv)[0][0] == '-')
60 switch (argv[0][1]) {
62 case 'N': /* ought to be used first... */
63 TROFF = 0;
64 break;
65 case 'd':
66 fprintf(stderr, "troff/nroff version %s\n", Version);
67 break;
68 case 'F': /* switch font tables from default */
69 if (argv[0][2] != '\0') {
70 strcpy(termtab, &argv[0][2]);
71 strcpy(fontdir, &argv[0][2]);
72 } else {
73 argv++; argc--;
74 strcpy(termtab, argv[0]);
75 strcpy(fontdir, argv[0]);
77 break;
78 case 0:
79 goto start;
80 case 'i':
81 stdi++;
82 break;
83 case 'n':
84 npn = atoi(&argv[0][2]);
85 break;
86 case 'u': /* set emboldening amount */
87 bdtab[3] = atoi(&argv[0][2]);
88 if (bdtab[3] < 0 || bdtab[3] > 50)
89 bdtab[3] = 0;
90 break;
91 case 's':
92 if (!(stop = atoi(&argv[0][2])))
93 stop++;
94 break;
95 case 'r':
96 sprintf(buf + strlen(buf), ".nr %c %s\n",
97 argv[0][2], &argv[0][3]);
98 /* not yet cpushback(buf);*/
99 /* dotnr(&argv[0][2], &argv[0][3]); */
100 break;
101 case 'm':
102 if (mflg++ >= NMF) {
103 ERROR "Too many macro packages: %s", argv[0] WARN;
104 break;
106 strcpy(mfiles[nmfi], nextf);
107 strcat(mfiles[nmfi++], &argv[0][2]);
108 break;
109 case 'o':
110 getpn(&argv[0][2]);
111 break;
112 case 'T':
113 strcpy(devname, &argv[0][2]);
114 dotT++;
115 break;
116 case 'a':
117 ascii = 1;
118 break;
119 case 'h':
120 hflg++;
121 break;
122 case 'e':
123 eqflg++;
124 break;
125 case 'q':
126 quiet++;
127 save_tty();
128 break;
129 case 'V':
130 fprintf(stdout, "%croff\n", TROFF ? 't' : 'n');
131 exit(0);
132 case 't':
133 if (argv[0][2] != '\0')
134 trace = trace1 = argv[0][2];
135 break; /* for the sake of compatibility */
136 default:
137 ERROR "unknown option %s", argv[0] WARN;
138 done(02);
141 start:
143 * cpushback maintains a LIFO, so push pack the -r arguments
144 * in reverse order to maintain a FIFO in case someone did -rC1 -rC3
146 if (buf[0]) {
147 char *p = buf;
148 while(*p++)
150 while(p > buf) {
151 while(strncmp(p, ".nr", 3) != 0)
152 p--;
153 cpushback(p);
154 *p-- = '\0';
157 argp = argv;
158 rargc = argc;
159 nmfi = 0;
160 init2();
161 setjmp(sjbuf);
162 loop:
163 copyf = lgf = nb = nflush = nlflg = 0;
164 if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl && dip == d) {
165 nflush++;
166 trap = 0;
167 eject((Stack *)0);
168 goto loop;
170 i = getch();
171 if (pendt)
172 goto Lt;
173 if ((j = cbits(i)) == XPAR) {
174 copyf++;
175 tflg++;
176 while (cbits(i) != '\n')
177 pchar(i = getch());
178 tflg = 0;
179 copyf--;
180 goto loop;
182 if (j == cc || j == c2) {
183 if (j == c2)
184 nb++;
185 copyf++;
186 while ((j = cbits(i = getch())) == ' ' || j == '\t')
188 ch = i;
189 copyf--;
190 control(getrq(), 1);
191 flushi();
192 goto loop;
195 ch = i;
196 text();
197 if (nlflg)
198 numtabp[HP].val = 0;
199 goto loop;
200 return 0;
205 void init2(void)
207 int i;
208 char buf[100];
210 for (i = NTRTAB; --i; )
211 trtab[i] = i;
212 trtab[UNPAD] = ' ';
213 iflg = 0;
214 obufp = obuf;
215 if (TROFF)
216 t_ptinit();
217 else
218 n_ptinit();
219 mchbits();
220 cvtime();
221 numtabp[PID].val = getpid();
222 numtabp[HP].val = init = 0;
223 numtabp[NL].val = -1;
224 nfo = 0;
225 copyf = raw = 0;
226 sprintf(buf, ".ds .T %s\n", devname);
227 cpushback(buf);
228 sprintf(buf, ".ds .P %s\n", TBASE);
229 cpushback(buf);
230 numtabp[CD].val = -1; /* compensation */
231 nx = mflg;
232 frame = stk = (Stack *)setbrk(STACKSIZE);
233 dip = &d[0];
234 nxf = frame + 1;
235 for (i = 1; i < NEV; i++) /* propagate the environment */
236 envcopy(&env[i], &env[0]);
237 for (i = 0; i < NEV; i++) {
238 if ((env[i]._word._bufp = (Tchar *)calloc(WDSIZE, sizeof(Tchar))) == NULL) {
239 ERROR "not enough room for word buffers" WARN;
240 done2(1);
242 env[i]._word._size = WDSIZE;
243 if ((env[i]._line._bufp = (Tchar *)calloc(LNSIZE, sizeof(Tchar))) == NULL) {
244 ERROR "not enough room for line buffers" WARN;
245 done2(1);
247 env[i]._line._size = LNSIZE;
249 if ((oline = (Tchar *)calloc(OLNSIZE, sizeof(Tchar))) == NULL) {
250 ERROR "not enough room for line buffers" WARN;
251 done2(1);
253 olinep = oline;
254 olnsize = OLNSIZE;
255 blockinit();
258 void cvtime(void)
260 long tt;
261 struct tm *ltime;
263 time(&tt);
264 ltime = localtime(&tt);
265 numtabp[YR].val = ltime->tm_year % 100;
266 numtabp[YR].fmt = 2;
267 numtabp[MO].val = ltime->tm_mon + 1; /* troff uses 1..12 */
268 numtabp[DY].val = ltime->tm_mday;
269 numtabp[DW].val = ltime->tm_wday + 1; /* troff uses 1..7 */
274 char errbuf[200];
276 void errprint(void) /* error message printer */
278 int savecd = numtabp[CD].val;
280 if (!nlflg)
281 numtabp[CD].val++;
283 fprintf(stderr, "%s: ", progname);
284 fputs(errbuf, stderr);
285 if (cfname[ifi][0])
286 fprintf(stderr, "; %s:%d", cfname[ifi], numtabp[CD].val);
287 fputs("\n", stderr);
288 if (cfname[ifi][0])
289 stackdump();
290 numtabp[CD].val = savecd;
294 int control(int a, int b)
296 int j, k;
297 extern Contab *contabp;
299 numerr.type = RQERR;
300 numerr.req = a;
301 if (a == 0 || (j = findmn(a)) == -1)
302 return(0);
303 if (contabp[j].f == 0) {
304 if (trace & TRMAC)
305 fprintf(stderr, "invoke macro %s\n", unpair(a));
306 if (dip != d)
307 for (k = dilev; k; k--)
308 if (d[k].curd == a) {
309 ERROR "diversion %s invokes itself during diversion",
310 unpair(a) WARN;
311 edone(0100);
313 nxf->nargs = 0;
314 if (b)
315 collect();
316 flushi();
317 return pushi(contabp[j].mx, a); /* BUG??? all that matters is 0/!0 */
319 if (b) {
320 if (trace & TRREQ)
321 fprintf(stderr, "invoke request %s\n", unpair(a));
322 (*contabp[j].f)();
324 return(0);
327 void casept(void)
329 int i;
331 noscale++;
332 if (skip())
333 i = trace1;
334 else {
335 i = max(inumb(&trace), 0);
336 if (nonumb)
337 i = trace1;
339 trace1 = trace;
340 trace = i;
341 noscale = 0;
345 int getrq(void)
347 int i, j;
349 if ((i = getach()) == 0 || (j = getach()) == 0)
350 goto rtn;
351 i = PAIR(i, j);
352 rtn:
353 return(i);
357 * table encodes some special characters, to speed up tests
358 * in getch, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
361 char gchtab[NCHARS] = {
362 000,004,000,000,010,000,000,000, /* fc, ldr */
363 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
364 000,000,000,000,000,000,000,000,
365 000,001,000,001,000,000,000,000, /* FLSS, ESC */
366 000,000,000,000,000,000,000,000,
367 000,000,000,000,000,000,000,000,
368 000,000,000,000,000,000,000,000,
369 000,000,000,000,000,000,000,000,
370 000,000,000,000,000,000,000,000,
371 000,000,000,000,000,000,000,000,
372 000,000,000,000,000,000,000,000,
373 000,000,000,000,000,000,000,000,
374 000,000,000,000,000,000,001,000, /* f */
375 000,000,000,000,000,000,000,000,
376 000,000,000,000,000,000,000,000,
377 000,000,000,000,000,000,000,000,
380 int realcbits(Tchar c) /* return character bits, or MOTCH if motion */
382 if (ismot(c))
383 return MOTCH;
384 else
385 return c & 0xFFFF;
388 Tchar getch(void)
390 int k;
391 Tchar i, j;
394 if (ch) {
395 i = ch;
396 if (cbits(i) == '\n')
397 nlflg++;
398 ch = 0;
399 return(i);
402 if (nlflg)
403 return('\n');
404 i = getch0();
405 if (ismot(i))
406 return(i);
407 k = cbits(i);
408 if (k >= sizeof(gchtab)/sizeof(gchtab[0]) || gchtab[k] == 0) /* nothing special */
409 return(i);
410 if (k != ESC) {
411 if (k == '\n') {
412 nlflg++;
413 if (ip == 0)
414 numtabp[CD].val++; /* line number */
415 return(k);
417 if (k == FLSS) {
418 copyf++;
419 raw++;
420 i = getch0();
421 if (!fi)
422 flss = i;
423 copyf--;
424 raw--;
425 goto g0;
427 if (k == RPT) {
428 setrpt();
429 goto g0;
431 if (!copyf) {
432 if (k == 'f' && lg && !lgf) {
433 i = getlg(i);
434 return(i);
436 if (k == fc || k == tabch || k == ldrch) {
437 if ((i = setfield(k)) == 0)
438 goto g0;
439 else
440 return(i);
442 if (k == '\b') {
443 i = makem(-width(' ' | chbits));
444 return(i);
447 return(i);
450 k = cbits(j = getch0());
451 if (ismot(j))
452 return(j);
454 switch (k) {
455 case 'n': /* number register */
456 setn();
457 goto g0;
458 case '$': /* argument indicator */
459 seta();
460 goto g0;
461 case '*': /* string indicator */
462 setstr();
463 goto g0;
464 case '{': /* LEFT */
465 i = LEFT;
466 goto gx;
467 case '}': /* RIGHT */
468 i = RIGHT;
469 goto gx;
470 case '"': /* comment */
471 while (cbits(i = getch0()) != '\n')
473 if (ip == 0)
474 numtabp[CD].val++; /* line number */
475 nlflg++;
476 return(i);
478 /* experiment: put it here instead of copy mode */
479 case '(': /* special char name \(xx */
480 case 'C': /* \C'...' */
481 if ((i = setch(k)) == 0)
482 goto g0;
483 goto gx;
485 case ESC: /* double backslash */
486 i = eschar;
487 goto gx;
488 case 'e': /* printable version of current eschar */
489 i = PRESC;
490 goto gx;
491 case '\n': /* concealed newline */
492 numtabp[CD].val++;
493 goto g0;
494 case ' ': /* unpaddable space */
495 i = UNPAD;
496 goto gx;
497 case '\'': /* \(aa */
498 i = ACUTE;
499 goto gx;
500 case '`': /* \(ga */
501 i = GRAVE;
502 goto gx;
503 case '_': /* \(ul */
504 i = UNDERLINE;
505 goto gx;
506 case '-': /* current font minus */
507 i = MINUS;
508 goto gx;
509 case '&': /* filler */
510 i = FILLER;
511 goto gx;
512 case 'c': /* to be continued */
513 i = CONT;
514 goto gx;
515 case '!': /* transparent indicator */
516 i = XPAR;
517 goto gx;
518 case 't': /* tab */
519 i = '\t';
520 return(i);
521 case 'a': /* leader (SOH) */
522 /* old: *pbp++ = LEADER; goto g0; */
523 i = LEADER;
524 return i;
525 case '%': /* ohc */
526 i = OHC;
527 return(i);
528 case 'g': /* return format of a number register */
529 setaf(); /* should this really be in copy mode??? */
530 goto g0;
531 case '.': /* . */
532 i = '.';
534 setsfbits(i, sfbits(j));
535 return(i);
537 if (copyf) {
538 *pbp++ = j;
539 return(eschar);
541 switch (k) {
543 case 'f': /* font indicator */
544 setfont(0);
545 goto g0;
546 case 's': /* size indicator */
547 setps();
548 goto g0;
549 case 'v': /* vert mot */
550 numerr.type = numerr.escarg = 0; numerr.esc = k;
551 if (i = vmot()) {
552 return(i);
554 goto g0;
555 case 'h': /* horiz mot */
556 numerr.type = numerr.escarg = 0; numerr.esc = k;
557 if (i = hmot())
558 return(i);
559 goto g0;
560 case '|': /* narrow space */
561 if (NROFF)
562 goto g0;
563 return(makem((int)(EM)/6));
564 case '^': /* half narrow space */
565 if (NROFF)
566 goto g0;
567 return(makem((int)(EM)/12));
568 case 'w': /* width function */
569 setwd();
570 goto g0;
571 case 'p': /* spread */
572 spread++;
573 goto g0;
574 case 'N': /* absolute character number */
575 numerr.type = numerr.escarg = 0; numerr.esc = k;
576 if ((i = setabs()) == 0)
577 goto g0;
578 return i;
579 case 'H': /* character height */
580 numerr.type = numerr.escarg = 0; numerr.esc = k;
581 return(setht());
582 case 'S': /* slant */
583 numerr.type = numerr.escarg = 0; numerr.esc = k;
584 return(setslant());
585 case 'z': /* zero with char */
586 return(setz());
587 case 'l': /* hor line */
588 numerr.type = numerr.escarg = 0; numerr.esc = k;
589 setline();
590 goto g0;
591 case 'L': /* vert line */
592 numerr.type = numerr.escarg = 0; numerr.esc = k;
593 setvline();
594 goto g0;
595 case 'D': /* drawing function */
596 numerr.type = numerr.escarg = 0; numerr.esc = k;
597 setdraw();
598 goto g0;
599 case 'X': /* \X'...' for copy through */
600 setxon();
601 goto g0;
602 case 'b': /* bracket */
603 setbra();
604 goto g0;
605 case 'o': /* overstrike */
606 setov();
607 goto g0;
608 case 'k': /* mark hor place */
609 if ((k = findr(getsn())) != -1) {
610 numtabp[k].val = numtabp[HP].val;
612 goto g0;
613 case '0': /* number space */
614 return(makem(width('0' | chbits)));
615 case 'x': /* extra line space */
616 numerr.type = numerr.escarg = 0; numerr.esc = k;
617 if (i = xlss())
618 return(i);
619 goto g0;
620 case 'u': /* half em up */
621 case 'r': /* full em up */
622 case 'd': /* half em down */
623 return(sethl(k));
624 default:
625 return(j);
627 /* NOTREACHED */
630 void setxon(void) /* \X'...' for copy through */
632 Tchar xbuf[NC];
633 Tchar *i;
634 Tchar c;
635 int delim, k;
637 if (ismot(c = getch()))
638 return;
639 delim = cbits(c);
640 i = xbuf;
641 *i++ = XON | chbits;
642 while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
643 if (k == ' ')
644 setcbits(c, WORDSP);
645 *i++ = c | ZBIT;
647 *i++ = XOFF | chbits;
648 *i = 0;
649 pushback(xbuf);
653 char ifilt[32] = { 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012 };
655 Tchar getch0(void)
657 Tchar i;
658 again:
659 if (pbp > lastpbp)
660 i = *--pbp;
661 else if (ip) {
662 /* i = rbf(); */
663 i = rbf0(ip);
664 if (i == 0)
665 i = rbf();
666 else {
667 ++ip;
668 if (pastend(ip)) {
669 --ip;
670 rbf();
673 } else {
674 if (donef || ndone)
675 done(0);
676 if (nx || 1) { /* BUG: was ibufp >= eibuf, so EOF test is wrong */
677 if (nfo < 0)
678 ERROR "in getch0, nfo = %d", nfo WARN;
679 if (nfo == 0) {
681 if (nextfile()) {
682 if (ip)
683 goto again;
686 nx = 0;
687 #ifdef UNICODE
688 if (MAXCBYTES > 1)
689 i = get1ch(ifile);
690 else
691 #endif /*UNICODE*/
692 i = getc(ifile);
693 if (i == EOF)
694 goto g0;
695 if (ip)
696 goto again;
698 if (i >= 040) /* zapped: && i < 0177 */
699 goto g4;
700 i = ifilt[i];
702 if (cbits(i) == IMP && !raw)
703 goto again;
704 if (i == 0 && !init && !raw) { /* zapped: || i == 0177 */
705 goto again;
708 if (ismot(i))
709 return i;
710 if (copyf == 0 && sfbits(i) == 0)
711 i |= chbits;
712 if (cbits(i) == eschar && !raw)
713 setcbits(i, ESC);
714 return(i);
717 #ifdef UNICODE
718 int readutf8(int *dst, char *src)
720 int l = 1;
721 char *s = src;
722 if (~*s & 0xc0) {
723 *dst = *s;
724 return 1;
726 while (l < 6 && *s & (0x40 >> l))
727 l++;
728 *dst = (0x3f >> l) & *s++;
729 while (l--)
730 *dst = (*dst << 6) | (*s++ & 0x3f);
731 return s - src;
734 static int utf8len(int c)
736 int l = 1;
737 if (~c & 0xc0)
738 return 1;
739 while (l < 6 && c & (0x40 >> l))
740 l++;
741 return l + 1;
744 /* get one "character" from input, figure out what alphabet */
745 Tchar get1ch(FILE *fp)
747 int wc;
748 char buf[100];
749 int i, n, c;
751 c = getc(fp);
752 n = utf8len(c);
753 if (c == EOF || n == 1)
754 return c;
755 buf[0] = c;
756 for (i = 1; i < n; i++)
757 buf[i] = getc(fp);
758 buf[n] = '\0';
759 readutf8(&wc, buf);
760 /* add name even if haven't seen it */
761 return chadd(buf, MBchar, Install);
763 #endif /*UNICODE*/
765 void pushback(Tchar *b)
767 Tchar *ob = b;
769 while (*b++)
771 b--;
772 while (b > ob && pbp < &pbbuf[NC-3])
773 *pbp++ = *--b;
774 if (pbp >= &pbbuf[NC-3]) {
775 ERROR "pushback overflow" WARN;
776 done(2);
780 void cpushback(char *b)
782 char *ob = b;
784 while (*b++)
786 b--;
787 while (b > ob && pbp < &pbbuf[NC-3])
788 *pbp++ = *--b;
789 if (pbp >= &pbbuf[NC-3]) {
790 ERROR "cpushback overflow" WARN;
791 done(2);
795 int nextfile(void)
797 char *p;
800 if (ifile != stdin)
801 fclose(ifile);
802 if (ifi > 0 && !nx) {
803 if (popf())
804 goto n0; /* popf error */
805 return(1); /* popf ok */
807 if (nx || nmfi < mflg) {
808 p = mfiles[nmfi++];
809 if (*p != 0)
810 goto n1;
812 if (rargc-- <= 0) {
813 if ((nfo -= mflg) && !stdi) {
814 done(0);
816 nfo++;
817 numtabp[CD].val = stdi = mflg = 0;
818 ifile = stdin;
819 strcpy(cfname[ifi], "stdin");
820 return(0);
822 p = (argp++)[0];
823 if (rargc >= 0)
824 cfname[ifi][0] = 0;
826 numtabp[CD].val = 0;
827 if (p[0] == '-' && p[1] == 0) {
828 ifile = stdin;
829 strcpy(cfname[ifi], "stdin");
830 } else if ((ifile = fopen(p, "r")) == NULL) {
831 ERROR "cannot open file %s", p WARN;
832 nfo -= mflg;
833 done(02);
834 } else
835 strcpy(cfname[ifi],p);
836 nfo++;
837 return(0);
841 int popf(void)
843 --ifi;
844 if (ifi < 0) {
845 ERROR "popf went negative" WARN;
846 return 1;
848 numtabp[CD].val = cfline[ifi]; /* restore line counter */
849 ip = ipl[ifi]; /* input pointer */
850 ifile = ifl[ifi]; /* input FILE * */
851 return 0;
855 void flushi(void)
857 if (nflush)
858 return;
859 ch = 0;
860 copyf++;
861 while (!nlflg) {
862 if (donef && frame == stk)
863 break;
864 getch();
866 copyf--;
870 * return 16-bit, ascii/alphabetic character, ignore chars with more bits,
871 * (internal names), spaces and special cookies (below 040).
872 * Leave STX ETX ENQ ACK and BELL in to maintain compatibility with v7 troff.
874 int getach(void)
876 Tchar i;
877 int j;
879 lgf++;
880 j = cbits(i = getch());
881 if (ismot(i) || j > SHORTMASK
882 || (j <= 040 && j != 002 /*STX*/
883 && j != 003 /*ETX*/
884 && j != 005 /*ENQ*/
885 && j != 006 /*ACK*/
886 && j != 007)) { /*BELL*/
887 ch = i;
888 j = 0;
890 lgf--;
891 return j;
895 void casenx(void)
897 lgf++;
898 skip();
899 getname();
900 nx++;
901 if (nmfi > 0)
902 nmfi--;
903 strcpy(mfiles[nmfi], nextf);
904 nextfile();
905 nlflg++;
906 ip = 0;
907 pendt = 0;
908 frame = stk;
909 nxf = frame + 1;
913 int getname(void)
915 int j, k;
917 lgf++;
918 for (k = 0; k < NS - 1; k++) {
919 j = getach();
920 if (!j)
921 break;
922 nextf[k] = j;
924 nextf[k] = 0;
925 lgf--;
926 return nextf[0];
930 void caseso(void)
932 FILE *fp = NULL;
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);
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++;
953 void caself(void) /* set line number and file */
955 int n;
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--;
970 void cpout(FILE *fin, char *token)
972 int n;
973 char buf[1024];
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;
983 newl = strchr(buf, '\n');
984 fputs(buf, ptid);
986 } else {
987 while ((n = fread(buf, sizeof *buf, sizeof buf, fin)) > 0)
988 fwrite(buf, n, 1, ptid);
989 fclose(fin);
993 void casecf(void)
994 { /* copy file without change */
995 FILE *fd;
996 char *eof, *p;
997 extern int hpos, esc, po;
999 /* this may not make much sense in nroff... */
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);
1009 eof = (char *) NULL;
1010 } else { /* current file */
1011 if (pbp > lastpbp || ip) {
1012 ERROR "casecf: not reading from file" WARN;
1013 done(02);
1015 eof = &nextf[2];
1016 if (!*eof) {
1017 ERROR "casecf: missing end of input token" WARN;
1018 done(02);
1020 p = eof;
1021 while(*++p)
1023 *p++ = '\n';
1024 *p = 0;
1025 fd = ifile;
1027 } else {
1028 ERROR "casecf: no argument" WARN;
1029 lgf--;
1030 return;
1032 lgf--;
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();
1050 void getline(char *s, int n) /* get rest of input line into s */
1052 int i;
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--;
1065 void casesy(void) /* call system */
1067 char sybuf[NTM];
1069 getline(sybuf, NTM);
1070 system(sybuf);
1074 void getpn(char *a)
1076 int n, neg;
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)) {
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);
1105 if (neg)
1106 *pnp++ = -9999;
1107 *pnp = -INT_MAX;
1108 print = 0;
1109 pnp = pnlist;
1110 if (*pnp != -INT_MAX)
1111 chkpn();
1115 void setrpt(void)
1117 Tchar i, j;
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;