xref: /csrg-svn/usr.bin/deroff/deroff.c (revision 9094)
19075Srrh #ifndef lint
2*9094Srrh static char sccsid[] = "@(#)deroff.c	4.3	(Berkeley)	82/11/06";
39075Srrh #endif not lint
49075Srrh 
5*9094Srrh #include <stdio.h>
69075Srrh 
7*9094Srrh /*
8*9094Srrh  *	Deroff command -- strip troff, eqn, and Tbl sequences from
9*9094Srrh  *	a file.  Has two flags argument, -w, to cause output one word per line
10*9094Srrh  *	rather than in the original format.
11*9094Srrh  *	-mm (or -ms) causes the corresponding macro's to be interpreted
12*9094Srrh  *	so that just sentences are output
13*9094Srrh  *	-ml  also gets rid of lists.
14*9094Srrh  *	Deroff follows .so and .nx commands, removes contents of macro
15*9094Srrh  *	definitions, equations (both .EQ ... .EN and $...$),
16*9094Srrh  *	Tbl command sequences, and Troff backslash constructions.
17*9094Srrh  *
18*9094Srrh  *	All input is through the Cget macro;
19*9094Srrh  *	the most recently read character is in c.
20*9094Srrh  *
21*9094Srrh  *	Modified by Robert Henry to process -me and -man macros.
22*9094Srrh  */
239075Srrh 
24*9094Srrh #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
25*9094Srrh #define C1get ( (c=getc(infile)) == EOF ? eof() :  c)
269075Srrh 
27*9094Srrh #ifdef DEBUG
28*9094Srrh #  define C	_C()
29*9094Srrh #  define C1	_C1()
30*9094Srrh #else not DEBUG
31*9094Srrh #  define C	Cget
32*9094Srrh #  define C1	C1get
33*9094Srrh #endif not DEBUG
349075Srrh 
359075Srrh #define SKIP while(C != '\n')
369075Srrh #define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
379075Srrh 
38*9094Srrh #define	YES 1
39*9094Srrh #define	NO 0
40*9094Srrh #define	MS 0	/* -ms */
41*9094Srrh #define	MM 1	/* -mm */
42*9094Srrh #define	ME 2	/* -me */
43*9094Srrh #define	MA 3	/* -man */
449075Srrh 
45*9094Srrh #ifdef DEBUG
46*9094Srrh char *mactab[] = {"-ms", "-mm", "-me", "-ma"};
47*9094Srrh #endif DEBUG
48*9094Srrh 
49*9094Srrh #define	ONE 1
50*9094Srrh #define	TWO 2
51*9094Srrh 
529075Srrh #define NOCHAR -2
539075Srrh #define SPECIAL 0
549075Srrh #define APOS 1
559079Srrh #define PUNCT 2
569079Srrh #define DIGIT 3
579079Srrh #define LETTER 4
589075Srrh 
59*9094Srrh int	wordflag;
60*9094Srrh int	msflag;		/* processing a source written using a mac package */
61*9094Srrh int	mac;		/* which package */
62*9094Srrh int	disp;
63*9094Srrh int	parag;
64*9094Srrh int	inmacro;
65*9094Srrh int	intable;
66*9094Srrh int	keepblock;	/* keep blocks of text; normally false when msflag */
679075Srrh 
689079Srrh char chars[128];  /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
699075Srrh 
709075Srrh char line[512];
719075Srrh char *lp;
729075Srrh 
739075Srrh int c;
749075Srrh int pc;
75*9094Srrh int ldelim;
76*9094Srrh int rdelim;
779075Srrh 
789075Srrh 
799075Srrh int argc;
809075Srrh char **argv;
819075Srrh 
829075Srrh char fname[50];
839075Srrh FILE *files[15];
849075Srrh FILE **filesp;
859075Srrh FILE *infile;
86*9094Srrh FILE	*opn();
87*9094Srrh /*
88*9094Srrh  *	Flags for matching conditions other than
89*9094Srrh  *	the macro name
90*9094Srrh  */
91*9094Srrh #define	NONE		0
92*9094Srrh #define	FNEST		1		/* no nested files */
93*9094Srrh #define	NOMAC		2		/* no macro */
94*9094Srrh #define	MAC		3		/* macro */
95*9094Srrh #define	PARAG		4		/* in a paragraph */
96*9094Srrh #define	MSF		5		/* msflag is on */
97*9094Srrh #define	NBLK		6		/* set if no blocks to be kept */
989075Srrh 
99*9094Srrh /*
100*9094Srrh  *	Return codes from macro minions, determine where to jump,
101*9094Srrh  *	how to repeat/reprocess text
102*9094Srrh  */
103*9094Srrh #define	COMX		1		/* goto comx */
104*9094Srrh #define	COM		2		/* goto com */
105*9094Srrh 
1069075Srrh main(ac, av)
1079075Srrh int ac;
1089075Srrh char **av;
1099075Srrh {
1109079Srrh 	register int i;
111*9094Srrh 	int	errflg = 0;
112*9094Srrh 	register	optchar;
1139079Srrh 	FILE *opn();
114*9094Srrh 	int	kflag = NO;
115*9094Srrh 	char	*p;
1169075Srrh 
117*9094Srrh 	wordflag = NO;
118*9094Srrh 	msflag = NO;
119*9094Srrh 	mac = ME;
120*9094Srrh 	disp = NO;
121*9094Srrh 	parag = NO;
122*9094Srrh 	inmacro = NO;
123*9094Srrh 	intable = NO;
124*9094Srrh 	ldelim	= NOCHAR;
125*9094Srrh 	rdelim	= NOCHAR;
126*9094Srrh 	keepblock = YES;
127*9094Srrh 
128*9094Srrh 	for(argc = ac - 1, argv = av + 1;
129*9094Srrh 	    (   (argc > 0)
130*9094Srrh 	     && (argv[0][0] == '-')
131*9094Srrh 	     && (argv[0][1] != '\0') );
132*9094Srrh 	    --argc, ++argv
133*9094Srrh 	){
134*9094Srrh 		for(p = argv[0]+1; *p; ++p) {
135*9094Srrh 			switch(*p) {
136*9094Srrh 			case 'p':
137*9094Srrh 				parag=YES;
138*9094Srrh 				break;
139*9094Srrh 			case 'k':
140*9094Srrh 				kflag = YES;
141*9094Srrh 				break;
142*9094Srrh 			case 'w':
143*9094Srrh 				wordflag = YES;
144*9094Srrh 				kflag = YES;
145*9094Srrh 				break;
146*9094Srrh 			case 'm':
147*9094Srrh 				msflag = YES;
148*9094Srrh 				keepblock = NO;
149*9094Srrh 				switch(p[1]){
150*9094Srrh 				case 'm':	mac = MM; p++; break;
151*9094Srrh 				case 's':	mac = MS; p++; break;
152*9094Srrh 				case 'e':	mac = ME; p++; break;
153*9094Srrh 				case 'a':	mac = MA; p++; break;
154*9094Srrh 				case 'l':	disp = YES; p++; break;
155*9094Srrh 				default:	errflg++; break;
156*9094Srrh 				}
157*9094Srrh 				break;
158*9094Srrh 			default:
159*9094Srrh 				errflg++;
160*9094Srrh 			}
161*9094Srrh 		}
1629075Srrh 	}
163*9094Srrh 
164*9094Srrh 	if (kflag)
165*9094Srrh 		keepblock = YES;
1669079Srrh 	if (errflg)
167*9094Srrh 		fatal("usage: deroff [ -w ] [ -k] [ -m (a e m s l) ] [ file ] ... \n",
168*9094Srrh 			(char *) NULL);
169*9094Srrh 
170*9094Srrh #ifdef DEBUG
171*9094Srrh 	printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
172*9094Srrh 		msflag, mactab[mac], keepblock, disp);
173*9094Srrh #endif DEBUG
174*9094Srrh 	if (argc == 0){
1759079Srrh 		infile = stdin;
176*9094Srrh 	} else {
177*9094Srrh 		infile = opn(argv[0]);
178*9094Srrh 		--argc;
179*9094Srrh 		++argv;
180*9094Srrh 	}
181*9094Srrh 
182*9094Srrh 
1839079Srrh 	files[0] = infile;
1849079Srrh 	filesp = &files[0];
1859075Srrh 
1869079Srrh 	for(i='a'; i<='z' ; ++i)
1879079Srrh 		chars[i] = LETTER;
1889079Srrh 	for(i='A'; i<='Z'; ++i)
1899079Srrh 		chars[i] = LETTER;
1909079Srrh 	for(i='0'; i<='9'; ++i)
1919079Srrh 		chars[i] = DIGIT;
1929079Srrh 	chars['\''] = APOS;
1939079Srrh 	chars['&'] = APOS;
1949079Srrh 	chars['.'] = PUNCT;
1959079Srrh 	chars[','] = PUNCT;
1969079Srrh 	chars[';'] = PUNCT;
1979079Srrh 	chars['?'] = PUNCT;
1989079Srrh 	chars[':'] = PUNCT;
1999079Srrh 	work();
2009079Srrh }
2019079Srrh char *calloc();
2029075Srrh 
2039075Srrh skeqn()
2049075Srrh {
2059079Srrh 	while((c = getc(infile)) != rdelim)
2069079Srrh 		if(c == EOF)
2079079Srrh 			c = eof();
2089079Srrh 		else if(c == '"')
2099079Srrh 			while( (c = getc(infile)) != '"')
2109079Srrh 				if(c == EOF)
2119075Srrh 					c = eof();
2129079Srrh 				else if(c == '\\')
2139079Srrh 					if((c = getc(infile)) == EOF)
2149079Srrh 						c = eof();
2159079Srrh 	if(msflag)return(c='x');
2169079Srrh 	return(c = ' ');
2179075Srrh }
2189075Srrh 
2199075Srrh FILE *opn(p)
2209075Srrh register char *p;
2219075Srrh {
2229079Srrh 	FILE *fd;
2239075Srrh 
2249079Srrh 	if( (fd = fopen(p, "r")) == NULL)
2259079Srrh 		fatal("Cannot open file %s\n", p);
2269075Srrh 
2279079Srrh 	return(fd);
2289075Srrh }
2299075Srrh 
2309075Srrh eof()
2319075Srrh {
2329079Srrh 	if(infile != stdin)
2339079Srrh 		fclose(infile);
2349079Srrh 	if(filesp > files)
2359079Srrh 		infile = *--filesp;
236*9094Srrh 	else if (argc > 0) {
237*9094Srrh 		infile = opn(argv[0]);
238*9094Srrh 		--argc;
239*9094Srrh 		++argv;
240*9094Srrh 	} else
2419079Srrh 		exit(0);
2429079Srrh 	return(C);
2439075Srrh }
2449075Srrh 
2459075Srrh getfname()
2469075Srrh {
2479079Srrh 	register char *p;
2489079Srrh 	struct chain {
2499079Srrh 		struct chain *nextp;
2509079Srrh 		char *datap;
2519079Srrh 	} *chainblock;
2529079Srrh 	register struct chain *q;
2539079Srrh 	static struct chain *namechain	= NULL;
2549079Srrh 	char *copys();
2559075Srrh 
2569079Srrh 	while(C == ' ') ;
2579075Srrh 
2589079Srrh 	for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
2599079Srrh 		C;
2609079Srrh 	*p = '\0';
2619079Srrh 	while(c != '\n')
2629079Srrh 		C;
2639075Srrh 
2649079Srrh 	/* see if this name has already been used */
2659075Srrh 
2669079Srrh 	for(q = namechain ; q; q = q->nextp)
2679079Srrh 		if( ! strcmp(fname, q->datap))
2689075Srrh 		{
2699079Srrh 			fname[0] = '\0';
2709079Srrh 			return;
2719075Srrh 		}
2729075Srrh 
2739079Srrh 	q = (struct chain *) calloc(1, sizeof(*chainblock));
2749079Srrh 	q->nextp = namechain;
2759079Srrh 	q->datap = copys(fname);
2769079Srrh 	namechain = q;
2779075Srrh }
2789075Srrh 
2799075Srrh fatal(s,p)
2809075Srrh char *s, *p;
2819075Srrh {
2829079Srrh 	fprintf(stderr, "Deroff: ");
2839079Srrh 	fprintf(stderr, s, p);
2849079Srrh 	exit(1);
2859075Srrh }
2869079Srrh 
287*9094Srrh /*ARGSUSED*/
288*9094Srrh textline(str, const)
289*9094Srrh 	char	*str;
290*9094Srrh 	int	const;
291*9094Srrh {
292*9094Srrh 	if (wordflag) {
293*9094Srrh 		msputwords(0);
294*9094Srrh 		return;
295*9094Srrh 	}
296*9094Srrh 	puts(str);
297*9094Srrh }
298*9094Srrh 
2999075Srrh work()
3009075Srrh {
3019079Srrh 	for( ;; )
3029075Srrh 	{
303*9094Srrh 		C;
304*9094Srrh #ifdef FULLDEBUG
305*9094Srrh 		printf("Starting work with `%c'\n", c);
306*9094Srrh #endif FULLDEBUG
307*9094Srrh 		if(c == '.'  ||  c == '\'')
3089079Srrh 			comline();
3099079Srrh 		else
310*9094Srrh 			regline(textline, TWO);
3119075Srrh 	}
3129075Srrh }
3139075Srrh 
314*9094Srrh regline(pfunc, const)
315*9094Srrh 	int	(*pfunc)();
316*9094Srrh 	int	const;
3179075Srrh {
3189079Srrh 	line[0] = c;
3199079Srrh 	lp = line;
3209079Srrh 	for( ; ; )
3219075Srrh 	{
322*9094Srrh 		if(c == '\\') {
3239079Srrh 			*lp = ' ';
3249079Srrh 			backsl();
3259075Srrh 		}
326*9094Srrh 		if(c == '\n')
327*9094Srrh 			break;
328*9094Srrh 		if(intable && c=='T') {
3299079Srrh 			*++lp = C;
330*9094Srrh 			if(c=='{' || c=='}') {
3319079Srrh 				lp[-1] = ' ';
3329079Srrh 				*lp = C;
3339075Srrh 			}
334*9094Srrh 		} else {
335*9094Srrh 			*++lp = C;
3369075Srrh 		}
3379075Srrh 	}
3389075Srrh 
3399079Srrh 	*lp = '\0';
3409075Srrh 
3419079Srrh 	if(line[0] != '\0')
342*9094Srrh 		(*pfunc)(line, const);
3439075Srrh }
3449075Srrh 
3459075Srrh macro()
3469075Srrh {
3479079Srrh 	if(msflag){
3489079Srrh 		do {
3499079Srrh 			SKIP;
3509079Srrh 		}		while(C!='.' || C!='.' || C=='.');	/* look for  .. */
3519079Srrh 		if(c != '\n')SKIP;
3529079Srrh 		return;
3539079Srrh 	}
3549079Srrh 	SKIP;
3559079Srrh 	inmacro = YES;
3569075Srrh }
3579075Srrh 
3589075Srrh tbl()
3599075Srrh {
3609079Srrh 	while(C != '.');
3619079Srrh 	SKIP;
3629079Srrh 	intable = YES;
3639075Srrh }
3649075Srrh stbl()
3659075Srrh {
3669079Srrh 	while(C != '.');
3679079Srrh 	SKIP_TO_COM;
3689079Srrh 	if(c != 'T' || C != 'E'){
3699079Srrh 		SKIP;
3709079Srrh 		pc=c;
3719079Srrh 		while(C != '.' || pc != '\n' || C != 'T' || C != 'E')pc=c;
3729079Srrh 	}
3739075Srrh }
3749075Srrh 
3759075Srrh eqn()
3769075Srrh {
3779079Srrh 	register int c1, c2;
3789079Srrh 	register int dflg;
3799079Srrh 	char last;
3809075Srrh 
3819079Srrh 	last=0;
3829079Srrh 	dflg = 1;
3839079Srrh 	SKIP;
3849075Srrh 
3859079Srrh 	for( ;;)
3869075Srrh 	{
3879079Srrh 		if(C1 == '.'  || c == '\'')
3889075Srrh 		{
3899079Srrh 			while(C1==' ' || c=='\t')
3909079Srrh 				;
3919079Srrh 			if(c=='E' && C1=='N')
3929075Srrh 			{
3939079Srrh 				SKIP;
3949079Srrh 				if(msflag && dflg){
3959079Srrh 					putchar('x');
3969079Srrh 					putchar(' ');
3979079Srrh 					if(last){
3989079Srrh 						putchar(last);
3999079Srrh 						putchar('\n');
4009079Srrh 					}
4019079Srrh 				}
4029079Srrh 				return;
4039075Srrh 			}
4049075Srrh 		}
4059079Srrh 		else if(c == 'd')	/* look for delim */
4069075Srrh 		{
4079079Srrh 			if(C1=='e' && C1=='l')
4089079Srrh 				if( C1=='i' && C1=='m')
4099075Srrh 				{
4109079Srrh 					while(C1 == ' ');
4119079Srrh 					if((c1=c)=='\n' || (c2=C1)=='\n'
4129079Srrh 					    || (c1=='o' && c2=='f' && C1=='f') )
4139079Srrh 					{
4149079Srrh 						ldelim = NOCHAR;
4159079Srrh 						rdelim = NOCHAR;
4169079Srrh 					}
4179079Srrh 					else	{
4189079Srrh 						ldelim = c1;
4199079Srrh 						rdelim = c2;
4209079Srrh 					}
4219075Srrh 				}
4229075Srrh 			dflg = 0;
4239075Srrh 		}
4249075Srrh 
4259079Srrh 		if(c != '\n') while(C1 != '\n'){
4269079Srrh 			if(chars[c] == PUNCT)last = c;
4279079Srrh 			else if(c != ' ')last = 0;
4289079Srrh 		}
4299075Srrh 	}
4309075Srrh }
4319075Srrh 
4329075Srrh backsl()	/* skip over a complete backslash construction */
4339075Srrh {
4349079Srrh 	int bdelim;
4359075Srrh 
4369079Srrh sw:
4379079Srrh 	switch(C)
4389075Srrh 	{
4399075Srrh 	case '"':
4409075Srrh 		SKIP;
4419075Srrh 		return;
4429075Srrh 	case 's':
4439075Srrh 		if(C == '\\') backsl();
4449075Srrh 		else	{
4459075Srrh 			while(C>='0' && c<='9') ;
4469075Srrh 			ungetc(c,infile);
4479075Srrh 			c = '0';
4489079Srrh 		}
4499075Srrh 		--lp;
4509075Srrh 		return;
4519075Srrh 
4529075Srrh 	case 'f':
4539075Srrh 	case 'n':
4549075Srrh 	case '*':
4559075Srrh 		if(C != '(')
4569075Srrh 			return;
4579075Srrh 
4589075Srrh 	case '(':
4599079Srrh 		if(msflag){
4609079Srrh 			if(C == 'e'){
4619079Srrh 				if(C == 'm'){
4629079Srrh 					*lp = '-';
4639079Srrh 					return;
4649079Srrh 				}
4659079Srrh 			}
4669079Srrh 			else if(c != '\n')C;
4679079Srrh 			return;
4689079Srrh 		}
4699075Srrh 		if(C != '\n') C;
4709075Srrh 		return;
4719075Srrh 
4729075Srrh 	case '$':
4739075Srrh 		C;	/* discard argument number */
4749075Srrh 		return;
4759075Srrh 
4769075Srrh 	case 'b':
4779075Srrh 	case 'x':
4789075Srrh 	case 'v':
4799075Srrh 	case 'h':
4809075Srrh 	case 'w':
4819075Srrh 	case 'o':
4829075Srrh 	case 'l':
4839075Srrh 	case 'L':
4849075Srrh 		if( (bdelim=C) == '\n')
4859075Srrh 			return;
4869075Srrh 		while(C!='\n' && c!=bdelim)
4879075Srrh 			if(c == '\\') backsl();
4889075Srrh 		return;
4899075Srrh 
4909075Srrh 	case '\\':
4919075Srrh 		if(inmacro)
4929075Srrh 			goto sw;
4939075Srrh 	default:
4949075Srrh 		return;
4959075Srrh 	}
4969075Srrh }
4979075Srrh 
4989075Srrh char *copys(s)
4999075Srrh register char *s;
5009075Srrh {
5019079Srrh 	register char *t, *t0;
5029075Srrh 
5039079Srrh 	if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL)
5049079Srrh 		fatal("Cannot allocate memory", (char *) NULL);
5059075Srrh 
5069079Srrh 	while( *t++ = *s++ )
5079079Srrh 		;
5089079Srrh 	return(t0);
5099075Srrh }
510*9094Srrh 
511*9094Srrh sce()
512*9094Srrh {
5139079Srrh 	register char *ap;
5149079Srrh 	register int n, i;
5159079Srrh 	char a[10];
5169075Srrh 	for(ap=a;C != '\n';ap++){
5179075Srrh 		*ap = c;
5189075Srrh 		if(ap == &a[9]){
5199075Srrh 			SKIP;
5209075Srrh 			ap=a;
5219075Srrh 			break;
5229075Srrh 		}
5239075Srrh 	}
5249075Srrh 	if(ap != a)n = atoi(a);
5259075Srrh 	else n = 1;
5269075Srrh 	for(i=0;i<n;){
5279075Srrh 		if(C == '.'){
5289075Srrh 			if(C == 'c'){
5299075Srrh 				if(C == 'e'){
5309075Srrh 					while(C == ' ');
5319079Srrh 					if(c == '0'){
5329079Srrh 						SKIP;
5339079Srrh 						break;
5349079Srrh 					}
5359075Srrh 					else SKIP;
5369075Srrh 				}
5379075Srrh 				else SKIP;
5389075Srrh 			}
5399079Srrh 			else if(c == 'P' || C == 'P'){
5409079Srrh 				if(c != '\n')SKIP;
5419079Srrh 				break;
5429079Srrh 			}
5439079Srrh 			else if(c != '\n')SKIP;
5449075Srrh 		}
5459075Srrh 		else {
5469075Srrh 			SKIP;
5479075Srrh 			i++;
5489075Srrh 		}
5499075Srrh 	}
5509075Srrh }
551*9094Srrh 
5529079Srrh refer(c1)
5539079Srrh {
5549079Srrh 	register int c2;
5559079Srrh 	if(c1 != '\n')
5569079Srrh 		SKIP;
5579079Srrh 	while(1){
5589079Srrh 		if(C != '.')
5599079Srrh 			SKIP;
5609079Srrh 		else {
5619079Srrh 			if(C != ']')
5629079Srrh 				SKIP;
5639079Srrh 			else {
5649079Srrh 				while(C != '\n')
5659079Srrh 					c2=c;
5669079Srrh 				if(chars[c2] == PUNCT)putchar(c2);
5679079Srrh 				return;
5689079Srrh 			}
5699079Srrh 		}
5709079Srrh 	}
5719079Srrh }
572*9094Srrh 
573*9094Srrh inpic()
574*9094Srrh {
5759079Srrh 	register int c1;
5769079Srrh 	register char *p1;
5779079Srrh 	SKIP;
5789079Srrh 	p1 = line;
5799079Srrh 	c = '\n';
5809079Srrh 	while(1){
5819079Srrh 		c1 = c;
5829079Srrh 		if(C == '.' && c1 == '\n'){
5839079Srrh 			if(C != 'P'){
5849079Srrh 				if(c == '\n')continue;
5859079Srrh 				else { SKIP; c='\n'; continue;}
5869079Srrh 			}
5879079Srrh 			if(C != 'E'){
5889079Srrh 				if(c == '\n')continue;
5899079Srrh 				else { SKIP; c='\n';continue; }
5909079Srrh 			}
5919079Srrh 			SKIP;
5929079Srrh 			return;
5939079Srrh 		}
5949079Srrh 		else if(c == '\"'){
5959079Srrh 			while(C != '\"'){
5969079Srrh 				if(c == '\\'){
5979079Srrh 					if(C == '\"')continue;
5989079Srrh 					ungetc(c,infile);
5999079Srrh 					backsl();
6009079Srrh 				}
6019079Srrh 				else *p1++ = c;
6029079Srrh 			}
6039079Srrh 			*p1++ = ' ';
6049079Srrh 		}
6059079Srrh 		else if(c == '\n' && p1 != line){
6069079Srrh 			*p1 = '\0';
607*9094Srrh 			if(wordflag)msputwords(NO);
6089079Srrh 			else {
6099079Srrh 				puts(line);
6109079Srrh 				putchar('\n');
6119079Srrh 			}
6129079Srrh 			p1 = line;
6139079Srrh 		}
6149079Srrh 	}
6159079Srrh }
616*9094Srrh 
617*9094Srrh #ifdef DEBUG
618*9094Srrh _C1()
619*9094Srrh {
620*9094Srrh 	return(C1get);
621*9094Srrh }
622*9094Srrh _C()
623*9094Srrh {
624*9094Srrh 	return(Cget);
625*9094Srrh }
626*9094Srrh #endif DEBUG
627*9094Srrh 
628*9094Srrh /*
629*9094Srrh  *	Macro processing
630*9094Srrh  *
631*9094Srrh  *	Macro table definitions
632*9094Srrh  */
633*9094Srrh #define	reg	register
634*9094Srrh typedef	int pacmac;		/* compressed macro name */
635*9094Srrh int	argconcat = 0;		/* concat arguments together (-me only) */
636*9094Srrh 
637*9094Srrh #define	tomac(c1, c2)		((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
638*9094Srrh #define	frommac(src, c1, c2)	(((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
639*9094Srrh 
640*9094Srrh struct	mactab{
641*9094Srrh 	int	condition;
642*9094Srrh 	pacmac	macname;
643*9094Srrh 	int	(*func)();
644*9094Srrh };
645*9094Srrh struct	mactab	troffmactab[];
646*9094Srrh struct	mactab	ppmactab[];
647*9094Srrh struct	mactab	msmactab[];
648*9094Srrh struct	mactab	mmmactab[];
649*9094Srrh struct	mactab	memactab[];
650*9094Srrh struct	mactab	manmactab[];
651*9094Srrh /*
652*9094Srrh  *	macro table initialization
653*9094Srrh  */
654*9094Srrh #define	M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
655*9094Srrh 
656*9094Srrh /*
657*9094Srrh  *	Put out a macro line, using ms and mm conventions.
658*9094Srrh  */
659*9094Srrh msputmac(s, const)
660*9094Srrh 	register char *s;
661*9094Srrh 	int	const;
662*9094Srrh {
663*9094Srrh 	register char *t;
664*9094Srrh 	register found;
665*9094Srrh 	int last;
666*9094Srrh 	found = 0;
667*9094Srrh 
668*9094Srrh 	if (wordflag) {
669*9094Srrh 		msputwords(YES);
670*9094Srrh 		return;
671*9094Srrh 	}
672*9094Srrh 	while(*s)
673*9094Srrh 	{
674*9094Srrh 		while(*s==' ' || *s=='\t')
675*9094Srrh 			putchar(*s++);
676*9094Srrh 		for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
677*9094Srrh 			;
678*9094Srrh 		if(*s == '\"')s++;
679*9094Srrh 		if(t>s+const && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
680*9094Srrh 			while(s < t)
681*9094Srrh 				if(*s == '\"')s++;
682*9094Srrh 				else
683*9094Srrh 					putchar(*s++);
684*9094Srrh 			last = *(t-1);
685*9094Srrh 			found++;
686*9094Srrh 		}
687*9094Srrh 		else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0')
688*9094Srrh 			putchar(*s++);
689*9094Srrh 		else{
690*9094Srrh 			last = *(t-1);
691*9094Srrh 			s = t;
692*9094Srrh 		}
693*9094Srrh 	}
694*9094Srrh 	putchar('\n');
695*9094Srrh 	if(msflag && chars[last] == PUNCT){
696*9094Srrh 		putchar(last);
697*9094Srrh 		putchar('\n');
698*9094Srrh 	}
699*9094Srrh }
700*9094Srrh /*
701*9094Srrh  *	put out words (for the -w option) with ms and mm conventions
702*9094Srrh  */
703*9094Srrh msputwords(macline)
704*9094Srrh 	int macline;	/* is this is a macro line */
705*9094Srrh {
706*9094Srrh 	register char *p, *p1;
707*9094Srrh 	int i, nlet;
708*9094Srrh 
709*9094Srrh 	for(p1 = line ; ;) {
710*9094Srrh 		/*
711*9094Srrh 		 *	skip initial specials ampersands and apostrophes
712*9094Srrh 		 */
713*9094Srrh 		while( chars[*p1] < DIGIT)
714*9094Srrh 			if(*p1++ == '\0') return;
715*9094Srrh 		nlet = 0;
716*9094Srrh 		for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
717*9094Srrh 			if(i == LETTER) ++nlet;
718*9094Srrh 
719*9094Srrh 		if (   (macline && nlet > 1)
720*9094Srrh 		    || (!macline && nlet > 2
721*9094Srrh 				 && chars[p1[0]] == LETTER
722*9094Srrh 				 && chars[p1[1]] == LETTER) )
723*9094Srrh 		{
724*9094Srrh 			/*
725*9094Srrh 			 *	delete trailing ampersands and apostrophes
726*9094Srrh 			 */
727*9094Srrh 			while(  (p[-1]=='\'')
728*9094Srrh 			     || (p[-1]=='&')
729*9094Srrh 			     || (chars[p[-1]] == PUNCT) ){
730*9094Srrh 				--p;
731*9094Srrh 			}
732*9094Srrh 			while(p1 < p)
733*9094Srrh 				putchar(*p1++);
734*9094Srrh 			putchar('\n');
735*9094Srrh 		} else {
736*9094Srrh 			p1 = p;
737*9094Srrh 		}
738*9094Srrh 	}
739*9094Srrh }
740*9094Srrh /*
741*9094Srrh  *	put out a macro using the me conventions
742*9094Srrh  */
743*9094Srrh #define SKIPBLANK(cp)	while(*cp == ' ' || *cp == '\t') { cp++; }
744*9094Srrh #define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
745*9094Srrh 
746*9094Srrh meputmac(cp, const)
747*9094Srrh 	reg	char	*cp;
748*9094Srrh 		int	const;
749*9094Srrh {
750*9094Srrh 	reg	char	*np;
751*9094Srrh 		int	found;
752*9094Srrh 		int	argno;
753*9094Srrh 		int	last;
754*9094Srrh 		int	inquote;
755*9094Srrh 
756*9094Srrh 	if (wordflag) {
757*9094Srrh 		meputwords(YES);
758*9094Srrh 		return;
759*9094Srrh 	}
760*9094Srrh 	for (argno = 0; *cp; argno++){
761*9094Srrh 		SKIPBLANK(cp);
762*9094Srrh 		inquote = (*cp == '"');
763*9094Srrh 		if (inquote)
764*9094Srrh 			cp++;
765*9094Srrh 		for (np = cp; *np; np++){
766*9094Srrh 			switch(*np){
767*9094Srrh 			case '\n':
768*9094Srrh 			case '\0':	break;
769*9094Srrh 			case '\t':
770*9094Srrh 			case ' ':	if (inquote) {
771*9094Srrh 						continue;
772*9094Srrh 					} else {
773*9094Srrh 						goto endarg;
774*9094Srrh 					}
775*9094Srrh 			case '"':	if(inquote && np[1] == '"'){
776*9094Srrh 						strcpy(np, np + 1);
777*9094Srrh 						np++;
778*9094Srrh 						continue;
779*9094Srrh 					} else {
780*9094Srrh 						*np = ' '; 	/* bye bye " */
781*9094Srrh 						goto endarg;
782*9094Srrh 					}
783*9094Srrh 			default:	continue;
784*9094Srrh 			}
785*9094Srrh 		}
786*9094Srrh 		endarg: ;
787*9094Srrh 		/*
788*9094Srrh 		 *	cp points at the first char in the arg
789*9094Srrh 		 *	np points one beyond the last char in the arg
790*9094Srrh 		 */
791*9094Srrh 		if ((argconcat == 0) || (argconcat != argno)) {
792*9094Srrh 			putchar(' ');
793*9094Srrh 		}
794*9094Srrh #ifdef FULLDEBUG
795*9094Srrh 		{
796*9094Srrh 			char	*p;
797*9094Srrh 			printf("[%d,%d: ", argno, np - cp);
798*9094Srrh 			for (p = cp; p < np; p++) {
799*9094Srrh 				putchar(*p);
800*9094Srrh 			}
801*9094Srrh 			printf("]");
802*9094Srrh 		}
803*9094Srrh #endif FULLDEBUG
804*9094Srrh 		/*
805*9094Srrh 		 *	Determine if the argument merits being printed
806*9094Srrh 		 *
807*9094Srrh 		 *	const is the cut off point below which something
808*9094Srrh 		 *	is not a word.
809*9094Srrh 		 */
810*9094Srrh 		if (   ( (np - cp) > const)
811*9094Srrh 		    && (    inquote
812*9094Srrh 		         || (chars[cp[0]] == LETTER)) ){
813*9094Srrh 			for (cp = cp; cp < np; cp++){
814*9094Srrh 				putchar(*cp);
815*9094Srrh 			}
816*9094Srrh 			last = np[-1];
817*9094Srrh 			found++;
818*9094Srrh 		} else
819*9094Srrh 		if(found && (np - cp == 1) && chars[*cp] == PUNCT){
820*9094Srrh 			putchar(*cp);
821*9094Srrh 		} else {
822*9094Srrh 			last = np[-1];
823*9094Srrh 		}
824*9094Srrh 		cp = np;
825*9094Srrh 	}
826*9094Srrh 	if(msflag && chars[last] == PUNCT)
827*9094Srrh 		putchar(last);
828*9094Srrh 	putchar('\n');
829*9094Srrh }
830*9094Srrh /*
831*9094Srrh  *	put out words (for the -w option) with ms and mm conventions
832*9094Srrh  */
833*9094Srrh meputwords(macline)
834*9094Srrh 	int	macline;
835*9094Srrh {
836*9094Srrh 	msputwords(macline);
837*9094Srrh }
838*9094Srrh /*
839*9094Srrh  *
840*9094Srrh  *	Skip over a nested set of macros
841*9094Srrh  *
842*9094Srrh  *	Possible arguments to noblock are:
843*9094Srrh  *
844*9094Srrh  *	fi	end of unfilled text
845*9094Srrh  *	PE	pic ending
846*9094Srrh  *	DE	display ending
847*9094Srrh  *
848*9094Srrh  *	for ms and mm only:
849*9094Srrh  *		KE	keep ending
850*9094Srrh  *
851*9094Srrh  *		NE	undocumented match to NS (for mm?)
852*9094Srrh  *		LE	mm only: matches RL or *L (for lists)
853*9094Srrh  *
854*9094Srrh  *	for me:
855*9094Srrh  *		([lqbzcdf]
856*9094Srrh  */
857*9094Srrh 
858*9094Srrh noblock(a1, a2)
859*9094Srrh 	char a1, a2;
860*9094Srrh {
861*9094Srrh 	register int c1,c2;
862*9094Srrh 	register int eqnf;
863*9094Srrh 	int lct;
864*9094Srrh 	lct = 0;
865*9094Srrh 	eqnf = 1;
866*9094Srrh 	SKIP;
867*9094Srrh 	while(1){
868*9094Srrh 		while(C != '.')
869*9094Srrh 			if(c == '\n')
870*9094Srrh 				continue;
871*9094Srrh 			else
872*9094Srrh 				SKIP;
873*9094Srrh 		if((c1=C) == '\n')
874*9094Srrh 			continue;
875*9094Srrh 		if((c2=C) == '\n')
876*9094Srrh 			continue;
877*9094Srrh 		if(c1==a1 && c2 == a2){
878*9094Srrh 			SKIP;
879*9094Srrh 			if(lct != 0){
880*9094Srrh 				lct--;
881*9094Srrh 				continue;
882*9094Srrh 			}
883*9094Srrh 			if(eqnf)
884*9094Srrh 				putchar('.');
885*9094Srrh 			putchar('\n');
886*9094Srrh 			return;
887*9094Srrh 		} else if(a1 == 'L' && c2 == 'L'){
888*9094Srrh 			lct++;
889*9094Srrh 			SKIP;
890*9094Srrh 		}
891*9094Srrh 		/*
892*9094Srrh 		 *	equations (EQ) nested within a display
893*9094Srrh 		 */
894*9094Srrh 		else if(c1 == 'E' && c2 == 'Q'){
895*9094Srrh 			if (   (mac == ME && a1 == ')')
896*9094Srrh 			    || (mac != ME && a1 == 'D') ) {
897*9094Srrh 				eqn();
898*9094Srrh 				eqnf=0;
899*9094Srrh 			}
900*9094Srrh 		}
901*9094Srrh 		/*
902*9094Srrh 		 *	turning on filling is done by the paragraphing
903*9094Srrh 		 *	macros
904*9094Srrh 		 */
905*9094Srrh 		else if(a1 == 'f') {	/* .fi */
906*9094Srrh 			if  (  (mac == ME && (c2 == 'h' || c2 == 'p'))
907*9094Srrh 			     ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) {
908*9094Srrh 				SKIP;
909*9094Srrh 				return;
910*9094Srrh 			}
911*9094Srrh 		} else {
912*9094Srrh 			SKIP;
913*9094Srrh 		}
914*9094Srrh 	}
915*9094Srrh }
916*9094Srrh 
917*9094Srrh EQ()
918*9094Srrh {
919*9094Srrh 	eqn();
920*9094Srrh 	return(0);
921*9094Srrh }
922*9094Srrh domacro()
923*9094Srrh {
924*9094Srrh 	macro();
925*9094Srrh 	return(0);
926*9094Srrh }
927*9094Srrh PS()
928*9094Srrh {
929*9094Srrh 	if (!msflag) {
930*9094Srrh 		inpic();
931*9094Srrh 	} else {
932*9094Srrh 		noblock('P', 'E');
933*9094Srrh 	}
934*9094Srrh 	return(0);
935*9094Srrh }
936*9094Srrh 
937*9094Srrh skip()
938*9094Srrh {
939*9094Srrh 	SKIP;
940*9094Srrh 	return(0);
941*9094Srrh }
942*9094Srrh 
943*9094Srrh intbl()
944*9094Srrh {
945*9094Srrh 	if(msflag){
946*9094Srrh 		stbl();
947*9094Srrh 	}
948*9094Srrh 	else tbl();
949*9094Srrh 	return(0);
950*9094Srrh }
951*9094Srrh 
952*9094Srrh outtbl(){ intable = NO; }
953*9094Srrh 
954*9094Srrh so()
955*9094Srrh {
956*9094Srrh 	getfname();
957*9094Srrh 	if( fname[0] )
958*9094Srrh 		infile = *++filesp = opn( fname );
959*9094Srrh 	return(0);
960*9094Srrh }
961*9094Srrh nx()
962*9094Srrh {
963*9094Srrh 	getfname();
964*9094Srrh 	if(fname[0] == '\0') exit(0);
965*9094Srrh 	if(infile != stdin)
966*9094Srrh 		fclose(infile);
967*9094Srrh 	infile = *filesp = opn(fname);
968*9094Srrh 	return(0);
969*9094Srrh }
970*9094Srrh skiptocom(){ SKIP_TO_COM; return(COMX); }
971*9094Srrh 
972*9094Srrh PP(c12)
973*9094Srrh 	pacmac	c12;
974*9094Srrh {
975*9094Srrh 	int	c1, c2;
976*9094Srrh 
977*9094Srrh 	frommac(c12, c1, c2);
978*9094Srrh 	printf(".%c%c",c1,c2);
979*9094Srrh 	while(C != '\n')putchar(c);
980*9094Srrh 	putchar('\n');
981*9094Srrh 	return(0);
982*9094Srrh }
983*9094Srrh AU()
984*9094Srrh {
985*9094Srrh 	if(mac==MM) {
986*9094Srrh 		return(0);
987*9094Srrh 	} else {
988*9094Srrh 		SKIP_TO_COM;
989*9094Srrh 		return(COMX);
990*9094Srrh 	}
991*9094Srrh }
992*9094Srrh 
993*9094Srrh SH(c12)
994*9094Srrh 	pacmac	c12;
995*9094Srrh {
996*9094Srrh 	int	c1, c2;
997*9094Srrh 
998*9094Srrh 	frommac(c12, c1, c2);
999*9094Srrh 
1000*9094Srrh 	if(parag){
1001*9094Srrh 		printf(".%c%c",c1,c2);
1002*9094Srrh 		while(C != '\n')putchar(c);
1003*9094Srrh 		putchar(c);
1004*9094Srrh 		putchar('!');
1005*9094Srrh 		while(1){
1006*9094Srrh 			while(C != '\n')putchar(c);
1007*9094Srrh 			putchar('\n');
1008*9094Srrh 			if(C == '.')
1009*9094Srrh 				return(COM);
1010*9094Srrh 			putchar('!');
1011*9094Srrh 			putchar(c);
1012*9094Srrh 		}
1013*9094Srrh 		/*NOTREACHED*/
1014*9094Srrh 	} else {
1015*9094Srrh 		SKIP_TO_COM;
1016*9094Srrh 		return(COMX);
1017*9094Srrh 	}
1018*9094Srrh }
1019*9094Srrh 
1020*9094Srrh UX()
1021*9094Srrh {
1022*9094Srrh 	if(wordflag)
1023*9094Srrh 		printf("UNIX\n");
1024*9094Srrh 	else
1025*9094Srrh 		printf("UNIX ");
1026*9094Srrh 	return(0);
1027*9094Srrh }
1028*9094Srrh 
1029*9094Srrh MMHU(c12)
1030*9094Srrh 	pacmac	c12;
1031*9094Srrh {
1032*9094Srrh 	int	c1, c2;
1033*9094Srrh 
1034*9094Srrh 	frommac(c12, c1, c2);
1035*9094Srrh 	if(parag){
1036*9094Srrh 		printf(".%c%c",c1,c2);
1037*9094Srrh 		while(C != '\n')putchar(c);
1038*9094Srrh 		putchar('\n');
1039*9094Srrh 	} else {
1040*9094Srrh 		SKIP;
1041*9094Srrh 	}
1042*9094Srrh 	return(0);
1043*9094Srrh }
1044*9094Srrh 
1045*9094Srrh mesnblock(c12)
1046*9094Srrh 	pacmac	c12;
1047*9094Srrh {
1048*9094Srrh 	int	c1, c2;
1049*9094Srrh 
1050*9094Srrh 	frommac(c12, c1, c2);
1051*9094Srrh 	noblock(')',c2);
1052*9094Srrh 	return(0);
1053*9094Srrh }
1054*9094Srrh mssnblock(c12)
1055*9094Srrh 	pacmac	c12;
1056*9094Srrh {
1057*9094Srrh 	int	c1, c2;
1058*9094Srrh 
1059*9094Srrh 	frommac(c12, c1, c2);
1060*9094Srrh 	noblock(c1,'E');
1061*9094Srrh 	return(0);
1062*9094Srrh }
1063*9094Srrh nf()
1064*9094Srrh {
1065*9094Srrh 	noblock('f','i');
1066*9094Srrh 	return(0);
1067*9094Srrh }
1068*9094Srrh 
1069*9094Srrh ce()
1070*9094Srrh {
1071*9094Srrh 	sce();
1072*9094Srrh 	return(0);
1073*9094Srrh }
1074*9094Srrh 
1075*9094Srrh meip(c12)
1076*9094Srrh 	pacmac	c12;
1077*9094Srrh {
1078*9094Srrh 	if(parag)
1079*9094Srrh 		mepp(c12);
1080*9094Srrh 	else if (wordflag)	/* save the tag */
1081*9094Srrh 		regline(meputmac, ONE);
1082*9094Srrh 	else {
1083*9094Srrh 		SKIP;
1084*9094Srrh 	}
1085*9094Srrh 	return(0);
1086*9094Srrh }
1087*9094Srrh /*
1088*9094Srrh  *	only called for -me .pp or .sh, when parag is on
1089*9094Srrh  */
1090*9094Srrh mepp(c12)
1091*9094Srrh 	pacmac	c12;
1092*9094Srrh {
1093*9094Srrh 	PP(c12);		/* eats the line */
1094*9094Srrh 	return(0);
1095*9094Srrh }
1096*9094Srrh /*
1097*9094Srrh  *	Start of a section heading; output the section name if doing words
1098*9094Srrh  */
1099*9094Srrh mesh(c12)
1100*9094Srrh 	pacmac	c12;
1101*9094Srrh {
1102*9094Srrh 	if (parag)
1103*9094Srrh 		mepp(c12);
1104*9094Srrh 	else if (wordflag)
1105*9094Srrh 		defcomline(c12);
1106*9094Srrh 	else {
1107*9094Srrh 		SKIP;
1108*9094Srrh 	}
1109*9094Srrh 	return(0);
1110*9094Srrh }
1111*9094Srrh /*
1112*9094Srrh  *	process a font setting
1113*9094Srrh  */
1114*9094Srrh mefont(c12)
1115*9094Srrh 	pacmac	c12;
1116*9094Srrh {
1117*9094Srrh 	argconcat = 1;
1118*9094Srrh 	defcomline(c12);
1119*9094Srrh 	argconcat = 0;
1120*9094Srrh 	return(0);
1121*9094Srrh }
1122*9094Srrh manfont(c12)
1123*9094Srrh 	pacmac	c12;
1124*9094Srrh {
1125*9094Srrh 	return(mefont(c12));
1126*9094Srrh }
1127*9094Srrh manpp(c12)
1128*9094Srrh 	pacmac	c12;
1129*9094Srrh {
1130*9094Srrh 	return(mepp(c12));
1131*9094Srrh }
1132*9094Srrh 
1133*9094Srrh defcomline(c12)
1134*9094Srrh 	pacmac	c12;
1135*9094Srrh {
1136*9094Srrh 	int	c1, c2;
1137*9094Srrh 
1138*9094Srrh 	frommac(c12, c1, c2);
1139*9094Srrh 	if(msflag && mac==MM && c2=='L'){
1140*9094Srrh 		if(disp || c1 == 'R') {
1141*9094Srrh 			noblock('L','E');
1142*9094Srrh 		} else {
1143*9094Srrh 			SKIP;
1144*9094Srrh 			putchar('.');
1145*9094Srrh 		}
1146*9094Srrh 	}
1147*9094Srrh 	else if(c1=='.' && c2=='.'){
1148*9094Srrh 		if(msflag){
1149*9094Srrh 			SKIP;
1150*9094Srrh 			return;
1151*9094Srrh 		}
1152*9094Srrh 		while(C == '.')
1153*9094Srrh 			/*VOID*/;
1154*9094Srrh 	}
1155*9094Srrh 	++inmacro;
1156*9094Srrh 	/*
1157*9094Srrh 	 *	Process the arguments to the macro
1158*9094Srrh 	 */
1159*9094Srrh 	switch(mac){
1160*9094Srrh 	default:
1161*9094Srrh 	case MM:
1162*9094Srrh 	case MS:
1163*9094Srrh 		if(c1 <= 'Z' && msflag)
1164*9094Srrh 			regline(msputmac, ONE);
1165*9094Srrh 		else
1166*9094Srrh 			regline(msputmac, TWO);
1167*9094Srrh 		break;
1168*9094Srrh 	case ME:
1169*9094Srrh 		regline(meputmac, ONE);
1170*9094Srrh 		break;
1171*9094Srrh 	}
1172*9094Srrh 	--inmacro;
1173*9094Srrh }
1174*9094Srrh 
1175*9094Srrh comline()
1176*9094Srrh {
1177*9094Srrh 	reg	int	c1;
1178*9094Srrh 	reg	int	c2;
1179*9094Srrh 		pacmac	c12;
1180*9094Srrh 	reg	int	mid;
1181*9094Srrh 		int	lb, ub;
1182*9094Srrh 		int	hit;
1183*9094Srrh 	static	int	tabsize = 0;
1184*9094Srrh 	static	struct	mactab	*mactab = (struct mactab *)0;
1185*9094Srrh 	reg	struct	mactab	*mp;
1186*9094Srrh 
1187*9094Srrh 	if (mactab == 0){
1188*9094Srrh 		 buildtab(&mactab, &tabsize);
1189*9094Srrh 	}
1190*9094Srrh com:
1191*9094Srrh 	while(C==' ' || c=='\t')
1192*9094Srrh 		;
1193*9094Srrh comx:
1194*9094Srrh 	if( (c1=c) == '\n')
1195*9094Srrh 		return;
1196*9094Srrh 	c2 = C;
1197*9094Srrh 	if(c1=='.' && c2 !='.')
1198*9094Srrh 		inmacro = NO;
1199*9094Srrh 	if(msflag && c1 == '['){
1200*9094Srrh 		refer(c2);
1201*9094Srrh 		return;
1202*9094Srrh 	}
1203*9094Srrh 	if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
1204*9094Srrh 		printf(".P\n");
1205*9094Srrh 		return;
1206*9094Srrh 	}
1207*9094Srrh 	if(c2 == '\n')
1208*9094Srrh 		return;
1209*9094Srrh 	/*
1210*9094Srrh 	 *	Single letter macro
1211*9094Srrh 	 */
1212*9094Srrh 	if (mac == ME && (c2 == ' ' || c2 == '\t') )
1213*9094Srrh 		c2 = ' ';
1214*9094Srrh 	c12 = tomac(c1, c2);
1215*9094Srrh 	/*
1216*9094Srrh 	 *	binary search through the table of macros
1217*9094Srrh 	 */
1218*9094Srrh 	lb = 0;
1219*9094Srrh 	ub = tabsize - 1;
1220*9094Srrh 	while(lb <= ub){
1221*9094Srrh 		mid = (ub + lb) / 2;
1222*9094Srrh 		mp = &mactab[mid];
1223*9094Srrh 		if (mp->macname < c12)
1224*9094Srrh 			lb = mid + 1;
1225*9094Srrh 		else if (mp->macname > c12)
1226*9094Srrh 			ub = mid - 1;
1227*9094Srrh 		else {
1228*9094Srrh 			hit = 1;
1229*9094Srrh #ifdef FULLDEBUG
1230*9094Srrh 			printf("preliminary hit macro %c%c ", c1, c2);
1231*9094Srrh #endif FULLDEBUG
1232*9094Srrh 			switch(mp->condition){
1233*9094Srrh 			case NONE:	hit = YES;			break;
1234*9094Srrh 			case FNEST:	hit = (filesp == files);	break;
1235*9094Srrh 			case NOMAC:	hit = !inmacro;			break;
1236*9094Srrh 			case MAC:	hit = inmacro;			break;
1237*9094Srrh 			case PARAG:	hit = parag;			break;
1238*9094Srrh 			case NBLK:	hit = !keepblock;		break;
1239*9094Srrh 			default:	hit = 0;
1240*9094Srrh 			}
1241*9094Srrh 			if (hit) {
1242*9094Srrh #ifdef FULLDEBUG
1243*9094Srrh 				printf("MATCH\n");
1244*9094Srrh #endif FULLDEBUG
1245*9094Srrh 				switch( (*(mp->func))(c12) ) {
1246*9094Srrh 				default: 	return;
1247*9094Srrh 				case COMX:	goto comx;
1248*9094Srrh 				case COM:	goto com;
1249*9094Srrh 				}
1250*9094Srrh 			}
1251*9094Srrh #ifdef FULLDEBUG
1252*9094Srrh 			printf("FAIL\n");
1253*9094Srrh #endif FULLDEBUG
1254*9094Srrh 			break;
1255*9094Srrh 		}
1256*9094Srrh 	}
1257*9094Srrh 	defcomline(c12);
1258*9094Srrh }
1259*9094Srrh 
1260*9094Srrh int macsort(p1, p2)
1261*9094Srrh 	struct	mactab	*p1, *p2;
1262*9094Srrh {
1263*9094Srrh 	return(p1->macname - p2->macname);
1264*9094Srrh }
1265*9094Srrh 
1266*9094Srrh int sizetab(mp)
1267*9094Srrh 	reg	struct	mactab	*mp;
1268*9094Srrh {
1269*9094Srrh 	reg	int	i;
1270*9094Srrh 	i = 0;
1271*9094Srrh 	if (mp){
1272*9094Srrh 		for (; mp->macname; mp++, i++)
1273*9094Srrh 			/*VOID*/ ;
1274*9094Srrh 	}
1275*9094Srrh 	return(i);
1276*9094Srrh }
1277*9094Srrh 
1278*9094Srrh struct mactab *macfill(dst, src)
1279*9094Srrh 	reg	struct	mactab	*dst;
1280*9094Srrh 	reg	struct	mactab	*src;
1281*9094Srrh {
1282*9094Srrh 	if (src) {
1283*9094Srrh 		while(src->macname){
1284*9094Srrh 			*dst++ = *src++;
1285*9094Srrh 		}
1286*9094Srrh 	}
1287*9094Srrh 	return(dst);
1288*9094Srrh }
1289*9094Srrh 
1290*9094Srrh buildtab(r_back, r_size)
1291*9094Srrh 	struct	mactab	**r_back;
1292*9094Srrh 	int	*r_size;
1293*9094Srrh {
1294*9094Srrh 	int	size;
1295*9094Srrh 
1296*9094Srrh 	struct	mactab	*p, *p1, *p2;
1297*9094Srrh 	struct	mactab	*back;
1298*9094Srrh 
1299*9094Srrh 	size = sizetab(troffmactab);
1300*9094Srrh 	size += sizetab(ppmactab);
1301*9094Srrh 	p1 = p2 = (struct mactab *)0;
1302*9094Srrh 	if (msflag){
1303*9094Srrh 		switch(mac){
1304*9094Srrh 		case ME:	p1 = memactab; break;
1305*9094Srrh 		case MM:	p1 = msmactab;
1306*9094Srrh 				p2 = mmmactab; break;
1307*9094Srrh 
1308*9094Srrh 		case MS:	p1 = msmactab; break;
1309*9094Srrh 		case MA:	p1 = manmactab; break;
1310*9094Srrh 		default:	break;
1311*9094Srrh 		}
1312*9094Srrh 	}
1313*9094Srrh 	size += sizetab(p1);
1314*9094Srrh 	size += sizetab(p2);
1315*9094Srrh 	back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
1316*9094Srrh 
1317*9094Srrh 	p = macfill(back, troffmactab);
1318*9094Srrh 	p = macfill(p, ppmactab);
1319*9094Srrh 	p = macfill(p, p1);
1320*9094Srrh 	p = macfill(p, p2);
1321*9094Srrh 
1322*9094Srrh 	qsort(back, size, sizeof(struct mactab), macsort);
1323*9094Srrh 	*r_size = size;
1324*9094Srrh 	*r_back = back;
1325*9094Srrh }
1326*9094Srrh 
1327*9094Srrh /*
1328*9094Srrh  *	troff commands
1329*9094Srrh  */
1330*9094Srrh struct	mactab	troffmactab[] = {
1331*9094Srrh 	M(NONE,		'\\','"',	skip),	/* comment */
1332*9094Srrh 	M(NOMAC,	'd','e',	domacro),	/* define */
1333*9094Srrh 	M(NOMAC,	'i','g',	domacro),	/* ignore till .. */
1334*9094Srrh 	M(NOMAC,	'a','m',	domacro),	/* append macro */
1335*9094Srrh 	M(NBLK,		'n','f',	nf),	/* filled */
1336*9094Srrh 	M(NBLK,		'c','e',	ce),	/* centered */
1337*9094Srrh 
1338*9094Srrh 	M(NONE,		's','o',	so),	/* source a file */
1339*9094Srrh 	M(NONE,		'n','x',	nx),	/* go to next file */
1340*9094Srrh 
1341*9094Srrh 	M(NONE,		't','m',	skip),	/* print string on tty */
1342*9094Srrh 	M(NONE,		'h','w',	skip),	/* exception hyphen words */
1343*9094Srrh 	M(NONE,		0,0,		0)
1344*9094Srrh };
1345*9094Srrh /*
1346*9094Srrh  *	Preprocessor output
1347*9094Srrh  */
1348*9094Srrh struct	mactab	ppmactab[] = {
1349*9094Srrh 	M(FNEST,	'E','Q',	EQ),	/* equation starting */
1350*9094Srrh 	M(FNEST,	'T','S',	intbl),	/* table starting */
1351*9094Srrh 	M(FNEST,	'T','C',	intbl),	/* alternative table? */
1352*9094Srrh 	M(FNEST,	'T','&',	intbl),	/* table reformatting */
1353*9094Srrh 	M(NONE,		'T','E',	outtbl),/* table ending */
1354*9094Srrh 	M(NONE,		'P','S',	PS),	/* picture starting */
1355*9094Srrh 	M(NONE,		0,0,		0)
1356*9094Srrh };
1357*9094Srrh /*
1358*9094Srrh  *	Particular to ms and mm
1359*9094Srrh  */
1360*9094Srrh struct	mactab	msmactab[] = {
1361*9094Srrh 	M(NONE,		'T','L',	skiptocom),	/* title follows */
1362*9094Srrh 	M(NONE,		'F','S',	skiptocom),	/* start footnote */
1363*9094Srrh 	M(NONE,		'O','K',	skiptocom),	/* Other kws */
1364*9094Srrh 
1365*9094Srrh 	M(NONE,		'N','R',	skip),	/* undocumented */
1366*9094Srrh 	M(NONE,		'N','D',	skip),	/* use supplied date */
1367*9094Srrh 
1368*9094Srrh 	M(PARAG,	'P','P',	PP),	/* begin parag */
1369*9094Srrh 	M(PARAG,	'I','P',	PP),	/* begin indent parag, tag x */
1370*9094Srrh 	M(PARAG,	'L','P',	PP),	/* left blocked parag */
1371*9094Srrh 
1372*9094Srrh 	M(NONE,		'A','U',	AU),	/* author */
1373*9094Srrh 	M(NONE,		'A','I',	AU),	/* authors institution */
1374*9094Srrh 
1375*9094Srrh 	M(NONE,		'S','H',	SH),	/* section heading */
1376*9094Srrh 	M(NONE,		'S','N',	SH),	/* undocumented */
1377*9094Srrh 	M(NONE,		'U','X',	UX),	/* unix */
1378*9094Srrh 
1379*9094Srrh 	M(NBLK,		'D','S',	mssnblock),	/* start display text */
1380*9094Srrh 	M(NBLK,		'K','S',	mssnblock),	/* start keep */
1381*9094Srrh 	M(NBLK,		'K','F',	mssnblock),	/* start float keep */
1382*9094Srrh 	M(NONE,		0,0,		0)
1383*9094Srrh };
1384*9094Srrh 
1385*9094Srrh struct	mactab	mmmactab[] = {
1386*9094Srrh 	M(NONE,		'H',' ',	MMHU),	/* -mm ? */
1387*9094Srrh 	M(NONE,		'H','U',	MMHU),	/* -mm ? */
1388*9094Srrh 	M(PARAG,	'P',' ',	PP),	/* paragraph for -mm */
1389*9094Srrh 	M(NBLK,		'N','S',	mssnblock),	/* undocumented */
1390*9094Srrh 	M(NONE,		0,0,		0)
1391*9094Srrh };
1392*9094Srrh 
1393*9094Srrh struct	mactab	memactab[] = {
1394*9094Srrh 	M(PARAG,	'p','p',	mepp),
1395*9094Srrh 	M(PARAG,	'l','p',	mepp),
1396*9094Srrh 	M(PARAG,	'n','p',	mepp),
1397*9094Srrh 	M(NONE,		'i','p',	meip),
1398*9094Srrh 
1399*9094Srrh 	M(NONE,		's','h',	mesh),
1400*9094Srrh 	M(NONE,		'u','h',	mesh),
1401*9094Srrh 
1402*9094Srrh 	M(NBLK,		'(','l',	mesnblock),
1403*9094Srrh 	M(NBLK,		'(','q',	mesnblock),
1404*9094Srrh 	M(NBLK,		'(','b',	mesnblock),
1405*9094Srrh 	M(NBLK,		'(','z',	mesnblock),
1406*9094Srrh 	M(NBLK,		'(','c',	mesnblock),
1407*9094Srrh 
1408*9094Srrh 	M(NBLK,		'(','d',	mesnblock),
1409*9094Srrh 	M(NBLK,		'(','f',	mesnblock),
1410*9094Srrh 	M(NBLK,		'(','x',	mesnblock),
1411*9094Srrh 
1412*9094Srrh 	M(NONE,		'r',' ',	mefont),
1413*9094Srrh 	M(NONE,		'i',' ',	mefont),
1414*9094Srrh 	M(NONE,		'b',' ',	mefont),
1415*9094Srrh 	M(NONE,		'u',' ',	mefont),
1416*9094Srrh 	M(NONE,		'q',' ',	mefont),
1417*9094Srrh 	M(NONE,		'r','b',	mefont),
1418*9094Srrh 	M(NONE,		'b','i',	mefont),
1419*9094Srrh 	M(NONE,		'b','x',	mefont),
1420*9094Srrh 	M(NONE,		0,0,		0)
1421*9094Srrh };
1422*9094Srrh 
1423*9094Srrh 
1424*9094Srrh struct	mactab	manmactab[] = {
1425*9094Srrh 	M(PARAG,	'B','I',	manfont),
1426*9094Srrh 	M(PARAG,	'B','R',	manfont),
1427*9094Srrh 	M(PARAG,	'I','B',	manfont),
1428*9094Srrh 	M(PARAG,	'I','R',	manfont),
1429*9094Srrh 	M(PARAG,	'R','B',	manfont),
1430*9094Srrh 	M(PARAG,	'R','I',	manfont),
1431*9094Srrh 
1432*9094Srrh 	M(PARAG,	'P','P',	manpp),
1433*9094Srrh 	M(PARAG,	'L','P',	manpp),
1434*9094Srrh 	M(PARAG,	'H','P',	manpp),
1435*9094Srrh 	M(NONE,		0,0,		0)
1436*9094Srrh };
1437