1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30/*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40/*
41 * n1.c
42 *
43 *	consume options, initialization, main loop,
44 *	input routines, escape function calling
45 */
46
47#include <ctype.h>
48#include <signal.h>
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <setjmp.h>
52#include <time.h>
53#include <stdarg.h>
54#include <locale.h>
55#include <fcntl.h>
56#include <stdlib.h>
57#include <string.h>
58#ifdef 	EUC
59#ifdef	NROFF
60#include <stddef.h>
61#include <limits.h>
62#endif	/* NROFF */
63#endif	/* EUC */
64
65#include "tdef.h"
66#include "ext.h"
67
68#ifdef NROFF
69#include "tw.h"
70#endif
71
72#define	MAX_RECURSION_DEPTH	512
73
74jmp_buf sjbuf;
75extern	void	fdprintf(int, char *, ...);
76extern	char	*roff_sprintf(char *, char *, ...);
77filep	ipl[NSO];
78long	offl[NSO];
79long	ioff;
80char	*ttyp;
81char	cfname[NSO+1][NS];	/*file name stack*/
82int	cfline[NSO];		/*input line count stack*/
83char	*progname;	/* program name (troff) */
84#ifdef	EUC
85#ifdef	NROFF
86char	mbbuf1[MB_LEN_MAX + 1];
87char	*mbbuf1p = mbbuf1;
88wchar_t	twc = 0;
89#endif	/* NROFF */
90#endif	/* EUC */
91
92#ifdef	DEBUG
93int	debug = 0;	/*debug flag*/
94#endif	/* DEBUG */
95
96static char *sprintn(char *, long, int);
97static int printn(long, int);
98
99int
100main(int argc, char **argv)
101{
102	char	*p, *q;
103	int	j;
104	tchar i;
105	int eileenct;		/*count to test for "Eileen's loop"*/
106	extern void catch(), kcatch();
107	char	**oargv;
108
109	(void)setlocale(LC_ALL, "");
110#if !defined(TEXT_DOMAIN)
111#define TEXT_DOMAIN "SYS_TEST"
112#endif
113	(void)textdomain(TEXT_DOMAIN);
114	progname = argv[0];
115	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
116		signal(SIGHUP, catch);
117	if (signal(SIGINT, catch) == SIG_IGN) {
118		signal(SIGHUP, SIG_IGN);
119		signal(SIGINT, SIG_IGN);
120		signal(SIGQUIT, SIG_IGN);
121	}
122	signal(SIGPIPE, catch);
123	signal(SIGTERM, kcatch);
124	oargv = argv;
125	strcpy(cfname[0], "<standard input>");
126	mrehash();
127	nrehash();
128	init0();
129#ifdef EUC
130#ifdef NROFF
131	(void)localize();
132#endif /* NROFF */
133#endif /* EUC */
134	if ((p = getenv("TYPESETTER")) != 0)
135		strcpy(devname, p);
136	while (--argc > 0 && (++argv)[0][0] == '-')
137		switch (argv[0][1]) {
138
139		case 'F':	/* switch font tables from default */
140			if (argv[0][2] != '\0') {
141				strcpy(termtab, &argv[0][2]);
142				strcpy(fontfile, &argv[0][2]);
143			} else {
144				argv++; argc--;
145				if (argv[0] != NULL) {
146					strcpy(termtab, argv[0]);
147					strcpy(fontfile, argv[0]);
148				} else
149					errprint(gettext("missing the font directory"));
150			}
151			continue;
152		case 0:
153			goto start;
154		case 'i':
155			stdi++;
156			continue;
157		case 'q':
158#ifdef	NROFF
159			quiet++;
160			save_tty();
161#else
162			errprint(gettext("-q option ignored in troff"));
163#endif	/* NROFF */
164			continue;
165		case 'n':
166			npn = ctoi(&argv[0][2]);
167			continue;
168		case 'u':	/* set emboldening amount */
169			bdtab[3] = ctoi(&argv[0][2]);
170			if (bdtab[3] < 0 || bdtab[3] > 50)
171				bdtab[3] = 0;
172			continue;
173		case 's':
174			if (!(stop = ctoi(&argv[0][2])))
175				stop++;
176			continue;
177		case 't':
178			ptid = 1;
179			continue;
180		case 'r':
181			if (strlen(&argv[0][2]) >= 2) {
182				eibuf = roff_sprintf(ibuf+strlen(ibuf),
183				    ".nr %c %s\n", argv[0][2], &argv[0][3]);
184			} else {
185				errprint(gettext("wrong options"));
186			}
187			continue;
188		case 'c':
189		case 'm':
190			if (mflg++ >= NMF) {
191				errprint(gettext("Too many macro packages: %s"),
192					 argv[0]);
193				continue;
194			}
195		        if (argv[0][2] == '\0') {
196				errprint(gettext("No library provided with -m"));
197				done(02);
198			}
199			p = getenv("TROFFMACS");
200			if (p != NULL && *p != '\0') {
201			     if (tryfile(getenv("TROFFMACS"), &argv[0][2], nmfi))
202			       nmfi++;
203			} else
204			  if (tryfile("/usr/share/lib/tmac/", &argv[0][2], nmfi)
205			  || tryfile("/usr/share/lib/tmac/tmac.", &argv[0][2], nmfi))
206				nmfi++;
207			  else {
208				errprint(gettext("Cannot find library %s\n"),
209					argv[0]);
210				done(02);
211			  }
212			continue;
213		case 'o':
214			getpn(&argv[0][2]);
215			continue;
216		case 'T':
217			strcpy(devname, &argv[0][2]);
218			dotT++;
219			continue;
220#ifdef NROFF
221		case 'h':
222			hflg++;
223			continue;
224		case 'z':
225			no_out++;
226			continue;
227		case 'e':
228			eqflg++;
229			continue;
230#endif
231#ifndef NROFF
232		case 'z':
233			no_out++;
234		case 'a':
235			ascii = 1;
236			nofeed++;
237			continue;
238		case 'f':
239			nofeed++;
240			continue;
241#endif
242		case '#':
243#ifdef	DEBUG
244			debug = ctoi(&argv[0][2]);
245#else
246			errprint("DEBUG not enabled");
247#endif	/* DEBUG */
248			continue;
249		default:
250			errprint(gettext("unknown option %s"), argv[0]);
251			done(02);
252		}
253
254start:
255	init1(oargv[0][0]);
256	argp = argv;
257	rargc = argc;
258	nmfi = 0;
259	init2();
260	setjmp(sjbuf);
261	eileenct = 0;		/*reset count for "Eileen's loop"*/
262loop:
263	copyf = lgf = nb = nflush = nlflg = 0;
264	if (ip && rbf0(ip) == 0 && ejf && frame->pframe <= ejl) {
265		nflush++;
266		trap = 0;
267		eject((struct s *)0);
268#ifdef	DEBUG
269	if (debug & DB_LOOP)
270		fdprintf(stderr, "loop: NL=%d, ejf=%d, lss=%d, eileenct=%d\n",
271			numtab[NL].val, ejf, lss, eileenct);
272#endif	/* DEBUG */
273		if (eileenct > 20) {
274			errprint(gettext("job looping; check abuse of macros"));
275			ejf = 0;	/*try to break Eileen's loop*/
276			eileenct = 0;
277		} else
278			eileenct++;
279		goto loop;
280	}
281	eileenct = 0;		/*reset count for "Eileen's loop"*/
282	i = getch();
283	if (pendt)
284		goto Lt;
285	if ((j = cbits(i)) == XPAR) {
286		copyf++;
287		tflg++;
288		while (cbits(i) != '\n')
289			pchar(i = getch());
290		tflg = 0;
291		copyf--;
292		goto loop;
293	}
294	if (j == cc || j == c2) {
295		if (j == c2)
296			nb++;
297		copyf++;
298		while ((j = cbits(i = getch())) == ' ' || j == '\t')
299			;
300		ch = i;
301		copyf--;
302		control(getrq(), 1);
303		flushi();
304		goto loop;
305	}
306Lt:
307	ch = i;
308	text();
309	if (nlflg)
310		numtab[HP].val = 0;
311	goto loop;
312}
313
314
315int
316tryfile(pat, fn, idx)
317char *pat, *fn;
318int idx;
319{
320	strcpy(mfiles[idx], pat);
321	strcat(mfiles[idx], fn);
322	if (access(mfiles[idx], 4) == -1)
323		return(0);
324	else return(1);
325}
326
327void catch()
328{
329	done3(01);
330}
331
332
333void kcatch()
334{
335	signal(SIGTERM, SIG_IGN);
336	done3(01);
337}
338
339int
340init0()
341{
342	eibuf = ibufp = ibuf;
343	ibuf[0] = 0;
344	numtab[NL].val = -1;
345	return (0);
346}
347
348
349int
350init1(a)
351char	a;
352{
353	char	*p;
354	int i;
355
356	p = tmp_name;
357	if (a == 'a')
358		p = &p[9];
359	if ((ibf = mkstemp(p)) == -1) {
360		errprint(gettext("cannot create temp file."));
361		exit(-1);
362	}
363	unlkp = p;
364	for (i = NTRTAB; --i; )
365		trtab[i] = i;
366	trtab[UNPAD] = ' ';
367	return (0);
368}
369
370
371int
372init2()
373{
374	int	i, j;
375	extern char	*setbrk();
376	extern char	*ttyname();
377
378	ttyod = 2;
379	if ((ttyp=ttyname(j=0)) != 0 || (ttyp=ttyname(j=1)) != 0 || (ttyp=ttyname(j=2)) != 0)
380		;
381	else
382		ttyp = "notty";
383	iflg = j;
384	if (ascii)
385		mesg(0);
386	obufp = obuf;
387	ptinit();
388	mchbits();
389	cvtime();
390	numtab[PID].val = getpid();
391	olinep = oline;
392	ioff = 0;
393	numtab[HP].val = init = 0;
394	numtab[NL].val = -1;
395	nfo = 0;
396	ifile = 0;
397	copyf = raw = 0;
398	eibuf = roff_sprintf(ibuf+strlen(ibuf), ".ds .T %s\n", devname);
399	numtab[CD].val = -1;	/* compensation */
400	cpushback(ibuf);
401	ibufp = ibuf;
402	nx = mflg;
403	frame = stk = (struct s *)setbrk(DELTA);
404	dip = &d[0];
405	nxf = frame + 1;
406#ifdef INCORE
407	for (i = 0; i < NEV; i++) {
408		extern tchar corebuf[];
409		*(struct env *)&corebuf[i * sizeof(env)/sizeof(tchar)] = env;
410	}
411#else
412	for (i = NEV; i--; )
413		write(ibf, (char *) & env, sizeof(env));
414#endif
415	return (0);
416}
417
418int
419cvtime()
420{
421	time_t	tt;
422	struct tm *tm;
423
424	tt = time((time_t *) 0);
425	tm = localtime(&tt);
426	numtab[DY].val = tm->tm_mday;
427	numtab[DW].val = tm->tm_wday + 1;
428	numtab[YR].val = tm->tm_year;
429	numtab[MO].val = tm->tm_mon + 1;
430
431	return (0);
432}
433
434
435int
436ctoi(s)
437	char *s;
438{
439	int	n;
440
441	while (*s == ' ')
442		s++;
443	n = 0;
444	while (isdigit((unsigned char)*s))
445		n = 10 * n + *s++ - '0';
446	return n;
447}
448
449
450int
451mesg(f)
452int	f;
453{
454	static int	mode;
455	struct stat stbuf;
456
457	if (!f) {
458		stat(ttyp, &stbuf);
459		mode = stbuf.st_mode;
460		chmod(ttyp, mode & ~0122);	/* turn off writing for others */
461	} else {
462		if (ttyp && *ttyp && mode)
463			chmod(ttyp, mode);
464	}
465
466	return (0);
467}
468
469int
470errprint(s, s1, s2, s3, s4, s5)	/* error message printer */
471	char *s, *s1, *s2, *s3, *s4, *s5;
472{
473	fdprintf(stderr, "%s: ", progname);
474	fdprintf(stderr, s, s1, s2, s3, s4, s5);
475	if (numtab[CD].val > 0)
476		fdprintf(stderr, gettext("; line %d, file %s"), numtab[CD].val,
477			 cfname[ifi]);
478	fdprintf(stderr, "\n");
479	stackdump();
480#ifdef	DEBUG
481	if (debug)
482		abort();
483#endif	/* DEBUG */
484	return (0);
485}
486
487
488/*
489 * Scaled down version of C Library printf.
490 * Only %s %u %d (==%u) %o %c %x %D are recognized.
491 */
492#undef putchar
493#define	putchar(n)	(*pfbp++ = (n))	/* NO CHECKING! */
494
495static char	pfbuf[NTM];
496static char	*pfbp = pfbuf;
497int	stderr	 = 2;	/* NOT stdio value */
498
499void
500fdprintf(int fd, char *fmt, ...)
501{
502	int	c;
503	char	*s;
504	int	i;
505	va_list	ap;
506
507	pfbp = pfbuf;
508	va_start(ap, fmt);
509loop:
510	while ((c = *fmt++) != '%') {
511		if (c == '\0') {
512			if (fd == stderr)
513				write(stderr, pfbuf, pfbp - pfbuf);
514			else {
515				*pfbp = 0;
516				pfbp = pfbuf;
517				while (*pfbp) {
518					*obufp++ = *pfbp++;
519					if (obufp >= &obuf[OBUFSZ])
520						flusho();
521				}
522			}
523			va_end(ap);
524			return;
525		}
526		putchar(c);
527	}
528	c = *fmt++;
529	if (c == 'd') {
530		i = va_arg(ap, int);
531		if (i < 0) {
532			putchar('-');
533			i = -i;
534		}
535		printn((long)i, 10);
536	} else if (c == 'u' || c == 'o' || c == 'x')
537		printn(va_arg(ap, long), c == 'o' ? 8 : (c == 'x' ? 16 : 10));
538	else if (c == 'c') {
539		if (c > 0177 || c < 040)
540			putchar('\\');
541		putchar(va_arg(ap, int) & 0177);
542	} else if (c == 's') {
543		s = va_arg(ap, char *);
544		while (c = *s++)
545			putchar(c);
546	} else if (c == 'D') {
547		printn(va_arg(ap, long), 10);
548	} else if (c == 'O') {
549		printn(va_arg(ap, long), 8);
550	}
551	goto loop;
552}
553
554
555/*
556 * Print an unsigned integer in base b.
557 */
558static int
559printn(n, b)
560	long	n;
561	int	b;
562{
563	long	a;
564
565	if (n < 0) {	/* shouldn't happen */
566		putchar('-');
567		n = -n;
568	}
569	if (a = n / b)
570		printn(a, b);
571	putchar("0123456789ABCDEF"[(int)(n%b)]);
572
573	return (0);
574}
575
576/* scaled down version of library roff_sprintf */
577/* same limits as fdprintf */
578/* returns pointer to \0 that ends the string */
579
580/* VARARGS2 */
581char *roff_sprintf(char *str, char *fmt, ...)
582{
583	int	c;
584	char	*s;
585	int	i;
586	va_list ap;
587
588	va_start(ap, fmt);
589loop:
590	while ((c = *fmt++) != '%') {
591		if (c == '\0') {
592			*str = 0;
593			va_end(ap);
594			return str;
595		}
596		*str++ = c;
597	}
598	c = *fmt++;
599	if (c == 'd') {
600		i = va_arg(ap, int);
601		if (i < 0) {
602			*str++ = '-';
603			i = -i;
604		}
605		str = sprintn(str, (long)i, 10);
606	} else if (c == 'u' || c == 'o' || c == 'x')
607		str = sprintn(str, va_arg(ap, long), c == 'o' ? 8 : (c == 'x' ? 16 : 10));
608	else if (c == 'c') {
609		if (c > 0177 || c < 040)
610			*str++ = '\\';
611		*str++ = va_arg(ap, int) & 0177;
612	} else if (c == 's') {
613		s = va_arg(ap, char *);
614		while (c = *s++)
615			*str++ = c;
616	} else if (c == 'D') {
617		str = sprintn(str, va_arg(ap, long), 10);
618	} else if (c == 'O') {
619		str = sprintn(str, va_arg(ap, unsigned) , 8);
620	}
621	goto loop;
622}
623
624/*
625 * Print an unsigned integer in base b.
626 */
627static char *sprintn(s, n, b)
628	char *s;
629	long n;
630	int b;
631{
632	long	a;
633
634	if (n < 0) {	/* shouldn't happen */
635		*s++ = '-';
636		n = -n;
637	}
638	if (a = n / b)
639		s = sprintn(s, a, b);
640	*s++ = "0123456789ABCDEF"[(int)(n%b)];
641	return s;
642}
643
644
645int
646control(a, b)
647int	a, b;
648{
649	int	j;
650
651	if (a == 0 || (j = findmn(a)) == -1)
652		return(0);
653
654	/*
655	 * Attempt to find endless recursion at runtime. Arbitrary
656	 * recursion limit of MAX_RECURSION_DEPTH was chosen as
657	 * it is extremely unlikely that a correct nroff/troff
658	 * invocation would exceed this value.
659	 */
660
661	if (frame != stk) {
662		int frame_cnt = 0;
663		struct s *p;
664
665		for (p = frame; p != stk; p = p->pframe)
666			frame_cnt++;
667		if (frame_cnt > MAX_RECURSION_DEPTH) {
668			errprint(
669			    gettext("Exceeded maximum stack size (%d) when "
670			    "executing macro %c%c. Stack dump follows"),
671			    MAX_RECURSION_DEPTH,
672			    frame->mname & 0177, (frame->mname >> BYTE) & 0177);
673			edone(02);
674		}
675	}
676
677#ifdef	DEBUG
678	if (debug & DB_MAC)
679		fdprintf(stderr, "control: macro %c%c, contab[%d]\n",
680			a&0177, (a>>BYTE)&0177 ? (a>>BYTE)&0177 : ' ', j);
681#endif	/* DEBUG */
682	if (contab[j].f == 0) {
683		nxf->nargs = 0;
684		if (b)
685			collect();
686		flushi();
687		return pushi((filep)contab[j].mx, a);
688	} else if (b)
689		return((*contab[j].f)(0));
690	else
691		return(0);
692}
693
694int
695getrq()
696{
697	int	i, j;
698
699	if (((i = getach()) == 0) || ((j = getach()) == 0))
700		goto rtn;
701	i = PAIR(i, j);
702rtn:
703	return(i);
704}
705
706/*
707 * table encodes some special characters, to speed up tests
708 * in getchar, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
709 */
710
711char
712gchtab[] = {
713	000,004,000,000,010,000,000,000, /* fc, ldr */
714	001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
715	000,000,000,000,000,000,000,000,
716	000,001,000,000,000,000,000,000, /* FLSS */
717	000,000,000,000,000,000,000,000,
718	000,000,000,000,000,000,000,000,
719	000,000,000,000,000,000,000,000,
720	000,000,000,000,000,000,000,000,
721	000,000,000,000,000,000,000,000,
722	000,000,000,000,000,000,000,000,
723	000,000,000,000,000,000,000,000,
724	000,000,000,000,000,000,000,000,
725	000,000,000,000,000,000,001,000, /* f */
726	000,000,000,000,000,000,000,000,
727	000,000,000,000,000,000,000,000,
728	000,000,000,000,000,000,000,000,
729};
730
731tchar
732getch()
733{
734	int	k;
735	tchar i, j;
736	tchar setht(), setslant();
737
738g0:
739	if (i = ch) {
740#ifdef	DEBUG
741		if (debug & DB_GETC)
742			fdprintf(stderr, "getch: ch is %x (%c)\n",
743				ch, (ch&0177) < 040 ? 0177 : ch&0177);
744#endif	/* DEBUG */
745		if (cbits(i) == '\n')
746			nlflg++;
747		ch = 0;
748		return(i);
749	}
750
751#ifdef	DEBUG
752	if (nlflg)
753		if (debug & DB_GETC)
754			fdprintf(stderr,"getch: nlflg is %x\n", nlflg);
755#endif	/* DEBUG */
756	if (nlflg)
757		return('\n');
758	i = getch0();
759#ifdef	DEBUG
760	if (debug & DB_GETC)
761		fdprintf(stderr, "getch: getch0 returns %x (%c)\n",
762			i, (i&0177) < 040 ? 0177 : i&0177);
763#endif	/* DEBUG */
764	if (ismot(i))
765		return(i);
766	k = cbits(i);
767	if (k != ESC) {
768		/*
769		 * gchtab[] has only 128 entries
770		 * if k is out of the range, it should be
771		 * handled as gchtab[k] == 0
772		 */
773		if (!isascii(k) || gchtab[k]==0)
774			return(i);
775		if (k == '\n') {
776			if (cbits(i) == '\n') {
777				nlflg++;
778				if (ip == 0)
779					numtab[CD].val++; /* line number */
780			}
781			return(k);
782		}
783		if (k == FLSS) {
784			copyf++;
785			raw++;
786			i = getch0();
787			if (!fi)
788				flss = i;
789			copyf--;
790			raw--;
791			goto g0;
792		}
793		if (k == RPT) {
794			setrpt();
795			goto g0;
796		}
797		if (!copyf) {
798			if (k == 'f' && lg && !lgf) {
799				i = getlg(i);
800				return(i);
801			}
802			if (k == fc || k == tabch || k == ldrch) {
803				if ((i = setfield(k)) == 0)
804					goto g0;
805				else
806					return(i);
807			}
808			if (k == '\b') {
809				i = makem(-width(' ' | chbits));
810				return(i);
811			}
812		}
813		return(i);
814	}
815	k = cbits(j = getch0());
816	if (ismot(j))
817		return(j);
818	switch (k) {
819
820	case 'X':	/* \X'...' for copy through */
821		setxon();
822		goto g0;
823	case '\n':	/* concealed newline */
824		goto g0;
825	case 'n':	/* number register */
826		setn();
827		goto g0;
828	case '*':	/* string indicator */
829		setstr();
830		goto g0;
831	case '$':	/* argument indicator */
832		seta();
833		goto g0;
834	case '{':	/* LEFT */
835		i = LEFT;
836		goto gx;
837	case '}':	/* RIGHT */
838		i = RIGHT;
839		goto gx;
840	case '"':	/* comment */
841		while (cbits(i = getch0()) != '\n')
842			;
843		nlflg++;
844		if (ip == 0)
845			numtab[CD].val++;
846		return(i);
847	case ESC:	/* double backslash */
848		i = eschar;
849		goto gx;
850	case 'e':	/* printable version of current eschar */
851		i = PRESC;
852		goto gx;
853	case ' ':	/* unpaddable space */
854		i = UNPAD;
855		goto gx;
856	case '\'':	/* \(aa */
857		i = ACUTE;
858		goto gx;
859	case '`':	/* \(ga */
860		i = GRAVE;
861		goto gx;
862	case '_':	/* \(ul */
863		i = UNDERLINE;
864		goto gx;
865	case '-':	/* current font minus */
866		i = MINUS;
867		goto gx;
868	case '&':	/* filler */
869		i = FILLER;
870		goto gx;
871	case 'c':	/* to be continued */
872		i = CONT;
873		goto gx;
874	case '!':	/* transparent indicator */
875		i = XPAR;
876		goto gx;
877	case 't':	/* tab */
878		i = '\t';
879		return(i);
880	case 'a':	/* leader (SOH) */
881		i = LEADER;
882		return(i);
883	case '%':	/* ohc */
884		i = OHC;
885		return(i);
886	case 'g':	/* return format of a number register */
887		setaf();
888		goto g0;
889	case 'N':	/* absolute character number */
890		i = setabs();
891		goto gx;
892	case '.':	/* . */
893		i = '.';
894gx:
895		setsfbits(i, sfbits(j));
896		return(i);
897	}
898	if (copyf) {
899		*pbp++ = j;
900		return(eschar);
901	}
902	switch (k) {
903
904	case 'p':	/* spread */
905		spread++;
906		goto g0;
907	case '(':	/* special char name */
908		if ((i = setch()) == 0)
909			goto g0;
910		return(i);
911	case 's':	/* size indicator */
912		setps();
913		goto g0;
914	case 'H':	/* character height */
915		return(setht());
916	case 'S':	/* slant */
917		return(setslant());
918	case 'f':	/* font indicator */
919		setfont(0);
920		goto g0;
921	case 'w':	/* width function */
922		setwd();
923		goto g0;
924	case 'v':	/* vert mot */
925		if (i = vmot())
926			return(i);
927		goto g0;
928	case 'h': 	/* horiz mot */
929		if (i = hmot())
930			return(i);
931		goto g0;
932	case 'z':	/* zero with char */
933		return(setz());
934	case 'l':	/* hor line */
935		setline();
936		goto g0;
937	case 'L':	/* vert line */
938		setvline();
939		goto g0;
940	case 'D':	/* drawing function */
941		setdraw();
942		goto g0;
943	case 'b':	/* bracket */
944		setbra();
945		goto g0;
946	case 'o':	/* overstrike */
947		setov();
948		goto g0;
949	case 'k':	/* mark hor place */
950		if ((k = findr(getsn())) != -1) {
951			numtab[k].val = numtab[HP].val;
952		}
953		goto g0;
954	case '0':	/* number space */
955		return(makem(width('0' | chbits)));
956#ifdef NROFF
957	case '|':
958	case '^':
959		goto g0;
960#else
961	case '|':	/* narrow space */
962		return(makem((int)(EM)/6));
963	case '^':	/* half narrow space */
964		return(makem((int)(EM)/12));
965#endif
966	case 'x':	/* extra line space */
967		if (i = xlss())
968			return(i);
969		goto g0;
970	case 'u':	/* half em up */
971	case 'r':	/* full em up */
972	case 'd':	/* half em down */
973		return(sethl(k));
974	default:
975		return(j);
976	}
977	/* NOTREACHED */
978}
979
980int
981setxon()	/* \X'...' for copy through */
982{
983	tchar xbuf[NC];
984	tchar *i;
985	tchar c;
986	int delim, k;
987
988	if (ismot(c = getch()))
989		return (0);
990	delim = cbits(c);
991	i = xbuf;
992	*i++ = XON;
993	while ((k = cbits(c = getch())) != delim && k != '\n' && i < xbuf+NC-1) {
994		if (k == ' ')
995			setcbits(c, UNPAD);
996		*i++ = c | ZBIT;
997	}
998	*i++ = XOFF;
999	*i = 0;
1000	pushback(xbuf);
1001
1002	return (0);
1003}
1004
1005
1006char	ifilt[32] = {
1007	0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012};
1008
1009tchar getch0()
1010{
1011	int	j;
1012	tchar i;
1013#ifdef	EUC
1014#ifdef	NROFF
1015	int	n;
1016	int col_index;
1017#endif	/* NROFF */
1018#endif	/* EUC */
1019
1020again:
1021	if (pbp > lastpbp)
1022		i = *--pbp;
1023	else if (ip) {
1024#ifdef INCORE
1025		extern tchar corebuf[];
1026		i = corebuf[ip];
1027		if (i == 0)
1028			i = rbf();
1029		else {
1030			if ((++ip & (BLK - 1)) == 0) {
1031				--ip;
1032				(void)rbf();
1033			}
1034		}
1035#else
1036		i = rbf();
1037#endif
1038	} else {
1039		if (donef || ndone)
1040			done(0);
1041		if (nx || ibufp >= eibuf) {
1042			if (nfo==0) {
1043g0:
1044				if (nextfile()) {
1045					if (ip)
1046						goto again;
1047					if (ibufp < eibuf)
1048						goto g2;
1049				}
1050			}
1051			nx = 0;
1052			if ((j = read(ifile, ibuf, IBUFSZ)) <= 0)
1053				goto g0;
1054			ibufp = ibuf;
1055			eibuf = ibuf + j;
1056			if (ip)
1057				goto again;
1058		}
1059g2:
1060#ifndef	EUC
1061		i = *ibufp++ & 0177;
1062		ioff++;
1063		if (i >= 040 && i < 0177)
1064#else
1065#ifndef	NROFF
1066		i = *ibufp++ & 0177;
1067		ioff++;
1068		if (i >= 040 && i < 0177)
1069#else
1070		i = *ibufp++ & 0377;
1071		*mbbuf1p++ = i;
1072		*mbbuf1p = 0;
1073		if (!multi_locale) {
1074			twc = 0;
1075			mbbuf1p = mbbuf1;
1076		} else if ((n = mbtowc(&twc, mbbuf1, MB_CUR_MAX)) <= 0) {
1077			if (mbbuf1p >= mbbuf1 + MB_CUR_MAX) {
1078				i &= ~(MBMASK | CSMASK);
1079				twc = 0;
1080				mbbuf1p = mbbuf1;
1081				*mbbuf1p = 0;
1082			} else {
1083				i |= (MIDDLEOFMB);
1084			}
1085		} else {
1086			if (n > 1)
1087				i |= (LASTOFMB);
1088			else
1089				i |= (BYTE_CHR);
1090			if (isascii(twc)) {
1091				col_index = 0;
1092			} else {
1093				if ((col_index = wcwidth(twc)) < 0)
1094					col_index = 0;
1095			}
1096			setcsbits(i, col_index);
1097			twc = 0;
1098			mbbuf1p = mbbuf1;
1099		}
1100		ioff++;
1101		if (i >= 040 && i != 0177)
1102#endif	/* NROFF */
1103#endif	/* EUC */
1104			goto g4;
1105		if (i != 0177)
1106			i = ifilt[i];
1107	}
1108	if (cbits(i) == IMP && !raw)
1109		goto again;
1110	if ((i == 0 || i == 0177) && !init && !raw) {
1111		goto again;
1112	}
1113g4:
1114#ifndef EUC
1115	if (copyf == 0 && (i & ~BYTEMASK) == 0)
1116#else
1117#ifndef NROFF
1118	if (copyf == 0 && (i & ~BYTEMASK) == 0)
1119#else
1120	if (copyf == 0 && (i & ~CHMASK) == 0)
1121#endif /* NROFF */
1122#endif /* EUC */
1123		i |= chbits;
1124#ifdef EUC
1125#ifdef NROFF
1126	if (multi_locale)
1127		if (i & MBMASK1)
1128			i |= ZBIT;
1129#endif /* NROFF */
1130#endif /* EUC */
1131	if (cbits(i) == eschar && !raw)
1132		setcbits(i, ESC);
1133	return(i);
1134}
1135
1136int
1137pushback(b)
1138tchar *b;
1139{
1140	tchar *ob = b;
1141
1142	while (*b++)
1143		;
1144	b--;
1145	while (b > ob && pbp < &pbbuf[NC-3])
1146		*pbp++ = *--b;
1147	if (pbp >= &pbbuf[NC-3]) {
1148		errprint(gettext("pushback overflow"));
1149		done(2);
1150	}
1151
1152	return (0);
1153}
1154
1155int
1156cpushback(b)
1157char *b;
1158{
1159	char *ob = b;
1160
1161	while (*b++)
1162		;
1163	b--;
1164	while (b > ob && pbp < &pbbuf[NC-3])
1165		*pbp++ = *--b;
1166	if (pbp >= &pbbuf[NC-3]) {
1167		errprint(gettext("cpushback overflow"));
1168		done(2);
1169	}
1170
1171	return (0);
1172}
1173
1174int
1175nextfile()
1176{
1177	char	*p;
1178
1179n0:
1180	if (ifile)
1181		close(ifile);
1182	if (nx  ||  nmfi < mflg) {
1183		p = mfiles[nmfi++];
1184		if (*p != 0)
1185			goto n1;
1186	}
1187	if (ifi > 0) {
1188		if (popf())
1189			goto n0; /* popf error */
1190		return(1); /* popf ok */
1191	}
1192	if (rargc-- <= 0) {
1193		if ((nfo -= mflg) && !stdi)
1194			done(0);
1195		nfo++;
1196		numtab[CD].val = ifile = stdi = mflg = 0;
1197		strcpy(cfname[ifi], "<standard input>");
1198		ioff = 0;
1199		return(0);
1200	}
1201	p = (argp++)[0];
1202n1:
1203	numtab[CD].val = 0;
1204	if (p[0] == '-' && p[1] == 0) {
1205		ifile = 0;
1206		strcpy(cfname[ifi], "<standard input>");
1207	} else if ((ifile = open(p, 0)) < 0) {
1208		errprint(gettext("cannot open file %s"), p);
1209		nfo -= mflg;
1210		done(02);
1211	} else
1212		strcpy(cfname[ifi],p);
1213	nfo++;
1214	ioff = 0;
1215	return(0);
1216}
1217
1218
1219int
1220popf()
1221{
1222	int	i;
1223	char	*p, *q;
1224	extern char	*ttyname();
1225
1226	ioff = offl[--ifi];
1227	numtab[CD].val = cfline[ifi];		/*restore line counter*/
1228	ip = ipl[ifi];
1229	if ((ifile = ifl[ifi]) == 0) {
1230		p = xbuf;
1231		q = ibuf;
1232		ibufp = xbufp;
1233		eibuf = xeibuf;
1234		while (q < eibuf)
1235			*q++ = *p++;
1236		return(0);
1237	}
1238	if (lseek(ifile, (long)(ioff & ~(IBUFSZ-1)), 0) == (long) -1
1239	   || (i = read(ifile, ibuf, IBUFSZ)) < 0)
1240		return(1);
1241	eibuf = ibuf + i;
1242	ibufp = ibuf;
1243	if (ttyname(ifile) == 0)
1244		/* was >= ... */
1245		if ((ibufp = ibuf + (int)(ioff & (IBUFSZ - 1))) > eibuf)
1246			return(1);
1247	return(0);
1248}
1249
1250
1251int
1252flushi()
1253{
1254	if (nflush)
1255		return (0);
1256	ch = 0;
1257	copyf++;
1258	while (!nlflg) {
1259		if (donef && (frame == stk))
1260			break;
1261		getch();
1262	}
1263	copyf--;
1264
1265	return (0);
1266}
1267
1268
1269int
1270getach()
1271{
1272	tchar i;
1273	int	j;
1274
1275	lgf++;
1276	j = cbits(i = getch());
1277#ifndef	EUC
1278	if (ismot(i) || j == ' ' || j == '\n' || j & 0200) {
1279#else
1280#ifndef	NROFF
1281	if (ismot(i) || j == ' ' || j == '\n' || j & 0200) {
1282#else
1283	if (ismot(i) || j == ' ' || j == '\n' || j > 0200) {
1284#endif	/* NROFF */
1285#endif	/* EUC */
1286
1287		ch = i;
1288		j = 0;
1289	}
1290	lgf--;
1291	return(j & 0177);
1292}
1293
1294
1295int
1296casenx()
1297{
1298	lgf++;
1299	skip();
1300	getname();
1301	nx++;
1302	if (nmfi > 0)
1303		nmfi--;
1304	strcpy(mfiles[nmfi], nextf);
1305	nextfile();
1306	nlflg++;
1307	ip = 0;
1308	pendt = 0;
1309	frame = stk;
1310	nxf = frame + 1;
1311
1312	return (0);
1313}
1314
1315
1316int
1317getname()
1318{
1319	int	j, k;
1320	tchar i;
1321
1322	lgf++;
1323	for (k = 0; k < (NS - 1); k++) {
1324#ifndef EUC
1325		if (((j = cbits(i = getch())) <= ' ') || (j > 0176))
1326#else
1327#ifndef NROFF
1328		if (((j = cbits(i = getch())) <= ' ') || (j > 0176))
1329#else
1330		if (((j = cbits(i = getch())) <= ' ') || (j == 0177))
1331#endif /* NROFF */
1332#endif /* EUC */
1333			break;
1334		nextf[k] = j & BYTEMASK;
1335	}
1336	nextf[k] = 0;
1337	ch = i;
1338	lgf--;
1339	return((int)nextf[0]);
1340}
1341
1342
1343int
1344caseso()
1345{
1346	int	i;
1347	char	*p, *q;
1348
1349	lgf++;
1350	nextf[0] = 0;
1351	if (skip() || !getname() || ((i = open(nextf, 0)) < 0) || (ifi >= NSO)) {
1352		errprint(gettext("can't open file %s"), nextf);
1353		done(02);
1354	}
1355	strcpy(cfname[ifi+1], nextf);
1356	cfline[ifi] = numtab[CD].val;		/*hold line counter*/
1357	numtab[CD].val = 0;
1358	flushi();
1359	ifl[ifi] = ifile;
1360	ifile = i;
1361	offl[ifi] = ioff;
1362	ioff = 0;
1363	ipl[ifi] = ip;
1364	ip = 0;
1365	nx++;
1366	nflush++;
1367	if (!ifl[ifi++]) {
1368		p = ibuf;
1369		q = xbuf;
1370		xbufp = ibufp;
1371		xeibuf = eibuf;
1372		while (p < eibuf)
1373			*q++ = *p++;
1374	}
1375
1376	return (0);
1377}
1378
1379int
1380caself()	/* set line number and file */
1381{
1382	int n;
1383
1384	if (skip())
1385		return (0);
1386	n = atoi();
1387	cfline[ifi] = numtab[CD].val = n - 2;
1388	if (skip())
1389		return (0);
1390	if (getname())
1391		strcpy(cfname[ifi], nextf);
1392
1393	return (0);
1394}
1395
1396
1397int
1398casecf()
1399{	/* copy file without change */
1400#ifndef NROFF
1401	int	fd, n;
1402	char	buf[512];
1403	extern int hpos, esc, po;
1404	nextf[0] = 0;
1405	if (skip() || !getname() || (fd = open(nextf, 0)) < 0) {
1406		errprint(gettext("can't open file %s"), nextf);
1407		done(02);
1408	}
1409	tbreak();
1410	/* make it into a clean state, be sure that everything is out */
1411	hpos = po;
1412	esc = un;
1413	ptesc();
1414	ptlead();
1415	ptps();
1416	ptfont();
1417	flusho();
1418	while ((n = read(fd, buf, sizeof buf)) > 0)
1419		write(ptid, buf, n);
1420	close(fd);
1421#endif
1422	return (0);
1423}
1424
1425
1426int
1427casesy()	/* call system */
1428{
1429	char	sybuf[NTM];
1430	int	i;
1431
1432	lgf++;
1433	copyf++;
1434	skip();
1435	for (i = 0; i < NTM - 2; i++)
1436		if ((sybuf[i] = getch()) == '\n')
1437			break;
1438	sybuf[i] = 0;
1439	system(sybuf);
1440	copyf--;
1441	lgf--;
1442
1443	return (0);
1444}
1445
1446
1447int
1448getpn(a)
1449	char *a;
1450{
1451	int n, neg;
1452
1453	if (*a == 0)
1454		return (0);
1455	neg = 0;
1456	for ( ; *a; a++)
1457		switch (*a) {
1458		case '+':
1459		case ',':
1460			continue;
1461		case '-':
1462			neg = 1;
1463			continue;
1464		default:
1465			n = 0;
1466			if (isdigit((unsigned char)*a)) {
1467				do
1468					n = 10 * n + *a++ - '0';
1469				while (isdigit((unsigned char)*a));
1470				a--;
1471			} else
1472				n = 9999;
1473			*pnp++ = neg ? -n : n;
1474			neg = 0;
1475			if (pnp >= &pnlist[NPN-2]) {
1476				errprint(gettext("too many page numbers"));
1477				done3(-3);
1478			}
1479		}
1480	if (neg)
1481		*pnp++ = -9999;
1482	*pnp = -32767;
1483	print = 0;
1484	pnp = pnlist;
1485	if (*pnp != -32767)
1486		chkpn();
1487
1488	return (0);
1489}
1490
1491
1492int
1493setrpt()
1494{
1495	tchar i, j;
1496
1497	copyf++;
1498	raw++;
1499	i = getch0();
1500	copyf--;
1501	raw--;
1502	if (i < 0 || cbits(j = getch0()) == RPT)
1503		return (0);
1504	i &= BYTEMASK;
1505	while (i>0 && pbp < &pbbuf[NC-3]) {
1506		i--;
1507		*pbp++ = j;
1508	}
1509
1510	return (0);
1511}
1512
1513
1514int
1515casedb()
1516{
1517#ifdef	DEBUG
1518	debug = 0;
1519	if (skip())
1520		return (0);
1521	noscale++;
1522	debug = max(atoi(), 0);
1523	noscale = 0;
1524#endif	/* DEBUG */
1525
1526	return (0);
1527}
1528