1 #ifndef lint
2 static char sccsid[] = "@(#)n1.c	2.2 (CWI) 88/03/31";
3 #endif lint
4 /*
5  * n1.c
6  *
7  *	consume options, initialization, main loop,
8  *	input routines, escape function calling
9  */
10 
11 #include <ctype.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <setjmp.h>
16 #include <sgtty.h>
17 
18 #include "tdef.h"
19 #include "ext.h"
20 
21 #include	<time.h>	/* See cvtime() (jaap) */
22 
23 #ifdef NROFF
24 #include "tw.h"
25 #endif
26 
27 jmp_buf sjbuf;
28 extern	char	*sprintf();
29 filep	ipl[NSO];
30 long	offl[NSO];
31 long	ioff;
32 char	*ttyp;
33 char	cfname[NSO][NS] = "<standard input>";	/*file name stack*/
34 int	cfline[NSO];		/*input line count stack*/
35 char	*progname;	/* program name (troff) */
36 
37 main(argc, argv)
38 int	argc;
39 char	**argv;
40 {
41 	register char	*p, *q;
42 	register j;
43 	register tchar i;
44 	extern catch(), kcatch();
45 	char	**oargv, *getenv();
46 
47 	progname = argv[0];
48 	signal(SIGHUP, catch);
49 	if (signal(SIGINT, catch) == SIG_IGN) {
50 		signal(SIGHUP, SIG_IGN);
51 		signal(SIGINT, SIG_IGN);
52 		signal(SIGQUIT, SIG_IGN);
53 	}
54 	signal(SIGPIPE, catch);
55 	signal(SIGTERM, kcatch);
56 	oargv = argv;
57 	mrehash();
58 	nrehash();
59 	init0();
60 	if ((p = getenv("TYPESETTER")) != 0)
61 		strcpy(devname, p);
62 	while (--argc > 0 && (++argv)[0][0] == '-')
63 		switch (argv[0][1]) {
64 
65 		case 'F':	/* switch font tables from default */
66 			if (argv[0][2] != '\0') {
67 				strcpy(termtab, &argv[0][2]);
68 				strcpy(fontfile, &argv[0][2]);
69 			} else {
70 				argv++; argc--;
71 				strcpy(termtab, argv[0]);
72 				strcpy(fontfile, argv[0]);
73 			}
74 			continue;
75 		case 0:
76 			goto start;
77 		case 'i':
78 			stdi++;
79 			continue;
80 		case 'q':
81 			quiet++;
82 			if (gtty(0, &ttys) >= 0)
83 				ttysave = ttys.sg_flags;
84 			continue;
85 		case 'n':
86 			npn = ctoi(&argv[0][2]);
87 			continue;
88 		case 'u':	/* set emboldening amount */
89 			bdtab[3] = ctoi(&argv[0][2]);
90 			if (bdtab[3] < 0 || bdtab[3] > 50)
91 				bdtab[3] = 0;
92 			continue;
93 		case 's':
94 			if (!(stop = ctoi(&argv[0][2])))
95 				stop++;
96 			continue;
97 		case 'r':
98 			eibuf = sprintf(ibuf+strlen(ibuf), ".nr %c %s\n",
99 				argv[0][2], &argv[0][3]);
100 			continue;
101 		case 'c':
102 		case 'm':
103 			strcat(nextf, &argv[0][2]);
104 			mflg++;
105 			continue;
106 		case 'o':
107 			getpn(&argv[0][2]);
108 			continue;
109 		case 'T':
110 			strcpy(devname, &argv[0][2]);
111 			dotT++;
112 			continue;
113 		case 'D':	/* select DUTCH as hyphenation style (jaap) */
114 			hyalg1 = hyalg = DUTCH;
115 			thresh = DUTCH_THRESH;
116 			continue;
117 #ifdef NROFF
118 		case 'h':
119 			hflg++;
120 			continue;
121 		case 'z':
122 			no_out++;
123 			continue;
124 		case 'e':
125 			eqflg++;
126 			continue;
127 #endif
128 #ifndef NROFF
129 		case 'z':
130 			no_out++;
131 		case 'a':
132 			ascii = 1;
133 			nofeed++;
134 			continue;
135 		case 'f':
136 			nofeed++;
137 			continue;
138 		case 't':		/* for backward compatability */
139 			continue;
140 #endif
141 		default:
142 			errprint("unknown option %s", argv[0]);
143 			done(02);
144 		}
145 
146 start:
147 	init1(oargv[0][0]);
148 	argp = argv;
149 	rargc = argc;
150 	init2();
151 	setjmp(sjbuf);
152 loop:
153 	copyf = lgf = nb = nflush = nlflg = 0;
154 	if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl) {
155 		nflush++;
156 		trap = 0;
157 		eject((struct s *)0);
158 		goto loop;
159 	}
160 	i = getch();
161 	if (pendt)
162 		goto Lt;
163 	if ((j = cbits(i)) == XPAR) {
164 		copyf++;
165 		tflg++;
166 		while (cbits(i) != '\n')
167 			pchar(i = getch());
168 		tflg = 0;
169 		copyf--;
170 		goto loop;
171 	}
172 	if (j == cc || j == c2) {
173 		if (j == c2)
174 			nb++;
175 		copyf++;
176 		while ((j = cbits(i = getch())) == ' ' || j == '\t')
177 			;
178 		ch = i;
179 		copyf--;
180 		control(getrq(), 1);
181 		flushi();
182 		goto loop;
183 	}
184 Lt:
185 	ch = i;
186 	text();
187 	if (nlflg)
188 		numtab[HP].val = 0;
189 	goto loop;
190 }
191 
192 
193 catch()
194 {
195 	done3(01);
196 }
197 
198 
199 kcatch()
200 {
201 	signal(SIGTERM, SIG_IGN);
202 	done3(01);
203 }
204 
205 
206 init0()
207 {
208 	eibuf = ibufp = ibuf;
209 	ibuf[0] = 0;
210 	numtab[NL].val = -1;
211 }
212 
213 
214 init1(a)
215 char	a;
216 {
217 	register char	*p;
218 	char	*mktemp();
219 	register i;
220 
221 	p = mktemp("/usr/tmp/trtmpXXXXX");
222 	if (a == 'a')
223 		p = &p[9];
224 	if ((close(creat(p, 0600))) < 0) {
225 		errprint("cannot create temp file.");
226 		exit(-1);
227 	}
228 	ibf = open(p, 2);
229 	unlkp = p;
230 	for (i = NTRTAB; --i; )
231 		trtab[i] = i;
232 	trtab[UNPAD] = ' ';
233 }
234 
235 
236 init2()
237 {
238 	register i, j;
239 	extern char	*setbrk();
240 	extern char	*ttyname();
241 
242 	ttyod = 2;
243 	if ((ttyp=ttyname(j=0)) != 0 || (ttyp=ttyname(j=1)) != 0 || (ttyp=ttyname(j=2)) != 0)
244 		;
245 	else
246 		ttyp = "notty";
247 	iflg = j;
248 	if (ascii)
249 		mesg(0);
250 	obufp = obuf;
251 	ptinit();
252 	mchbits();
253 	cvtime();
254 	numtab[PID].val = getpid();
255 	olinep = oline;
256 	ioff = 0;
257 	numtab[HP].val = init = 0;
258 	numtab[NL].val = -1;
259 	nfo = 0;
260 	ifile = 0;
261 	copyf = raw = 0;
262 	eibuf = sprintf(ibuf+strlen(ibuf), ".ds .T %s\n", devname);
263 	numtab[CD].val = -1;	/* compensation */
264 	cpushback(ibuf);
265 	ibufp = ibuf;
266 	nx = mflg;
267 	frame = stk = (struct s *)setbrk(DELTA);
268 	dip = &d[0];
269 	nxf = frame + 1;
270 	for (i = NEV; i--; )
271 		write(ibf, (char *) & env, sizeof(env));
272 }
273 
274 /*
275  * (jaap)
276  * This replaces the old cvtime, so on well maintained systems, you don't
277  * need to change the (quite unknown) ZONE constant in tdef.h
278  */
279 
280 cvtime() {
281 	long	tt;
282 	register struct tm	*tym;
283 	extern struct tm	*localtime();
284 
285 	time(&tt);
286 	tym = localtime(&tt);
287 	numtab[DY].val = tym->tm_mday;		/* Current day of the month */
288 	numtab[DW].val = tym->tm_wday + 1;	/* Current day of the week */
289 	numtab[YR].val = tym->tm_year;		/* Current year */
290 	numtab[MO].val = tym->tm_mon + 1;	/* Current month of year */
291 }
292 
293 
294 ctoi(s)
295 	register char *s;
296 {
297 	register n;
298 
299 	while (*s == ' ')
300 		s++;
301 	n = 0;
302 	while (isdigit(*s))
303 		n = 10 * n + *s++ - '0';
304 	return n;
305 }
306 
307 
308 mesg(f)
309 int	f;
310 {
311 	static int	mode;
312 	struct stat stbuf;
313 
314 	if (!f) {
315 		stat(ttyp, &stbuf);
316 		mode = stbuf.st_mode;
317 		chmod(ttyp, mode & ~0122);	/* turn off writing for others */
318 	} else {
319 		if (ttyp && *ttyp && mode)
320 			chmod(ttyp, mode);
321 	}
322 }
323 
324 errprint(s, s1, s2, s3, s4, s5)	/* error message printer */
325 	char *s, *s1, *s2, *s3, *s4, *s5;
326 {
327 	fdprintf(stderr, "%s: ", progname);
328 	fdprintf(stderr, s, s1, s2, s3, s4, s5);
329 	if (numtab[CD].val > 0)
330 		fdprintf(stderr, "; line %d, file %s", numtab[CD].val, cfname[ifi]);
331 	fdprintf(stderr, "\n");
332 	stackdump();
333 }
334 
335 
336 /*
337  * Scaled down version of C Library printf.
338  * Only %s %u %d (==%u) %o %c %x %D are recognized.
339  */
340 #define	putchar(n)	(*pfbp++ = (n))	/* NO CHECKING! */
341 
342 static char	pfbuf[NTM];
343 static char	*pfbp = pfbuf;
344 int	stderr	 = 2;	/* NOT stdio value */
345 
346 /* VARARGS2 */
347 fdprintf(fd, fmt, x1)
348 	int	fd;
349 	register char	*fmt;
350 	unsigned	x1;
351 {
352 	register c;
353 	register unsigned int	*adx;
354 	char	*s;
355 	register i;
356 
357 	pfbp = pfbuf;
358 	adx = &x1;
359 loop:
360 	while ((c = *fmt++) != '%') {
361 		if (c == '\0') {
362 			if (fd == stderr)
363 				write(stderr, pfbuf, pfbp - pfbuf);
364 			else {
365 				*pfbp = 0;
366 				pfbp = pfbuf;
367 				while (*pfbp) {
368 					*obufp++ = *pfbp++;
369 					if (obufp >= &obuf[OBUFSZ])
370 						flusho();
371 				}
372 			}
373 			return;
374 		}
375 		putchar(c);
376 	}
377 	c = *fmt++;
378 	if (c == 'd') {
379 		i = *adx;
380 		if (i < 0) {
381 			putchar('-');
382 			i = -i;
383 		}
384 		printn((long)i, 10);
385 	} else if (c == 'u' || c == 'o' || c == 'x')
386 		printn((long)*adx, c == 'o' ? 8 : (c == 'x' ? 16 : 10));
387 	else if (c == 'c') {
388 		if (c > 0177 || c < 040)
389 			putchar('\\');
390 		putchar(*adx & 0177);
391 	} else if (c == 's') {
392 		s = (char *) * adx;
393 		while (c = *s++)
394 			putchar(c);
395 	} else if (c == 'D') {
396 		printn(*(long *)adx, 10);
397 		adx += (sizeof(long) / sizeof(int)) - 1;
398 	} else if (c == 'O') {
399 		printn(*(long *)adx, 8);
400 		adx += (sizeof(long) / sizeof(int)) - 1;
401 	}
402 	adx++;
403 	goto loop;
404 }
405 
406 
407 /*
408  * Print an unsigned integer in base b.
409  */
410 static printn(n, b)
411 	register long	n;
412 {
413 	register long	a;
414 
415 	if (n < 0) {	/* shouldn't happen */
416 		putchar('-');
417 		n = -n;
418 	}
419 	if (a = n / b)
420 		printn(a, b);
421 	putchar("0123456789ABCDEF"[(int)(n%b)]);
422 }
423 
424 /* scaled down version of library sprintf */
425 /* same limits as fdprintf */
426 /* returns pointer to \0 that ends the string */
427 
428 /* VARARGS2 */
429 char *sprintf(str, fmt, x1)
430 	char	*str;
431 	char	*fmt;
432 	unsigned	x1;
433 {
434 	register c;
435 	char *sprintn();
436 	register unsigned int	*adx;
437 	char	*s;
438 	register i;
439 
440 	adx = &x1;
441 loop:
442 	while ((c = *fmt++) != '%') {
443 		if (c == '\0') {
444 			*str = 0;
445 			return str;
446 		}
447 		*str++ = c;
448 	}
449 	c = *fmt++;
450 	if (c == 'd') {
451 		i = *adx;
452 		if (i < 0) {
453 			*str++ = '-';
454 			i = -i;
455 		}
456 		str = sprintn(str, (long)i, 10);
457 	} else if (c == 'u' || c == 'o' || c == 'x')
458 		str = sprintn(str, (long)*adx, c == 'o' ? 8 : (c == 'x' ? 16 : 10));
459 	else if (c == 'c') {
460 		if (c > 0177 || c < 040)
461 			*str++ = '\\';
462 		*str++ = *adx & 0177;
463 	} else if (c == 's') {
464 		s = (char *) * adx;
465 		while (c = *s++)
466 			*str++ = c;
467 	} else if (c == 'D') {
468 		str = sprintn(str, *(long *)adx, 10);
469 		adx += (sizeof(long) / sizeof(int)) - 1;
470 	} else if (c == 'O') {
471 		str = sprintn(str, *(long *)adx, 8);
472 		adx += (sizeof(long) / sizeof(int)) - 1;
473 	}
474 	adx++;
475 	goto loop;
476 }
477 
478 /*
479  * Print an unsigned integer in base b.
480  */
481 static char *sprintn(s, n, b)
482 	register char *s;
483 	register long n;
484 {
485 	register long	a;
486 
487 	if (n < 0) {	/* shouldn't happen */
488 		*s++ = '-';
489 		n = -n;
490 	}
491 	if (a = n / b)
492 		s = sprintn(s, a, b);
493 	*s++ = "0123456789ABCDEF"[(int)(n%b)];
494 	return s;
495 }
496 
497 
498 control(a, b)
499 register int	a, b;
500 {
501 	register int	j;
502 
503 	if (a == 0 || (j = findmn(a)) == -1)
504 		return(0);
505 	if (contab[j].f == 0) {
506 		nxf->nargs = 0;
507 		if (b)
508 			collect();
509 		flushi();
510 		return pushi((filep)contab[j].mx, a);
511 	} else if (b)
512 		return((*contab[j].f)(0));
513 	else
514 		return(0);
515 }
516 
517 
518 getrq()
519 {
520 	register i, j;
521 
522 	if (((i = getach()) == 0) || ((j = getach()) == 0))
523 		goto rtn;
524 	i = PAIR(i, j);
525 rtn:
526 	return(i);
527 }
528 
529 /*
530  * table encodes some special characters, to speed up tests
531  * in getchar, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
532  */
533 
534 char
535 gchtab[] = {
536 	000,004,000,000,010,000,000,000, /* fc, ldr */
537 	001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
538 	000,000,000,000,000,000,000,000,
539 	000,001,000,000,000,000,000,000, /* FLSS */
540 	000,000,000,000,000,000,000,000,
541 	000,000,000,000,000,000,000,000,
542 	000,000,000,000,000,000,000,000,
543 	000,000,000,000,000,000,000,000,
544 	000,000,000,000,000,000,000,000,
545 	000,000,000,000,000,000,000,000,
546 	000,000,000,000,000,000,000,000,
547 	000,000,000,000,000,000,000,000,
548 	000,000,000,000,000,000,001,000, /* f */
549 	000,000,000,000,000,000,000,000,
550 	000,000,000,000,000,000,000,000,
551 	000,000,000,000,000,000,000,000,
552 };
553 
554 tchar
555 getch()
556 {
557 	register int	k;
558 	register tchar i, j;
559 	tchar setht(), setslant();
560 
561 g0:
562 	if (i = ch) {
563 		if (cbits(i) == '\n')
564 			nlflg++;
565 		ch = 0;
566 		return(i);
567 	}
568 
569 	if (nlflg)
570 		return('\n');
571 	i = getch0();
572 	if (ismot(i))
573 		return(i);
574 	k = cbits(i);
575 	if (k != ESC) {
576 		if (gchtab[k]==0)
577 			return(i);
578 		if (k == '\n') {
579 			if (cbits(i) == '\n') {
580 				nlflg++;
581 				if (ip == 0)
582 					numtab[CD].val++; /* line number */
583 			}
584 			return(k);
585 		}
586 		if (k == FLSS) {
587 			copyf++;
588 			raw++;
589 			i = getch0();
590 			if (!fi)
591 				flss = i;
592 			copyf--;
593 			raw--;
594 			goto g0;
595 		}
596 		if (k == RPT) {
597 			setrpt();
598 			goto g0;
599 		}
600 		if (!copyf) {
601 			if (k == 'f' && lg && !lgf) {
602 				i = getlg(i);
603 				return(i);
604 			}
605 			if (k == fc || k == tabch || k == ldrch) {
606 				if ((i = setfield(k)) == 0)
607 					goto g0;
608 				else
609 					return(i);
610 			}
611 			if (k == '\b') {
612 				i = makem(-width(' ' | chbits));
613 				return(i);
614 			}
615 		}
616 		return(i);
617 	}
618 	k = cbits(j = getch0());
619 	if (ismot(j))
620 		return(j);
621 	switch (k) {
622 
623 	case '\n':	/* concealed newline */
624 		goto g0;
625 	case 'n':	/* number register */
626 		setn();
627 		goto g0;
628 	case '*':	/* string indicator */
629 		setstr();
630 		goto g0;
631 	case '$':	/* argument indicator */
632 		seta();
633 		goto g0;
634 	case '{':	/* LEFT */
635 		i = LEFT;
636 		goto gx;
637 	case '}':	/* RIGHT */
638 		i = RIGHT;
639 		goto gx;
640 	case '"':	/* comment */
641 		while (cbits(i = getch0()) != '\n')
642 			;
643 		nlflg++;
644 		if (ip == 0)
645 			numtab[CD].val++;
646 		return(i);
647 	case ESC:	/* double backslash */
648 		i = eschar;
649 		goto gx;
650 	case 'e':	/* printable version of current eschar */
651 		i = PRESC;
652 		goto gx;
653 	case ' ':	/* unpaddable space */
654 		i = UNPAD;
655 		goto gx;
656 	case '\'':	/* \(aa */
657 		i = ACUTE;
658 		goto gx;
659 	case '`':	/* \(ga */
660 		i = GRAVE;
661 		goto gx;
662 	case '_':	/* \(ul */
663 		i = UNDERLINE;
664 		goto gx;
665 	case '-':	/* current font minus */
666 		i = MINUS;
667 		goto gx;
668 	case '&':	/* filler */
669 		i = FILLER;
670 		goto gx;
671 	case 'c':	/* to be continued */
672 		i = CONT;
673 		goto gx;
674 	case '!':	/* transparent indicator */
675 		i = XPAR;
676 		goto gx;
677 	case 't':	/* tab */
678 		i = '\t';
679 		return(i);
680 	case 'a':	/* leader (SOH) */
681 		i = LEADER;
682 		return(i);
683 	case '%':	/* ohc */
684 		i = OHC;
685 		return(i);
686 	case 'g':	/* return format of a number register */
687 		setaf();
688 		goto g0;
689 	case 'N':	/* absolute character number */
690 		i = setabs();
691 		goto gx;
692 	case '.':	/* . */
693 		i = '.';
694 gx:
695 		setsfbits(i, sfbits(j));
696 		return(i);
697 	}
698 	if (copyf) {
699 		*pbp++ = j;
700 		return(eschar);
701 	}
702 	switch (k) {
703 
704 	case 'X':	/* \X'...' for copy through */
705 		setxon();
706 		goto g0;
707 	case 'p':	/* spread */
708 		spread++;
709 		goto g0;
710 	case '(':	/* special char name */
711 		if ((i = setch()) == 0)
712 			goto g0;
713 		return(i);
714 	case 's':	/* size indicator */
715 		setps();
716 		goto g0;
717 	case 'H':	/* character height */
718 		return(setht());
719 	case 'S':	/* slant */
720 		return(setslant());
721 	case 'f':	/* font indicator */
722 		setfont(0);
723 		goto g0;
724 	case 'w':	/* width function */
725 		setwd();
726 		goto g0;
727 	case 'v':	/* vert mot */
728 		if (i = vmot())
729 			return(i);
730 		goto g0;
731 	case 'h': 	/* horiz mot */
732 		if (i = hmot())
733 			return(i);
734 		goto g0;
735 	case 'z':	/* zero with char */
736 		return(setz());
737 	case 'l':	/* hor line */
738 		setline();
739 		goto g0;
740 	case 'L':	/* vert line */
741 		setvline();
742 		goto g0;
743 	case 'D':	/* drawing function */
744 		setdraw();
745 		goto g0;
746 	case 'b':	/* bracket */
747 		setbra();
748 		goto g0;
749 	case 'o':	/* overstrike */
750 		setov();
751 		goto g0;
752 	case 'k':	/* mark hor place */
753 		if ((k = findr(getsn())) != -1) {
754 			numtab[k].val = numtab[HP].val;
755 		}
756 		goto g0;
757 	case '0':	/* number space */
758 		return(makem(width('0' | chbits)));
759 #ifdef NROFF
760 	case '|':
761 	case '^':
762 		goto g0;
763 #else
764 	case '|':	/* narrow space */
765 		return(makem((int)(EM)/6));
766 	case '^':	/* half narrow space */
767 		return(makem((int)(EM)/12));
768 #endif
769 	case 'x':	/* extra line space */
770 		if (i = xlss())
771 			return(i);
772 		goto g0;
773 	case 'u':	/* half em up */
774 	case 'r':	/* full em up */
775 	case 'd':	/* half em down */
776 		return(sethl(k));
777 	default:
778 		return(j);
779 	}
780 	/* NOTREACHED */
781 }
782 
783 setxon()	/* \X'...' for copy through */
784 {
785 	tchar xbuf[NC];
786 	register tchar *i;
787 	tchar c;
788 	int delim, k;
789 
790 	if (ismot(c = getch()))
791 		return;
792 	delim = cbits(c);
793 	i = xbuf;
794 	*i++ = XON;
795 	while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
796 		if (k == ' ')
797 			setcbits(c, UNPAD);
798 		*i++ = c | ZBIT;
799 	}
800 	*i++ = XOFF;
801 	*i = 0;
802 	pushback(xbuf);
803 }
804 
805 
806 char	ifilt[32] = {
807 	0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012};
808 
809 tchar getch0()
810 {
811 	register int	j;
812 	register tchar i;
813 
814 again:
815 	if (pbp > lastpbp)
816 		i = *--pbp;
817 	else if (ip) {
818 #ifdef INCORE
819 		extern tchar corebuf[];
820 		i = corebuf[ip];
821 		if (i == 0)
822 			i = rbf();
823 		else {
824 			if ((++ip & (BLK - 1)) == 0) {
825 				--ip;
826 				(void)rbf();
827 			}
828 		}
829 #else
830 		i = rbf();
831 #endif
832 	} else {
833 		if (donef)
834 			done(0);
835 		if (nx || ibufp >= eibuf) {
836 			if (nfo==0) {
837 g0:
838 				if (nextfile()) {
839 					if (ip)
840 						goto again;
841 					if (ibufp < eibuf)
842 						goto g2;
843 				}
844 			}
845 			nx = 0;
846 			if ((j = read(ifile, ibuf, IBUFSZ)) <= 0)
847 				goto g0;
848 			ibufp = ibuf;
849 			eibuf = ibuf + j;
850 			if (ip)
851 				goto again;
852 		}
853 g2:
854 		i = *ibufp++ & 0177;
855 		ioff++;
856 		if (i >= 040 && i < 0177)
857 			goto g4;
858 		if (i != 0177)
859 			i = ifilt[i];
860 	}
861 	if (cbits(i) == IMP && !raw)
862 		goto again;
863 	if ((i == 0 || i == 0177) && !init && !raw) {
864 		goto again;
865 	}
866 g4:
867 	if (copyf == 0 && (i & ~BYTEMASK) == 0)
868 		i |= chbits;
869 	if (cbits(i) == eschar && !raw)
870 		setcbits(i, ESC);
871 	return(i);
872 }
873 
874 pushback(b)
875 register tchar *b;
876 {
877 	register tchar *ob = b;
878 
879 	while (*b++)
880 		;
881 	b--;
882 	while (b > ob && pbp < &pbbuf[NC-3])
883 		*pbp++ = *--b;
884 	if (pbp >= &pbbuf[NC-3]) {
885 		errprint("pushback overflow");
886 		done(2);
887 	}
888 }
889 
890 cpushback(b)
891 register char *b;
892 {
893 	register char *ob = b;
894 
895 	while (*b++)
896 		;
897 	b--;
898 	while (b > ob && pbp < &pbbuf[NC-3])
899 		*pbp++ = *--b;
900 	if (pbp >= &pbbuf[NC-3]) {
901 		errprint("cpushback overflow");
902 		done(2);
903 	}
904 }
905 
906 nextfile()
907 {
908 	register char	*p;
909 
910 n0:
911 	if (ifile)
912 		close(ifile);
913 	if (nx) {
914 		p = nextf;
915 		if (*p != 0)
916 			goto n1;
917 	}
918 	if (ifi > 0) {
919 		if (popf())
920 			goto n0; /* popf error */
921 		return(1); /* popf ok */
922 	}
923 	if (rargc-- <= 0) {
924 		if ((nfo -= mflg) && !stdi)
925 			done(0);
926 		nfo++;
927 		numtab[CD].val = ifile = stdi = mflg = 0;
928 		strcpy(cfname[ifi], "<standard input>");
929 		ioff = 0;
930 		return(0);
931 	}
932 	p = (argp++)[0];
933 n1:
934 	numtab[CD].val = 0;
935 	if (p[0] == '-' && p[1] == 0) {
936 		ifile = 0;
937 		strcpy(cfname[ifi], "<standard input>");
938 	} else if ((ifile = open(p, 0)) < 0) {
939 		errprint("cannot open file %s", p);
940 		nfo -= mflg;
941 		done(02);
942 	} else
943 		strcpy(cfname[ifi],p);
944 	nfo++;
945 	ioff = 0;
946 	return(0);
947 }
948 
949 
950 popf()
951 {
952 	register i;
953 	register char	*p, *q;
954 	extern char	*ttyname();
955 
956 	ioff = offl[--ifi];
957 	numtab[CD].val = cfline[ifi];		/*restore line counter*/
958 	ip = ipl[ifi];
959 	if ((ifile = ifl[ifi]) == 0) {
960 		p = xbuf;
961 		q = ibuf;
962 		ibufp = xbufp;
963 		eibuf = xeibuf;
964 		while (q < eibuf)
965 			*q++ = *p++;
966 		return(0);
967 	}
968 	if (lseek(ifile, (long)(ioff & ~(IBUFSZ-1)), 0) == (long) -1
969 	   || (i = read(ifile, ibuf, IBUFSZ)) < 0)
970 		return(1);
971 	eibuf = ibuf + i;
972 	ibufp = ibuf;
973 	if (ttyname(ifile) == 0)
974 		/* was >= ... */
975 		if ((ibufp = ibuf + (int)(ioff & (IBUFSZ - 1))) > eibuf)
976 			return(1);
977 	return(0);
978 }
979 
980 
981 flushi()
982 {
983 	if (nflush)
984 		return;
985 	ch = 0;
986 	copyf++;
987 	while (!nlflg) {
988 		if (donef && (frame == stk))
989 			break;
990 		getch();
991 	}
992 	copyf--;
993 }
994 
995 
996 getach()
997 {
998 	register tchar i;
999 	register j;
1000 
1001 	lgf++;
1002 	j = cbits(i = getch());
1003 	if (ismot(i) || j == ' ' || j == '\n' || j & 0200) {
1004 		ch = i;
1005 		j = 0;
1006 	}
1007 	lgf--;
1008 	return(j & 0177);
1009 }
1010 
1011 
1012 casenx()
1013 {
1014 	lgf++;
1015 	skip();
1016 	getname();
1017 	nx++;
1018 	nextfile();
1019 	nlflg++;
1020 	ip = 0;
1021 	pendt = 0;
1022 	frame = stk;
1023 	nxf = frame + 1;
1024 }
1025 
1026 
1027 getname()
1028 {
1029 	register int	j, k;
1030 	tchar i;
1031 
1032 	lgf++;
1033 	for (k = 0; k < (NS - 1); k++) {
1034 		if (((j = cbits(i = getch())) <= ' ') || (j > 0176))
1035 			break;
1036 		nextf[k] = j;
1037 	}
1038 	nextf[k] = 0;
1039 	ch = i;
1040 	lgf--;
1041 	return(nextf[0]);
1042 }
1043 
1044 
1045 caseso()
1046 {
1047 	register i;
1048 	register char	*p, *q;
1049 
1050 	lgf++;
1051 	nextf[0] = 0;
1052 	if (skip() || !getname() || ((i = open(nextf, 0)) < 0) || (ifi >= NSO)) {
1053 		errprint("can't open file %s", nextf);
1054 		done(02);
1055 	}
1056 	strcpy(cfname[ifi+1], nextf);
1057 	cfline[ifi] = numtab[CD].val;		/*hold line counter*/
1058 	numtab[CD].val = 0;
1059 	flushi();
1060 	ifl[ifi] = ifile;
1061 	ifile = i;
1062 	offl[ifi] = ioff;
1063 	ioff = 0;
1064 	ipl[ifi] = ip;
1065 	ip = 0;
1066 	nx++;
1067 	nflush++;
1068 	if (!ifl[ifi++]) {
1069 		p = ibuf;
1070 		q = xbuf;
1071 		xbufp = ibufp;
1072 		xeibuf = eibuf;
1073 		while (p < eibuf)
1074 			*q++ = *p++;
1075 	}
1076 }
1077 
1078 caself()	/* set line number and file */
1079 {
1080 	int n;
1081 
1082 	if (skip())
1083 		return;
1084 	n = atoi();
1085 	cfline[ifi] = numtab[CD].val = n - 2;
1086 	if (skip())
1087 		return;
1088 	if (getname())
1089 		strcpy(cfname[ifi], nextf);
1090 }
1091 
1092 
1093 casecf()
1094 {	/* copy file without change */
1095 #ifndef NROFF
1096 	int	fd, n;
1097 	char	buf[512];
1098 	extern int hpos, esc, po;
1099 	nextf[0] = 0;
1100 	if (skip() || !getname() || (fd = open(nextf, 0)) < 0) {
1101 		errprint("can't open file %s", nextf);
1102 		done(02);
1103 	}
1104 	tbreak();
1105 	/* make it into a clean state, be sure that everything is out */
1106 	hpos = po;
1107 	esc = un;
1108 	ptesc();
1109 	ptlead();
1110 	ptps();
1111 	ptfont();
1112 	flusho();
1113 	while ((n = read(fd, buf, sizeof buf)) > 0)
1114 		write(ptid, buf, n);
1115 	close(fd);
1116 #endif
1117 }
1118 
1119 
1120 casesy()	/* call system */
1121 {
1122 	char	sybuf[NTM];
1123 	int	i;
1124 
1125 	lgf++;
1126 	copyf++;
1127 	skip();
1128 	for (i = 0; i < NTM - 2; i++)
1129 		if ((sybuf[i] = getch()) == '\n')
1130 			break;
1131 	sybuf[i] = 0;
1132 	system(sybuf);
1133 	copyf--;
1134 	lgf--;
1135 }
1136 
1137 
1138 getpn(a)
1139 	register char *a;
1140 {
1141 	register int n, neg;
1142 
1143 	if (*a == 0)
1144 		return;
1145 	neg = 0;
1146 	for ( ; *a; a++)
1147 		switch (*a) {
1148 		case '+':
1149 		case ',':
1150 			continue;
1151 		case '-':
1152 			neg = 1;
1153 			continue;
1154 		default:
1155 			n = 0;
1156 			if (isdigit(*a)) {
1157 				do
1158 					n = 10 * n + *a++ - '0';
1159 				while (isdigit(*a));
1160 				a--;
1161 			} else
1162 				n = 9999;
1163 			*pnp++ = neg ? -n : n;
1164 			neg = 0;
1165 			if (pnp >= &pnlist[NPN-2]) {
1166 				errprint("too many page numbers");
1167 				done3(-3);
1168 			}
1169 		}
1170 	if (neg)
1171 		*pnp++ = -9999;
1172 	*pnp = -32767;
1173 	print = 0;
1174 	pnp = pnlist;
1175 	if (*pnp != -32767)
1176 		chkpn();
1177 }
1178 
1179 
1180 setrpt()
1181 {
1182 	tchar i, j;
1183 
1184 	copyf++;
1185 	raw++;
1186 	i = getch0();
1187 	copyf--;
1188 	raw--;
1189 	if (i < 0 || cbits(j = getch0()) == RPT)
1190 		return;
1191 	i &= BYTEMASK;
1192 	while (i>0 && pbp < &pbbuf[NC-3]) {
1193 		i--;
1194 		*pbp++ = j;
1195 	}
1196 }
1197