xref: /csrg-svn/usr.bin/deroff/deroff.c (revision 48239)
1*48239Sbostic /*-
2*48239Sbostic  * Copyright (c) 1988 The Regents of the University of California.
3*48239Sbostic  * All rights reserved.
4*48239Sbostic  *
5*48239Sbostic  * %sccs.include.proprietary.c%
6*48239Sbostic  */
7*48239Sbostic 
89075Srrh #ifndef lint
9*48239Sbostic char copyright[] =
10*48239Sbostic "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
11*48239Sbostic  All rights reserved.\n";
12*48239Sbostic #endif /* not lint */
139075Srrh 
14*48239Sbostic #ifndef lint
15*48239Sbostic static char sccsid[] = "@(#)deroff.c	4.8 (Berkeley) 04/17/91";
16*48239Sbostic #endif /* not lint */
17*48239Sbostic 
189094Srrh #include <stdio.h>
199075Srrh 
209094Srrh /*
219094Srrh  *	Deroff command -- strip troff, eqn, and Tbl sequences from
229094Srrh  *	a file.  Has two flags argument, -w, to cause output one word per line
239094Srrh  *	rather than in the original format.
249094Srrh  *	-mm (or -ms) causes the corresponding macro's to be interpreted
259094Srrh  *	so that just sentences are output
269094Srrh  *	-ml  also gets rid of lists.
279094Srrh  *	Deroff follows .so and .nx commands, removes contents of macro
289094Srrh  *	definitions, equations (both .EQ ... .EN and $...$),
299094Srrh  *	Tbl command sequences, and Troff backslash constructions.
309094Srrh  *
319094Srrh  *	All input is through the Cget macro;
329094Srrh  *	the most recently read character is in c.
339094Srrh  *
349094Srrh  *	Modified by Robert Henry to process -me and -man macros.
359094Srrh  */
369075Srrh 
379094Srrh #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
389094Srrh #define C1get ( (c=getc(infile)) == EOF ? eof() :  c)
399075Srrh 
409094Srrh #ifdef DEBUG
419094Srrh #  define C	_C()
429094Srrh #  define C1	_C1()
439094Srrh #else not DEBUG
449094Srrh #  define C	Cget
459094Srrh #  define C1	C1get
469094Srrh #endif not DEBUG
479075Srrh 
489075Srrh #define SKIP while(C != '\n')
499075Srrh #define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
509075Srrh 
519094Srrh #define	YES 1
529094Srrh #define	NO 0
539094Srrh #define	MS 0	/* -ms */
549094Srrh #define	MM 1	/* -mm */
559094Srrh #define	ME 2	/* -me */
569094Srrh #define	MA 3	/* -man */
579075Srrh 
589094Srrh #ifdef DEBUG
599094Srrh char *mactab[] = {"-ms", "-mm", "-me", "-ma"};
609094Srrh #endif DEBUG
619094Srrh 
629094Srrh #define	ONE 1
639094Srrh #define	TWO 2
649094Srrh 
659075Srrh #define NOCHAR -2
669075Srrh #define SPECIAL 0
679075Srrh #define APOS 1
689079Srrh #define PUNCT 2
699079Srrh #define DIGIT 3
709079Srrh #define LETTER 4
719075Srrh 
729094Srrh int	wordflag;
739094Srrh int	msflag;		/* processing a source written using a mac package */
749094Srrh int	mac;		/* which package */
759094Srrh int	disp;
769094Srrh int	parag;
779094Srrh int	inmacro;
789094Srrh int	intable;
799094Srrh int	keepblock;	/* keep blocks of text; normally false when msflag */
809075Srrh 
819079Srrh char chars[128];  /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
829075Srrh 
839075Srrh char line[512];
849075Srrh char *lp;
859075Srrh 
869075Srrh int c;
879075Srrh int pc;
889094Srrh int ldelim;
899094Srrh int rdelim;
909075Srrh 
919075Srrh 
929075Srrh int argc;
939075Srrh char **argv;
949075Srrh 
959075Srrh char fname[50];
969075Srrh FILE *files[15];
979075Srrh FILE **filesp;
989075Srrh FILE *infile;
999094Srrh FILE	*opn();
1009094Srrh /*
1019094Srrh  *	Flags for matching conditions other than
1029094Srrh  *	the macro name
1039094Srrh  */
1049094Srrh #define	NONE		0
1059094Srrh #define	FNEST		1		/* no nested files */
1069094Srrh #define	NOMAC		2		/* no macro */
1079094Srrh #define	MAC		3		/* macro */
1089094Srrh #define	PARAG		4		/* in a paragraph */
1099094Srrh #define	MSF		5		/* msflag is on */
1109094Srrh #define	NBLK		6		/* set if no blocks to be kept */
1119075Srrh 
1129094Srrh /*
1139094Srrh  *	Return codes from macro minions, determine where to jump,
1149094Srrh  *	how to repeat/reprocess text
1159094Srrh  */
1169094Srrh #define	COMX		1		/* goto comx */
1179094Srrh #define	COM		2		/* goto com */
1189094Srrh 
1199075Srrh main(ac, av)
1209075Srrh int ac;
1219075Srrh char **av;
1229075Srrh {
1239079Srrh 	register int i;
1249094Srrh 	int	errflg = 0;
1259094Srrh 	register	optchar;
1269079Srrh 	FILE *opn();
1279094Srrh 	int	kflag = NO;
1289094Srrh 	char	*p;
1299075Srrh 
1309094Srrh 	wordflag = NO;
1319094Srrh 	msflag = NO;
1329094Srrh 	mac = ME;
1339094Srrh 	disp = NO;
1349094Srrh 	parag = NO;
1359094Srrh 	inmacro = NO;
1369094Srrh 	intable = NO;
1379094Srrh 	ldelim	= NOCHAR;
1389094Srrh 	rdelim	= NOCHAR;
1399094Srrh 	keepblock = YES;
1409094Srrh 
1419094Srrh 	for(argc = ac - 1, argv = av + 1;
1429094Srrh 	    (   (argc > 0)
1439094Srrh 	     && (argv[0][0] == '-')
1449094Srrh 	     && (argv[0][1] != '\0') );
1459094Srrh 	    --argc, ++argv
1469094Srrh 	){
1479094Srrh 		for(p = argv[0]+1; *p; ++p) {
1489094Srrh 			switch(*p) {
1499094Srrh 			case 'p':
1509094Srrh 				parag=YES;
1519094Srrh 				break;
1529094Srrh 			case 'k':
1539094Srrh 				kflag = YES;
1549094Srrh 				break;
1559094Srrh 			case 'w':
1569094Srrh 				wordflag = YES;
1579094Srrh 				kflag = YES;
1589094Srrh 				break;
1599094Srrh 			case 'm':
1609094Srrh 				msflag = YES;
1619094Srrh 				keepblock = NO;
1629094Srrh 				switch(p[1]){
1639094Srrh 				case 'm':	mac = MM; p++; break;
1649094Srrh 				case 's':	mac = MS; p++; break;
1659094Srrh 				case 'e':	mac = ME; p++; break;
1669094Srrh 				case 'a':	mac = MA; p++; break;
1679094Srrh 				case 'l':	disp = YES; p++; break;
1689094Srrh 				default:	errflg++; break;
1699094Srrh 				}
1709094Srrh 				break;
1719094Srrh 			default:
1729094Srrh 				errflg++;
1739094Srrh 			}
1749094Srrh 		}
1759075Srrh 	}
1769094Srrh 
1779094Srrh 	if (kflag)
1789094Srrh 		keepblock = YES;
1799079Srrh 	if (errflg)
1809094Srrh 		fatal("usage: deroff [ -w ] [ -k] [ -m (a e m s l) ] [ file ] ... \n",
1819094Srrh 			(char *) NULL);
1829094Srrh 
1839094Srrh #ifdef DEBUG
1849094Srrh 	printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
1859094Srrh 		msflag, mactab[mac], keepblock, disp);
1869094Srrh #endif DEBUG
1879094Srrh 	if (argc == 0){
1889079Srrh 		infile = stdin;
1899094Srrh 	} else {
1909094Srrh 		infile = opn(argv[0]);
1919094Srrh 		--argc;
1929094Srrh 		++argv;
1939094Srrh 	}
1949094Srrh 
1959094Srrh 
1969079Srrh 	files[0] = infile;
1979079Srrh 	filesp = &files[0];
1989075Srrh 
1999079Srrh 	for(i='a'; i<='z' ; ++i)
2009079Srrh 		chars[i] = LETTER;
2019079Srrh 	for(i='A'; i<='Z'; ++i)
2029079Srrh 		chars[i] = LETTER;
2039079Srrh 	for(i='0'; i<='9'; ++i)
2049079Srrh 		chars[i] = DIGIT;
2059079Srrh 	chars['\''] = APOS;
2069079Srrh 	chars['&'] = APOS;
2079079Srrh 	chars['.'] = PUNCT;
2089079Srrh 	chars[','] = PUNCT;
2099079Srrh 	chars[';'] = PUNCT;
2109079Srrh 	chars['?'] = PUNCT;
2119079Srrh 	chars[':'] = PUNCT;
2129079Srrh 	work();
2139079Srrh }
2149079Srrh char *calloc();
2159075Srrh 
2169075Srrh skeqn()
2179075Srrh {
2189079Srrh 	while((c = getc(infile)) != rdelim)
2199079Srrh 		if(c == EOF)
2209079Srrh 			c = eof();
2219079Srrh 		else if(c == '"')
2229079Srrh 			while( (c = getc(infile)) != '"')
2239079Srrh 				if(c == EOF)
2249075Srrh 					c = eof();
2259079Srrh 				else if(c == '\\')
2269079Srrh 					if((c = getc(infile)) == EOF)
2279079Srrh 						c = eof();
2289079Srrh 	if(msflag)return(c='x');
2299079Srrh 	return(c = ' ');
2309075Srrh }
2319075Srrh 
2329075Srrh FILE *opn(p)
2339075Srrh register char *p;
2349075Srrh {
2359079Srrh 	FILE *fd;
2369075Srrh 
23712097Smckusick 	if( (fd = fopen(p, "r")) == NULL) {
23812097Smckusick 		fprintf(stderr, "Deroff: ");
23912097Smckusick 		perror(p);
24012097Smckusick 		exit(1);
24112097Smckusick 	}
2429075Srrh 
2439079Srrh 	return(fd);
2449075Srrh }
2459075Srrh 
2469075Srrh eof()
2479075Srrh {
2489079Srrh 	if(infile != stdin)
2499079Srrh 		fclose(infile);
2509079Srrh 	if(filesp > files)
2519079Srrh 		infile = *--filesp;
2529094Srrh 	else if (argc > 0) {
2539094Srrh 		infile = opn(argv[0]);
2549094Srrh 		--argc;
2559094Srrh 		++argv;
2569094Srrh 	} else
2579079Srrh 		exit(0);
2589079Srrh 	return(C);
2599075Srrh }
2609075Srrh 
2619075Srrh getfname()
2629075Srrh {
2639079Srrh 	register char *p;
2649079Srrh 	struct chain {
2659079Srrh 		struct chain *nextp;
2669079Srrh 		char *datap;
2679079Srrh 	} *chainblock;
2689079Srrh 	register struct chain *q;
2699079Srrh 	static struct chain *namechain	= NULL;
2709079Srrh 	char *copys();
2719075Srrh 
2729079Srrh 	while(C == ' ') ;
2739075Srrh 
2749079Srrh 	for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
2759079Srrh 		C;
2769079Srrh 	*p = '\0';
2779079Srrh 	while(c != '\n')
2789079Srrh 		C;
2799075Srrh 
2809079Srrh 	/* see if this name has already been used */
2819075Srrh 
2829079Srrh 	for(q = namechain ; q; q = q->nextp)
2839079Srrh 		if( ! strcmp(fname, q->datap))
2849075Srrh 		{
2859079Srrh 			fname[0] = '\0';
2869079Srrh 			return;
2879075Srrh 		}
2889075Srrh 
2899079Srrh 	q = (struct chain *) calloc(1, sizeof(*chainblock));
2909079Srrh 	q->nextp = namechain;
2919079Srrh 	q->datap = copys(fname);
2929079Srrh 	namechain = q;
2939075Srrh }
2949075Srrh 
2959075Srrh fatal(s,p)
2969075Srrh char *s, *p;
2979075Srrh {
2989079Srrh 	fprintf(stderr, "Deroff: ");
2999079Srrh 	fprintf(stderr, s, p);
3009079Srrh 	exit(1);
3019075Srrh }
3029079Srrh 
3039094Srrh /*ARGSUSED*/
30434101Sbostic textline(str, constant)
3059094Srrh 	char	*str;
30634101Sbostic 	int	constant;
3079094Srrh {
3089094Srrh 	if (wordflag) {
3099094Srrh 		msputwords(0);
3109094Srrh 		return;
3119094Srrh 	}
3129094Srrh 	puts(str);
3139094Srrh }
3149094Srrh 
3159075Srrh work()
3169075Srrh {
3179079Srrh 	for( ;; )
3189075Srrh 	{
3199094Srrh 		C;
3209094Srrh #ifdef FULLDEBUG
3219094Srrh 		printf("Starting work with `%c'\n", c);
3229094Srrh #endif FULLDEBUG
3239094Srrh 		if(c == '.'  ||  c == '\'')
3249079Srrh 			comline();
3259079Srrh 		else
3269094Srrh 			regline(textline, TWO);
3279075Srrh 	}
3289075Srrh }
3299075Srrh 
33034101Sbostic regline(pfunc, constant)
3319094Srrh 	int	(*pfunc)();
33234101Sbostic 	int	constant;
3339075Srrh {
3349079Srrh 	line[0] = c;
3359079Srrh 	lp = line;
3369079Srrh 	for( ; ; )
3379075Srrh 	{
3389094Srrh 		if(c == '\\') {
3399079Srrh 			*lp = ' ';
3409079Srrh 			backsl();
3419075Srrh 		}
3429094Srrh 		if(c == '\n')
3439094Srrh 			break;
3449094Srrh 		if(intable && c=='T') {
3459079Srrh 			*++lp = C;
3469094Srrh 			if(c=='{' || c=='}') {
3479079Srrh 				lp[-1] = ' ';
3489079Srrh 				*lp = C;
3499075Srrh 			}
3509094Srrh 		} else {
3519094Srrh 			*++lp = C;
3529075Srrh 		}
3539075Srrh 	}
3549075Srrh 
3559079Srrh 	*lp = '\0';
3569075Srrh 
3579079Srrh 	if(line[0] != '\0')
35834101Sbostic 		(*pfunc)(line, constant);
3599075Srrh }
3609075Srrh 
3619075Srrh macro()
3629075Srrh {
3639079Srrh 	if(msflag){
3649079Srrh 		do {
3659079Srrh 			SKIP;
3669079Srrh 		}		while(C!='.' || C!='.' || C=='.');	/* look for  .. */
3679079Srrh 		if(c != '\n')SKIP;
3689079Srrh 		return;
3699079Srrh 	}
3709079Srrh 	SKIP;
3719079Srrh 	inmacro = YES;
3729075Srrh }
3739075Srrh 
3749075Srrh tbl()
3759075Srrh {
3769079Srrh 	while(C != '.');
3779079Srrh 	SKIP;
3789079Srrh 	intable = YES;
3799075Srrh }
3809075Srrh stbl()
3819075Srrh {
3829079Srrh 	while(C != '.');
3839079Srrh 	SKIP_TO_COM;
3849079Srrh 	if(c != 'T' || C != 'E'){
3859079Srrh 		SKIP;
3869079Srrh 		pc=c;
3879079Srrh 		while(C != '.' || pc != '\n' || C != 'T' || C != 'E')pc=c;
3889079Srrh 	}
3899075Srrh }
3909075Srrh 
3919075Srrh eqn()
3929075Srrh {
3939079Srrh 	register int c1, c2;
3949079Srrh 	register int dflg;
3959079Srrh 	char last;
3969075Srrh 
3979079Srrh 	last=0;
3989079Srrh 	dflg = 1;
3999079Srrh 	SKIP;
4009075Srrh 
4019079Srrh 	for( ;;)
4029075Srrh 	{
4039079Srrh 		if(C1 == '.'  || c == '\'')
4049075Srrh 		{
4059079Srrh 			while(C1==' ' || c=='\t')
4069079Srrh 				;
4079079Srrh 			if(c=='E' && C1=='N')
4089075Srrh 			{
4099079Srrh 				SKIP;
4109079Srrh 				if(msflag && dflg){
4119079Srrh 					putchar('x');
4129079Srrh 					putchar(' ');
4139079Srrh 					if(last){
4149079Srrh 						putchar(last);
4159079Srrh 						putchar('\n');
4169079Srrh 					}
4179079Srrh 				}
4189079Srrh 				return;
4199075Srrh 			}
4209075Srrh 		}
4219079Srrh 		else if(c == 'd')	/* look for delim */
4229075Srrh 		{
4239079Srrh 			if(C1=='e' && C1=='l')
4249079Srrh 				if( C1=='i' && C1=='m')
4259075Srrh 				{
4269079Srrh 					while(C1 == ' ');
4279079Srrh 					if((c1=c)=='\n' || (c2=C1)=='\n'
4289079Srrh 					    || (c1=='o' && c2=='f' && C1=='f') )
4299079Srrh 					{
4309079Srrh 						ldelim = NOCHAR;
4319079Srrh 						rdelim = NOCHAR;
4329079Srrh 					}
4339079Srrh 					else	{
4349079Srrh 						ldelim = c1;
4359079Srrh 						rdelim = c2;
4369079Srrh 					}
4379075Srrh 				}
4389075Srrh 			dflg = 0;
4399075Srrh 		}
4409075Srrh 
4419079Srrh 		if(c != '\n') while(C1 != '\n'){
4429079Srrh 			if(chars[c] == PUNCT)last = c;
4439079Srrh 			else if(c != ' ')last = 0;
4449079Srrh 		}
4459075Srrh 	}
4469075Srrh }
4479075Srrh 
4489075Srrh backsl()	/* skip over a complete backslash construction */
4499075Srrh {
4509079Srrh 	int bdelim;
4519075Srrh 
4529079Srrh sw:
4539079Srrh 	switch(C)
4549075Srrh 	{
4559075Srrh 	case '"':
4569075Srrh 		SKIP;
4579075Srrh 		return;
4589075Srrh 	case 's':
4599075Srrh 		if(C == '\\') backsl();
4609075Srrh 		else	{
4619075Srrh 			while(C>='0' && c<='9') ;
4629075Srrh 			ungetc(c,infile);
4639075Srrh 			c = '0';
4649079Srrh 		}
4659075Srrh 		--lp;
4669075Srrh 		return;
4679075Srrh 
4689075Srrh 	case 'f':
4699075Srrh 	case 'n':
4709075Srrh 	case '*':
4719075Srrh 		if(C != '(')
4729075Srrh 			return;
4739075Srrh 
4749075Srrh 	case '(':
4759079Srrh 		if(msflag){
4769079Srrh 			if(C == 'e'){
4779079Srrh 				if(C == 'm'){
4789079Srrh 					*lp = '-';
4799079Srrh 					return;
4809079Srrh 				}
4819079Srrh 			}
4829079Srrh 			else if(c != '\n')C;
4839079Srrh 			return;
4849079Srrh 		}
4859075Srrh 		if(C != '\n') C;
4869075Srrh 		return;
4879075Srrh 
4889075Srrh 	case '$':
4899075Srrh 		C;	/* discard argument number */
4909075Srrh 		return;
4919075Srrh 
4929075Srrh 	case 'b':
4939075Srrh 	case 'x':
4949075Srrh 	case 'v':
4959075Srrh 	case 'h':
4969075Srrh 	case 'w':
4979075Srrh 	case 'o':
4989075Srrh 	case 'l':
4999075Srrh 	case 'L':
5009075Srrh 		if( (bdelim=C) == '\n')
5019075Srrh 			return;
5029075Srrh 		while(C!='\n' && c!=bdelim)
5039075Srrh 			if(c == '\\') backsl();
5049075Srrh 		return;
5059075Srrh 
5069075Srrh 	case '\\':
5079075Srrh 		if(inmacro)
5089075Srrh 			goto sw;
5099075Srrh 	default:
5109075Srrh 		return;
5119075Srrh 	}
5129075Srrh }
5139075Srrh 
5149075Srrh char *copys(s)
5159075Srrh register char *s;
5169075Srrh {
5179079Srrh 	register char *t, *t0;
5189075Srrh 
5199079Srrh 	if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL)
5209079Srrh 		fatal("Cannot allocate memory", (char *) NULL);
5219075Srrh 
5229079Srrh 	while( *t++ = *s++ )
5239079Srrh 		;
5249079Srrh 	return(t0);
5259075Srrh }
5269094Srrh 
5279094Srrh sce()
5289094Srrh {
5299079Srrh 	register char *ap;
5309079Srrh 	register int n, i;
5319079Srrh 	char a[10];
5329075Srrh 	for(ap=a;C != '\n';ap++){
5339075Srrh 		*ap = c;
5349075Srrh 		if(ap == &a[9]){
5359075Srrh 			SKIP;
5369075Srrh 			ap=a;
5379075Srrh 			break;
5389075Srrh 		}
5399075Srrh 	}
5409075Srrh 	if(ap != a)n = atoi(a);
5419075Srrh 	else n = 1;
5429075Srrh 	for(i=0;i<n;){
5439075Srrh 		if(C == '.'){
5449075Srrh 			if(C == 'c'){
5459075Srrh 				if(C == 'e'){
5469075Srrh 					while(C == ' ');
5479079Srrh 					if(c == '0'){
5489079Srrh 						SKIP;
5499079Srrh 						break;
5509079Srrh 					}
5519075Srrh 					else SKIP;
5529075Srrh 				}
5539075Srrh 				else SKIP;
5549075Srrh 			}
5559079Srrh 			else if(c == 'P' || C == 'P'){
5569079Srrh 				if(c != '\n')SKIP;
5579079Srrh 				break;
5589079Srrh 			}
5599079Srrh 			else if(c != '\n')SKIP;
5609075Srrh 		}
5619075Srrh 		else {
5629075Srrh 			SKIP;
5639075Srrh 			i++;
5649075Srrh 		}
5659075Srrh 	}
5669075Srrh }
5679094Srrh 
5689079Srrh refer(c1)
5699079Srrh {
5709079Srrh 	register int c2;
5719079Srrh 	if(c1 != '\n')
5729079Srrh 		SKIP;
5739079Srrh 	while(1){
5749079Srrh 		if(C != '.')
5759079Srrh 			SKIP;
5769079Srrh 		else {
5779079Srrh 			if(C != ']')
5789079Srrh 				SKIP;
5799079Srrh 			else {
5809079Srrh 				while(C != '\n')
5819079Srrh 					c2=c;
5829079Srrh 				if(chars[c2] == PUNCT)putchar(c2);
5839079Srrh 				return;
5849079Srrh 			}
5859079Srrh 		}
5869079Srrh 	}
5879079Srrh }
5889094Srrh 
5899094Srrh inpic()
5909094Srrh {
5919079Srrh 	register int c1;
5929079Srrh 	register char *p1;
5939079Srrh 	SKIP;
5949079Srrh 	p1 = line;
5959079Srrh 	c = '\n';
5969079Srrh 	while(1){
5979079Srrh 		c1 = c;
5989079Srrh 		if(C == '.' && c1 == '\n'){
5999079Srrh 			if(C != 'P'){
6009079Srrh 				if(c == '\n')continue;
6019079Srrh 				else { SKIP; c='\n'; continue;}
6029079Srrh 			}
6039079Srrh 			if(C != 'E'){
6049079Srrh 				if(c == '\n')continue;
6059079Srrh 				else { SKIP; c='\n';continue; }
6069079Srrh 			}
6079079Srrh 			SKIP;
6089079Srrh 			return;
6099079Srrh 		}
6109079Srrh 		else if(c == '\"'){
6119079Srrh 			while(C != '\"'){
6129079Srrh 				if(c == '\\'){
6139079Srrh 					if(C == '\"')continue;
6149079Srrh 					ungetc(c,infile);
6159079Srrh 					backsl();
6169079Srrh 				}
6179079Srrh 				else *p1++ = c;
6189079Srrh 			}
6199079Srrh 			*p1++ = ' ';
6209079Srrh 		}
6219079Srrh 		else if(c == '\n' && p1 != line){
6229079Srrh 			*p1 = '\0';
6239094Srrh 			if(wordflag)msputwords(NO);
6249079Srrh 			else {
6259079Srrh 				puts(line);
6269079Srrh 				putchar('\n');
6279079Srrh 			}
6289079Srrh 			p1 = line;
6299079Srrh 		}
6309079Srrh 	}
6319079Srrh }
6329094Srrh 
6339094Srrh #ifdef DEBUG
6349094Srrh _C1()
6359094Srrh {
6369094Srrh 	return(C1get);
6379094Srrh }
6389094Srrh _C()
6399094Srrh {
6409094Srrh 	return(Cget);
6419094Srrh }
6429094Srrh #endif DEBUG
6439094Srrh 
6449094Srrh /*
6459094Srrh  *	Macro processing
6469094Srrh  *
6479094Srrh  *	Macro table definitions
6489094Srrh  */
6499094Srrh #define	reg	register
6509094Srrh typedef	int pacmac;		/* compressed macro name */
6519094Srrh int	argconcat = 0;		/* concat arguments together (-me only) */
6529094Srrh 
6539094Srrh #define	tomac(c1, c2)		((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
6549094Srrh #define	frommac(src, c1, c2)	(((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
6559094Srrh 
6569094Srrh struct	mactab{
6579094Srrh 	int	condition;
6589094Srrh 	pacmac	macname;
6599094Srrh 	int	(*func)();
6609094Srrh };
6619094Srrh struct	mactab	troffmactab[];
6629094Srrh struct	mactab	ppmactab[];
6639094Srrh struct	mactab	msmactab[];
6649094Srrh struct	mactab	mmmactab[];
6659094Srrh struct	mactab	memactab[];
6669094Srrh struct	mactab	manmactab[];
6679094Srrh /*
6689094Srrh  *	macro table initialization
6699094Srrh  */
6709094Srrh #define	M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
6719094Srrh 
6729094Srrh /*
6739094Srrh  *	Put out a macro line, using ms and mm conventions.
6749094Srrh  */
67534101Sbostic msputmac(s, constant)
6769094Srrh 	register char *s;
67734101Sbostic 	int	constant;
6789094Srrh {
6799094Srrh 	register char *t;
6809094Srrh 	register found;
6819094Srrh 	int last;
6829094Srrh 	found = 0;
6839094Srrh 
6849094Srrh 	if (wordflag) {
6859094Srrh 		msputwords(YES);
6869094Srrh 		return;
6879094Srrh 	}
6889094Srrh 	while(*s)
6899094Srrh 	{
6909094Srrh 		while(*s==' ' || *s=='\t')
6919094Srrh 			putchar(*s++);
6929094Srrh 		for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
6939094Srrh 			;
6949094Srrh 		if(*s == '\"')s++;
69534101Sbostic 		if(t>s+constant && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
6969094Srrh 			while(s < t)
6979094Srrh 				if(*s == '\"')s++;
6989094Srrh 				else
6999094Srrh 					putchar(*s++);
7009094Srrh 			last = *(t-1);
7019094Srrh 			found++;
7029094Srrh 		}
7039094Srrh 		else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0')
7049094Srrh 			putchar(*s++);
7059094Srrh 		else{
7069094Srrh 			last = *(t-1);
7079094Srrh 			s = t;
7089094Srrh 		}
7099094Srrh 	}
7109094Srrh 	putchar('\n');
7119094Srrh 	if(msflag && chars[last] == PUNCT){
7129094Srrh 		putchar(last);
7139094Srrh 		putchar('\n');
7149094Srrh 	}
7159094Srrh }
7169094Srrh /*
7179094Srrh  *	put out words (for the -w option) with ms and mm conventions
7189094Srrh  */
7199094Srrh msputwords(macline)
7209094Srrh 	int macline;	/* is this is a macro line */
7219094Srrh {
7229094Srrh 	register char *p, *p1;
7239094Srrh 	int i, nlet;
7249094Srrh 
7259094Srrh 	for(p1 = line ; ;) {
7269094Srrh 		/*
7279094Srrh 		 *	skip initial specials ampersands and apostrophes
7289094Srrh 		 */
7299094Srrh 		while( chars[*p1] < DIGIT)
7309094Srrh 			if(*p1++ == '\0') return;
7319094Srrh 		nlet = 0;
7329094Srrh 		for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
7339094Srrh 			if(i == LETTER) ++nlet;
7349094Srrh 
73517534Sralph 		if (nlet > 1 && chars[p1[0]] == LETTER) {
7369094Srrh 			/*
7379094Srrh 			 *	delete trailing ampersands and apostrophes
7389094Srrh 			 */
73917534Sralph 			while( (i=chars[p[-1]]) == PUNCT || i == APOS )
7409094Srrh 				--p;
7419094Srrh 			while(p1 < p)
7429094Srrh 				putchar(*p1++);
7439094Srrh 			putchar('\n');
7449094Srrh 		} else {
7459094Srrh 			p1 = p;
7469094Srrh 		}
7479094Srrh 	}
7489094Srrh }
7499094Srrh /*
7509094Srrh  *	put out a macro using the me conventions
7519094Srrh  */
7529094Srrh #define SKIPBLANK(cp)	while(*cp == ' ' || *cp == '\t') { cp++; }
7539094Srrh #define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
7549094Srrh 
75534101Sbostic meputmac(cp, constant)
7569094Srrh 	reg	char	*cp;
75734101Sbostic 		int	constant;
7589094Srrh {
7599094Srrh 	reg	char	*np;
7609094Srrh 		int	found;
7619094Srrh 		int	argno;
7629094Srrh 		int	last;
7639094Srrh 		int	inquote;
7649094Srrh 
7659094Srrh 	if (wordflag) {
7669094Srrh 		meputwords(YES);
7679094Srrh 		return;
7689094Srrh 	}
7699094Srrh 	for (argno = 0; *cp; argno++){
7709094Srrh 		SKIPBLANK(cp);
7719094Srrh 		inquote = (*cp == '"');
7729094Srrh 		if (inquote)
7739094Srrh 			cp++;
7749094Srrh 		for (np = cp; *np; np++){
7759094Srrh 			switch(*np){
7769094Srrh 			case '\n':
7779094Srrh 			case '\0':	break;
7789094Srrh 			case '\t':
7799094Srrh 			case ' ':	if (inquote) {
7809094Srrh 						continue;
7819094Srrh 					} else {
7829094Srrh 						goto endarg;
7839094Srrh 					}
7849094Srrh 			case '"':	if(inquote && np[1] == '"'){
7859094Srrh 						strcpy(np, np + 1);
7869094Srrh 						np++;
7879094Srrh 						continue;
7889094Srrh 					} else {
7899094Srrh 						*np = ' '; 	/* bye bye " */
7909094Srrh 						goto endarg;
7919094Srrh 					}
7929094Srrh 			default:	continue;
7939094Srrh 			}
7949094Srrh 		}
7959094Srrh 		endarg: ;
7969094Srrh 		/*
7979094Srrh 		 *	cp points at the first char in the arg
7989094Srrh 		 *	np points one beyond the last char in the arg
7999094Srrh 		 */
8009094Srrh 		if ((argconcat == 0) || (argconcat != argno)) {
8019094Srrh 			putchar(' ');
8029094Srrh 		}
8039094Srrh #ifdef FULLDEBUG
8049094Srrh 		{
8059094Srrh 			char	*p;
8069094Srrh 			printf("[%d,%d: ", argno, np - cp);
8079094Srrh 			for (p = cp; p < np; p++) {
8089094Srrh 				putchar(*p);
8099094Srrh 			}
8109094Srrh 			printf("]");
8119094Srrh 		}
8129094Srrh #endif FULLDEBUG
8139094Srrh 		/*
8149094Srrh 		 *	Determine if the argument merits being printed
8159094Srrh 		 *
81634101Sbostic 		 *	constant is the cut off point below which something
8179094Srrh 		 *	is not a word.
8189094Srrh 		 */
81934101Sbostic 		if (   ( (np - cp) > constant)
8209094Srrh 		    && (    inquote
8219094Srrh 		         || (chars[cp[0]] == LETTER)) ){
8229094Srrh 			for (cp = cp; cp < np; cp++){
8239094Srrh 				putchar(*cp);
8249094Srrh 			}
8259094Srrh 			last = np[-1];
8269094Srrh 			found++;
8279094Srrh 		} else
8289094Srrh 		if(found && (np - cp == 1) && chars[*cp] == PUNCT){
8299094Srrh 			putchar(*cp);
8309094Srrh 		} else {
8319094Srrh 			last = np[-1];
8329094Srrh 		}
8339094Srrh 		cp = np;
8349094Srrh 	}
8359094Srrh 	if(msflag && chars[last] == PUNCT)
8369094Srrh 		putchar(last);
8379094Srrh 	putchar('\n');
8389094Srrh }
8399094Srrh /*
8409094Srrh  *	put out words (for the -w option) with ms and mm conventions
8419094Srrh  */
8429094Srrh meputwords(macline)
8439094Srrh 	int	macline;
8449094Srrh {
8459094Srrh 	msputwords(macline);
8469094Srrh }
8479094Srrh /*
8489094Srrh  *
8499094Srrh  *	Skip over a nested set of macros
8509094Srrh  *
8519094Srrh  *	Possible arguments to noblock are:
8529094Srrh  *
8539094Srrh  *	fi	end of unfilled text
8549094Srrh  *	PE	pic ending
8559094Srrh  *	DE	display ending
8569094Srrh  *
8579094Srrh  *	for ms and mm only:
8589094Srrh  *		KE	keep ending
8599094Srrh  *
8609094Srrh  *		NE	undocumented match to NS (for mm?)
8619094Srrh  *		LE	mm only: matches RL or *L (for lists)
8629094Srrh  *
8639094Srrh  *	for me:
8649094Srrh  *		([lqbzcdf]
8659094Srrh  */
8669094Srrh 
8679094Srrh noblock(a1, a2)
8689094Srrh 	char a1, a2;
8699094Srrh {
8709094Srrh 	register int c1,c2;
8719094Srrh 	register int eqnf;
8729094Srrh 	int lct;
8739094Srrh 	lct = 0;
8749094Srrh 	eqnf = 1;
8759094Srrh 	SKIP;
8769094Srrh 	while(1){
8779094Srrh 		while(C != '.')
8789094Srrh 			if(c == '\n')
8799094Srrh 				continue;
8809094Srrh 			else
8819094Srrh 				SKIP;
8829094Srrh 		if((c1=C) == '\n')
8839094Srrh 			continue;
8849094Srrh 		if((c2=C) == '\n')
8859094Srrh 			continue;
8869094Srrh 		if(c1==a1 && c2 == a2){
8879094Srrh 			SKIP;
8889094Srrh 			if(lct != 0){
8899094Srrh 				lct--;
8909094Srrh 				continue;
8919094Srrh 			}
8929094Srrh 			if(eqnf)
8939094Srrh 				putchar('.');
8949094Srrh 			putchar('\n');
8959094Srrh 			return;
8969094Srrh 		} else if(a1 == 'L' && c2 == 'L'){
8979094Srrh 			lct++;
8989094Srrh 			SKIP;
8999094Srrh 		}
9009094Srrh 		/*
9019094Srrh 		 *	equations (EQ) nested within a display
9029094Srrh 		 */
9039094Srrh 		else if(c1 == 'E' && c2 == 'Q'){
9049094Srrh 			if (   (mac == ME && a1 == ')')
9059094Srrh 			    || (mac != ME && a1 == 'D') ) {
9069094Srrh 				eqn();
9079094Srrh 				eqnf=0;
9089094Srrh 			}
9099094Srrh 		}
9109094Srrh 		/*
9119094Srrh 		 *	turning on filling is done by the paragraphing
9129094Srrh 		 *	macros
9139094Srrh 		 */
9149094Srrh 		else if(a1 == 'f') {	/* .fi */
9159094Srrh 			if  (  (mac == ME && (c2 == 'h' || c2 == 'p'))
9169094Srrh 			     ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) {
9179094Srrh 				SKIP;
9189094Srrh 				return;
9199094Srrh 			}
9209094Srrh 		} else {
9219094Srrh 			SKIP;
9229094Srrh 		}
9239094Srrh 	}
9249094Srrh }
9259094Srrh 
9269094Srrh EQ()
9279094Srrh {
9289094Srrh 	eqn();
9299094Srrh 	return(0);
9309094Srrh }
9319094Srrh domacro()
9329094Srrh {
9339094Srrh 	macro();
9349094Srrh 	return(0);
9359094Srrh }
9369094Srrh PS()
9379094Srrh {
93832271Sbostic 	for (C; c == ' ' || c == '\t'; C);
93932271Sbostic 	if (c == '<') {		/* ".PS < file" -- don't expect a .PE */
94032271Sbostic 		SKIP;
94132271Sbostic 		return(0);
94232271Sbostic 	}
9439094Srrh 	if (!msflag) {
9449094Srrh 		inpic();
9459094Srrh 	} else {
9469094Srrh 		noblock('P', 'E');
9479094Srrh 	}
9489094Srrh 	return(0);
9499094Srrh }
9509094Srrh 
9519094Srrh skip()
9529094Srrh {
9539094Srrh 	SKIP;
9549094Srrh 	return(0);
9559094Srrh }
9569094Srrh 
9579094Srrh intbl()
9589094Srrh {
9599094Srrh 	if(msflag){
9609094Srrh 		stbl();
9619094Srrh 	}
9629094Srrh 	else tbl();
9639094Srrh 	return(0);
9649094Srrh }
9659094Srrh 
9669094Srrh outtbl(){ intable = NO; }
9679094Srrh 
9689094Srrh so()
9699094Srrh {
9709094Srrh 	getfname();
9719094Srrh 	if( fname[0] )
9729094Srrh 		infile = *++filesp = opn( fname );
9739094Srrh 	return(0);
9749094Srrh }
9759094Srrh nx()
9769094Srrh {
9779094Srrh 	getfname();
9789094Srrh 	if(fname[0] == '\0') exit(0);
9799094Srrh 	if(infile != stdin)
9809094Srrh 		fclose(infile);
9819094Srrh 	infile = *filesp = opn(fname);
9829094Srrh 	return(0);
9839094Srrh }
9849094Srrh skiptocom(){ SKIP_TO_COM; return(COMX); }
9859094Srrh 
9869094Srrh PP(c12)
9879094Srrh 	pacmac	c12;
9889094Srrh {
9899094Srrh 	int	c1, c2;
9909094Srrh 
9919094Srrh 	frommac(c12, c1, c2);
9929094Srrh 	printf(".%c%c",c1,c2);
9939094Srrh 	while(C != '\n')putchar(c);
9949094Srrh 	putchar('\n');
9959094Srrh 	return(0);
9969094Srrh }
9979094Srrh AU()
9989094Srrh {
9999094Srrh 	if(mac==MM) {
10009094Srrh 		return(0);
10019094Srrh 	} else {
10029094Srrh 		SKIP_TO_COM;
10039094Srrh 		return(COMX);
10049094Srrh 	}
10059094Srrh }
10069094Srrh 
10079094Srrh SH(c12)
10089094Srrh 	pacmac	c12;
10099094Srrh {
10109094Srrh 	int	c1, c2;
10119094Srrh 
10129094Srrh 	frommac(c12, c1, c2);
10139094Srrh 
10149094Srrh 	if(parag){
10159094Srrh 		printf(".%c%c",c1,c2);
10169094Srrh 		while(C != '\n')putchar(c);
10179094Srrh 		putchar(c);
10189094Srrh 		putchar('!');
10199094Srrh 		while(1){
10209094Srrh 			while(C != '\n')putchar(c);
10219094Srrh 			putchar('\n');
10229094Srrh 			if(C == '.')
10239094Srrh 				return(COM);
10249094Srrh 			putchar('!');
10259094Srrh 			putchar(c);
10269094Srrh 		}
10279094Srrh 		/*NOTREACHED*/
10289094Srrh 	} else {
10299094Srrh 		SKIP_TO_COM;
10309094Srrh 		return(COMX);
10319094Srrh 	}
10329094Srrh }
10339094Srrh 
10349094Srrh UX()
10359094Srrh {
10369094Srrh 	if(wordflag)
10379094Srrh 		printf("UNIX\n");
10389094Srrh 	else
10399094Srrh 		printf("UNIX ");
10409094Srrh 	return(0);
10419094Srrh }
10429094Srrh 
10439094Srrh MMHU(c12)
10449094Srrh 	pacmac	c12;
10459094Srrh {
10469094Srrh 	int	c1, c2;
10479094Srrh 
10489094Srrh 	frommac(c12, c1, c2);
10499094Srrh 	if(parag){
10509094Srrh 		printf(".%c%c",c1,c2);
10519094Srrh 		while(C != '\n')putchar(c);
10529094Srrh 		putchar('\n');
10539094Srrh 	} else {
10549094Srrh 		SKIP;
10559094Srrh 	}
10569094Srrh 	return(0);
10579094Srrh }
10589094Srrh 
10599094Srrh mesnblock(c12)
10609094Srrh 	pacmac	c12;
10619094Srrh {
10629094Srrh 	int	c1, c2;
10639094Srrh 
10649094Srrh 	frommac(c12, c1, c2);
10659094Srrh 	noblock(')',c2);
10669094Srrh 	return(0);
10679094Srrh }
10689094Srrh mssnblock(c12)
10699094Srrh 	pacmac	c12;
10709094Srrh {
10719094Srrh 	int	c1, c2;
10729094Srrh 
10739094Srrh 	frommac(c12, c1, c2);
10749094Srrh 	noblock(c1,'E');
10759094Srrh 	return(0);
10769094Srrh }
10779094Srrh nf()
10789094Srrh {
10799094Srrh 	noblock('f','i');
10809094Srrh 	return(0);
10819094Srrh }
10829094Srrh 
10839094Srrh ce()
10849094Srrh {
10859094Srrh 	sce();
10869094Srrh 	return(0);
10879094Srrh }
10889094Srrh 
10899094Srrh meip(c12)
10909094Srrh 	pacmac	c12;
10919094Srrh {
10929094Srrh 	if(parag)
10939094Srrh 		mepp(c12);
10949094Srrh 	else if (wordflag)	/* save the tag */
10959094Srrh 		regline(meputmac, ONE);
10969094Srrh 	else {
10979094Srrh 		SKIP;
10989094Srrh 	}
10999094Srrh 	return(0);
11009094Srrh }
11019094Srrh /*
11029094Srrh  *	only called for -me .pp or .sh, when parag is on
11039094Srrh  */
11049094Srrh mepp(c12)
11059094Srrh 	pacmac	c12;
11069094Srrh {
11079094Srrh 	PP(c12);		/* eats the line */
11089094Srrh 	return(0);
11099094Srrh }
11109094Srrh /*
11119094Srrh  *	Start of a section heading; output the section name if doing words
11129094Srrh  */
11139094Srrh mesh(c12)
11149094Srrh 	pacmac	c12;
11159094Srrh {
11169094Srrh 	if (parag)
11179094Srrh 		mepp(c12);
11189094Srrh 	else if (wordflag)
11199094Srrh 		defcomline(c12);
11209094Srrh 	else {
11219094Srrh 		SKIP;
11229094Srrh 	}
11239094Srrh 	return(0);
11249094Srrh }
11259094Srrh /*
11269094Srrh  *	process a font setting
11279094Srrh  */
11289094Srrh mefont(c12)
11299094Srrh 	pacmac	c12;
11309094Srrh {
11319094Srrh 	argconcat = 1;
11329094Srrh 	defcomline(c12);
11339094Srrh 	argconcat = 0;
11349094Srrh 	return(0);
11359094Srrh }
11369094Srrh manfont(c12)
11379094Srrh 	pacmac	c12;
11389094Srrh {
11399094Srrh 	return(mefont(c12));
11409094Srrh }
11419094Srrh manpp(c12)
11429094Srrh 	pacmac	c12;
11439094Srrh {
11449094Srrh 	return(mepp(c12));
11459094Srrh }
11469094Srrh 
11479094Srrh defcomline(c12)
11489094Srrh 	pacmac	c12;
11499094Srrh {
11509094Srrh 	int	c1, c2;
11519094Srrh 
11529094Srrh 	frommac(c12, c1, c2);
11539094Srrh 	if(msflag && mac==MM && c2=='L'){
11549094Srrh 		if(disp || c1 == 'R') {
11559094Srrh 			noblock('L','E');
11569094Srrh 		} else {
11579094Srrh 			SKIP;
11589094Srrh 			putchar('.');
11599094Srrh 		}
11609094Srrh 	}
11619094Srrh 	else if(c1=='.' && c2=='.'){
11629094Srrh 		if(msflag){
11639094Srrh 			SKIP;
11649094Srrh 			return;
11659094Srrh 		}
11669094Srrh 		while(C == '.')
11679094Srrh 			/*VOID*/;
11689094Srrh 	}
11699094Srrh 	++inmacro;
11709094Srrh 	/*
11719094Srrh 	 *	Process the arguments to the macro
11729094Srrh 	 */
11739094Srrh 	switch(mac){
11749094Srrh 	default:
11759094Srrh 	case MM:
11769094Srrh 	case MS:
11779094Srrh 		if(c1 <= 'Z' && msflag)
11789094Srrh 			regline(msputmac, ONE);
11799094Srrh 		else
11809094Srrh 			regline(msputmac, TWO);
11819094Srrh 		break;
11829094Srrh 	case ME:
11839094Srrh 		regline(meputmac, ONE);
11849094Srrh 		break;
11859094Srrh 	}
11869094Srrh 	--inmacro;
11879094Srrh }
11889094Srrh 
11899094Srrh comline()
11909094Srrh {
11919094Srrh 	reg	int	c1;
11929094Srrh 	reg	int	c2;
11939094Srrh 		pacmac	c12;
11949094Srrh 	reg	int	mid;
11959094Srrh 		int	lb, ub;
11969094Srrh 		int	hit;
11979094Srrh 	static	int	tabsize = 0;
11989094Srrh 	static	struct	mactab	*mactab = (struct mactab *)0;
11999094Srrh 	reg	struct	mactab	*mp;
12009094Srrh 
12019094Srrh 	if (mactab == 0){
12029094Srrh 		 buildtab(&mactab, &tabsize);
12039094Srrh 	}
12049094Srrh com:
12059094Srrh 	while(C==' ' || c=='\t')
12069094Srrh 		;
12079094Srrh comx:
12089094Srrh 	if( (c1=c) == '\n')
12099094Srrh 		return;
12109094Srrh 	c2 = C;
12119094Srrh 	if(c1=='.' && c2 !='.')
12129094Srrh 		inmacro = NO;
12139094Srrh 	if(msflag && c1 == '['){
12149094Srrh 		refer(c2);
12159094Srrh 		return;
12169094Srrh 	}
12179094Srrh 	if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
12189094Srrh 		printf(".P\n");
12199094Srrh 		return;
12209094Srrh 	}
12219094Srrh 	if(c2 == '\n')
12229094Srrh 		return;
12239094Srrh 	/*
12249094Srrh 	 *	Single letter macro
12259094Srrh 	 */
12269094Srrh 	if (mac == ME && (c2 == ' ' || c2 == '\t') )
12279094Srrh 		c2 = ' ';
12289094Srrh 	c12 = tomac(c1, c2);
12299094Srrh 	/*
12309094Srrh 	 *	binary search through the table of macros
12319094Srrh 	 */
12329094Srrh 	lb = 0;
12339094Srrh 	ub = tabsize - 1;
12349094Srrh 	while(lb <= ub){
12359094Srrh 		mid = (ub + lb) / 2;
12369094Srrh 		mp = &mactab[mid];
12379094Srrh 		if (mp->macname < c12)
12389094Srrh 			lb = mid + 1;
12399094Srrh 		else if (mp->macname > c12)
12409094Srrh 			ub = mid - 1;
12419094Srrh 		else {
12429094Srrh 			hit = 1;
12439094Srrh #ifdef FULLDEBUG
12449094Srrh 			printf("preliminary hit macro %c%c ", c1, c2);
12459094Srrh #endif FULLDEBUG
12469094Srrh 			switch(mp->condition){
12479094Srrh 			case NONE:	hit = YES;			break;
12489094Srrh 			case FNEST:	hit = (filesp == files);	break;
12499094Srrh 			case NOMAC:	hit = !inmacro;			break;
12509094Srrh 			case MAC:	hit = inmacro;			break;
12519094Srrh 			case PARAG:	hit = parag;			break;
12529094Srrh 			case NBLK:	hit = !keepblock;		break;
12539094Srrh 			default:	hit = 0;
12549094Srrh 			}
12559094Srrh 			if (hit) {
12569094Srrh #ifdef FULLDEBUG
12579094Srrh 				printf("MATCH\n");
12589094Srrh #endif FULLDEBUG
12599094Srrh 				switch( (*(mp->func))(c12) ) {
12609094Srrh 				default: 	return;
12619094Srrh 				case COMX:	goto comx;
12629094Srrh 				case COM:	goto com;
12639094Srrh 				}
12649094Srrh 			}
12659094Srrh #ifdef FULLDEBUG
12669094Srrh 			printf("FAIL\n");
12679094Srrh #endif FULLDEBUG
12689094Srrh 			break;
12699094Srrh 		}
12709094Srrh 	}
12719094Srrh 	defcomline(c12);
12729094Srrh }
12739094Srrh 
12749094Srrh int macsort(p1, p2)
12759094Srrh 	struct	mactab	*p1, *p2;
12769094Srrh {
12779094Srrh 	return(p1->macname - p2->macname);
12789094Srrh }
12799094Srrh 
12809094Srrh int sizetab(mp)
12819094Srrh 	reg	struct	mactab	*mp;
12829094Srrh {
12839094Srrh 	reg	int	i;
12849094Srrh 	i = 0;
12859094Srrh 	if (mp){
12869094Srrh 		for (; mp->macname; mp++, i++)
12879094Srrh 			/*VOID*/ ;
12889094Srrh 	}
12899094Srrh 	return(i);
12909094Srrh }
12919094Srrh 
12929094Srrh struct mactab *macfill(dst, src)
12939094Srrh 	reg	struct	mactab	*dst;
12949094Srrh 	reg	struct	mactab	*src;
12959094Srrh {
12969094Srrh 	if (src) {
12979094Srrh 		while(src->macname){
12989094Srrh 			*dst++ = *src++;
12999094Srrh 		}
13009094Srrh 	}
13019094Srrh 	return(dst);
13029094Srrh }
13039094Srrh 
13049094Srrh buildtab(r_back, r_size)
13059094Srrh 	struct	mactab	**r_back;
13069094Srrh 	int	*r_size;
13079094Srrh {
13089094Srrh 	int	size;
13099094Srrh 
13109094Srrh 	struct	mactab	*p, *p1, *p2;
13119094Srrh 	struct	mactab	*back;
13129094Srrh 
13139094Srrh 	size = sizetab(troffmactab);
13149094Srrh 	size += sizetab(ppmactab);
13159094Srrh 	p1 = p2 = (struct mactab *)0;
13169094Srrh 	if (msflag){
13179094Srrh 		switch(mac){
13189094Srrh 		case ME:	p1 = memactab; break;
13199094Srrh 		case MM:	p1 = msmactab;
13209094Srrh 				p2 = mmmactab; break;
13219094Srrh 
13229094Srrh 		case MS:	p1 = msmactab; break;
13239094Srrh 		case MA:	p1 = manmactab; break;
13249094Srrh 		default:	break;
13259094Srrh 		}
13269094Srrh 	}
13279094Srrh 	size += sizetab(p1);
13289094Srrh 	size += sizetab(p2);
13299094Srrh 	back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
13309094Srrh 
13319094Srrh 	p = macfill(back, troffmactab);
13329094Srrh 	p = macfill(p, ppmactab);
13339094Srrh 	p = macfill(p, p1);
13349094Srrh 	p = macfill(p, p2);
13359094Srrh 
13369094Srrh 	qsort(back, size, sizeof(struct mactab), macsort);
13379094Srrh 	*r_size = size;
13389094Srrh 	*r_back = back;
13399094Srrh }
13409094Srrh 
13419094Srrh /*
13429094Srrh  *	troff commands
13439094Srrh  */
13449094Srrh struct	mactab	troffmactab[] = {
13459094Srrh 	M(NONE,		'\\','"',	skip),	/* comment */
13469094Srrh 	M(NOMAC,	'd','e',	domacro),	/* define */
13479094Srrh 	M(NOMAC,	'i','g',	domacro),	/* ignore till .. */
13489094Srrh 	M(NOMAC,	'a','m',	domacro),	/* append macro */
13499094Srrh 	M(NBLK,		'n','f',	nf),	/* filled */
13509094Srrh 	M(NBLK,		'c','e',	ce),	/* centered */
13519094Srrh 
13529094Srrh 	M(NONE,		's','o',	so),	/* source a file */
13539094Srrh 	M(NONE,		'n','x',	nx),	/* go to next file */
13549094Srrh 
13559094Srrh 	M(NONE,		't','m',	skip),	/* print string on tty */
13569094Srrh 	M(NONE,		'h','w',	skip),	/* exception hyphen words */
13579094Srrh 	M(NONE,		0,0,		0)
13589094Srrh };
13599094Srrh /*
13609094Srrh  *	Preprocessor output
13619094Srrh  */
13629094Srrh struct	mactab	ppmactab[] = {
13639094Srrh 	M(FNEST,	'E','Q',	EQ),	/* equation starting */
13649094Srrh 	M(FNEST,	'T','S',	intbl),	/* table starting */
13659094Srrh 	M(FNEST,	'T','C',	intbl),	/* alternative table? */
13669094Srrh 	M(FNEST,	'T','&',	intbl),	/* table reformatting */
13679094Srrh 	M(NONE,		'T','E',	outtbl),/* table ending */
13689094Srrh 	M(NONE,		'P','S',	PS),	/* picture starting */
13699094Srrh 	M(NONE,		0,0,		0)
13709094Srrh };
13719094Srrh /*
13729094Srrh  *	Particular to ms and mm
13739094Srrh  */
13749094Srrh struct	mactab	msmactab[] = {
13759094Srrh 	M(NONE,		'T','L',	skiptocom),	/* title follows */
13769094Srrh 	M(NONE,		'F','S',	skiptocom),	/* start footnote */
13779094Srrh 	M(NONE,		'O','K',	skiptocom),	/* Other kws */
13789094Srrh 
13799094Srrh 	M(NONE,		'N','R',	skip),	/* undocumented */
13809094Srrh 	M(NONE,		'N','D',	skip),	/* use supplied date */
13819094Srrh 
13829094Srrh 	M(PARAG,	'P','P',	PP),	/* begin parag */
13839094Srrh 	M(PARAG,	'I','P',	PP),	/* begin indent parag, tag x */
13849094Srrh 	M(PARAG,	'L','P',	PP),	/* left blocked parag */
13859094Srrh 
13869094Srrh 	M(NONE,		'A','U',	AU),	/* author */
13879094Srrh 	M(NONE,		'A','I',	AU),	/* authors institution */
13889094Srrh 
13899094Srrh 	M(NONE,		'S','H',	SH),	/* section heading */
13909094Srrh 	M(NONE,		'S','N',	SH),	/* undocumented */
13919094Srrh 	M(NONE,		'U','X',	UX),	/* unix */
13929094Srrh 
13939094Srrh 	M(NBLK,		'D','S',	mssnblock),	/* start display text */
13949094Srrh 	M(NBLK,		'K','S',	mssnblock),	/* start keep */
13959094Srrh 	M(NBLK,		'K','F',	mssnblock),	/* start float keep */
13969094Srrh 	M(NONE,		0,0,		0)
13979094Srrh };
13989094Srrh 
13999094Srrh struct	mactab	mmmactab[] = {
14009094Srrh 	M(NONE,		'H',' ',	MMHU),	/* -mm ? */
14019094Srrh 	M(NONE,		'H','U',	MMHU),	/* -mm ? */
14029094Srrh 	M(PARAG,	'P',' ',	PP),	/* paragraph for -mm */
14039094Srrh 	M(NBLK,		'N','S',	mssnblock),	/* undocumented */
14049094Srrh 	M(NONE,		0,0,		0)
14059094Srrh };
14069094Srrh 
14079094Srrh struct	mactab	memactab[] = {
14089094Srrh 	M(PARAG,	'p','p',	mepp),
14099094Srrh 	M(PARAG,	'l','p',	mepp),
14109094Srrh 	M(PARAG,	'n','p',	mepp),
14119094Srrh 	M(NONE,		'i','p',	meip),
14129094Srrh 
14139094Srrh 	M(NONE,		's','h',	mesh),
14149094Srrh 	M(NONE,		'u','h',	mesh),
14159094Srrh 
14169094Srrh 	M(NBLK,		'(','l',	mesnblock),
14179094Srrh 	M(NBLK,		'(','q',	mesnblock),
14189094Srrh 	M(NBLK,		'(','b',	mesnblock),
14199094Srrh 	M(NBLK,		'(','z',	mesnblock),
14209094Srrh 	M(NBLK,		'(','c',	mesnblock),
14219094Srrh 
14229094Srrh 	M(NBLK,		'(','d',	mesnblock),
14239094Srrh 	M(NBLK,		'(','f',	mesnblock),
14249094Srrh 	M(NBLK,		'(','x',	mesnblock),
14259094Srrh 
14269094Srrh 	M(NONE,		'r',' ',	mefont),
14279094Srrh 	M(NONE,		'i',' ',	mefont),
14289094Srrh 	M(NONE,		'b',' ',	mefont),
14299094Srrh 	M(NONE,		'u',' ',	mefont),
14309094Srrh 	M(NONE,		'q',' ',	mefont),
14319094Srrh 	M(NONE,		'r','b',	mefont),
14329094Srrh 	M(NONE,		'b','i',	mefont),
14339094Srrh 	M(NONE,		'b','x',	mefont),
14349094Srrh 	M(NONE,		0,0,		0)
14359094Srrh };
14369094Srrh 
14379094Srrh 
14389094Srrh struct	mactab	manmactab[] = {
14399094Srrh 	M(PARAG,	'B','I',	manfont),
14409094Srrh 	M(PARAG,	'B','R',	manfont),
14419094Srrh 	M(PARAG,	'I','B',	manfont),
14429094Srrh 	M(PARAG,	'I','R',	manfont),
14439094Srrh 	M(PARAG,	'R','B',	manfont),
14449094Srrh 	M(PARAG,	'R','I',	manfont),
14459094Srrh 
14469094Srrh 	M(PARAG,	'P','P',	manpp),
14479094Srrh 	M(PARAG,	'L','P',	manpp),
14489094Srrh 	M(PARAG,	'H','P',	manpp),
14499094Srrh 	M(NONE,		0,0,		0)
14509094Srrh };
1451