xref: /openbsd-src/usr.bin/deroff/deroff.c (revision 08e9b19a4d03c0460760a69df3eff400acd69e32)
1*08e9b19aSmillert /*	$OpenBSD: deroff.c,v 1.18 2023/09/27 21:06:33 millert Exp $	*/
225a69cdcSmillert 
325a69cdcSmillert /*-
425a69cdcSmillert  * Copyright (c) 1988, 1993
525a69cdcSmillert  *	The Regents of the University of California.  All rights reserved.
625a69cdcSmillert  *
725a69cdcSmillert  * Redistribution and use in source and binary forms, with or without
825a69cdcSmillert  * modification, are permitted provided that the following conditions
925a69cdcSmillert  * are met:
1025a69cdcSmillert  * 1. Redistributions of source code must retain the above copyright
1125a69cdcSmillert  *    notice, this list of conditions and the following disclaimer.
1225a69cdcSmillert  * 2. Redistributions in binary form must reproduce the above copyright
1325a69cdcSmillert  *    notice, this list of conditions and the following disclaimer in the
1425a69cdcSmillert  *    documentation and/or other materials provided with the distribution.
15f75387cbSmillert  * 3. Neither the name of the University nor the names of its contributors
1625a69cdcSmillert  *    may be used to endorse or promote products derived from this software
1725a69cdcSmillert  *    without specific prior written permission.
1825a69cdcSmillert  *
1925a69cdcSmillert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2025a69cdcSmillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2125a69cdcSmillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2225a69cdcSmillert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2325a69cdcSmillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2425a69cdcSmillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2525a69cdcSmillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2625a69cdcSmillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2725a69cdcSmillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2825a69cdcSmillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2925a69cdcSmillert  * SUCH DAMAGE.
3025a69cdcSmillert  */
3125a69cdcSmillert /*
3225a69cdcSmillert  * Copyright (C) Caldera International Inc.  2001-2002.
3325a69cdcSmillert  * All rights reserved.
3425a69cdcSmillert  *
3525a69cdcSmillert  * Redistribution and use in source and binary forms, with or without
3625a69cdcSmillert  * modification, are permitted provided that the following conditions
3725a69cdcSmillert  * are met:
3825a69cdcSmillert  * 1. Redistributions of source code and documentation must retain the above
3925a69cdcSmillert  *    copyright notice, this list of conditions and the following disclaimer.
4025a69cdcSmillert  * 2. Redistributions in binary form must reproduce the above copyright
4125a69cdcSmillert  *    notice, this list of conditions and the following disclaimer in the
4225a69cdcSmillert  *    documentation and/or other materials provided with the distribution.
4325a69cdcSmillert  * 3. All advertising materials mentioning features or use of this software
4425a69cdcSmillert  *    must display the following acknowledgement:
4525a69cdcSmillert  *	This product includes software developed or owned by Caldera
4625a69cdcSmillert  *	International, Inc.
4725a69cdcSmillert  * 4. Neither the name of Caldera International, Inc. nor the names of other
4825a69cdcSmillert  *    contributors may be used to endorse or promote products derived from
4925a69cdcSmillert  *    this software without specific prior written permission.
5025a69cdcSmillert  *
5125a69cdcSmillert  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
5225a69cdcSmillert  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
5325a69cdcSmillert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5425a69cdcSmillert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5525a69cdcSmillert  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
5625a69cdcSmillert  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5725a69cdcSmillert  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5825a69cdcSmillert  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5925a69cdcSmillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
6025a69cdcSmillert  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
6125a69cdcSmillert  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
6225a69cdcSmillert  * POSSIBILITY OF SUCH DAMAGE.
6325a69cdcSmillert  */
6425a69cdcSmillert 
6525a69cdcSmillert #include <err.h>
6625a69cdcSmillert #include <limits.h>
6725a69cdcSmillert #include <stdio.h>
6825a69cdcSmillert #include <stdlib.h>
6925a69cdcSmillert #include <string.h>
7025a69cdcSmillert #include <unistd.h>
7125a69cdcSmillert 
7225a69cdcSmillert /*
7325a69cdcSmillert  *	Deroff command -- strip troff, eqn, and Tbl sequences from
7425a69cdcSmillert  *	a file.  Has two flags argument, -w, to cause output one word per line
7525a69cdcSmillert  *	rather than in the original format.
7625a69cdcSmillert  *	-mm (or -ms) causes the corresponding macro's to be interpreted
7725a69cdcSmillert  *	so that just sentences are output
7825a69cdcSmillert  *	-ml  also gets rid of lists.
7925a69cdcSmillert  *	Deroff follows .so and .nx commands, removes contents of macro
8025a69cdcSmillert  *	definitions, equations (both .EQ ... .EN and $...$),
8125a69cdcSmillert  *	Tbl command sequences, and Troff backslash constructions.
8225a69cdcSmillert  *
8325a69cdcSmillert  *	All input is through the Cget macro;
8425a69cdcSmillert  *	the most recently read character is in c.
8525a69cdcSmillert  *
8625a69cdcSmillert  *	Modified by Robert Henry to process -me and -man macros.
8725a69cdcSmillert  */
8825a69cdcSmillert 
8925a69cdcSmillert #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
9025a69cdcSmillert #define C1get ( (c=getc(infile)) == EOF ? eof() :  c)
9125a69cdcSmillert 
9225a69cdcSmillert #ifdef DEBUG
9325a69cdcSmillert #  define C	_C()
9425a69cdcSmillert #  define C1	_C1()
95dc955345Sdanh #else /* not DEBUG */
9625a69cdcSmillert #  define C	Cget
9725a69cdcSmillert #  define C1	C1get
98dc955345Sdanh #endif /* not DEBUG */
9925a69cdcSmillert 
10025a69cdcSmillert #define SKIP while (C != '\n')
10125a69cdcSmillert #define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c
10225a69cdcSmillert 
10325a69cdcSmillert #define	YES 1
10425a69cdcSmillert #define	NO 0
10525a69cdcSmillert #define	MS 0	/* -ms */
10625a69cdcSmillert #define	MM 1	/* -mm */
10725a69cdcSmillert #define	ME 2	/* -me */
10825a69cdcSmillert #define	MA 3	/* -man */
10925a69cdcSmillert 
11025a69cdcSmillert #ifdef DEBUG
11125a69cdcSmillert char *mactab[] = { "-ms", "-mm", "-me", "-ma" };
112dc955345Sdanh #endif /* DEBUG */
11325a69cdcSmillert 
11425a69cdcSmillert #define	ONE 1
11525a69cdcSmillert #define	TWO 2
11625a69cdcSmillert 
11725a69cdcSmillert #define NOCHAR -2
11825a69cdcSmillert #define SPECIAL 0
11925a69cdcSmillert #define APOS 1
12025a69cdcSmillert #define PUNCT 2
12125a69cdcSmillert #define DIGIT 3
12225a69cdcSmillert #define LETTER 4
12325a69cdcSmillert 
12425a69cdcSmillert #define MAXFILES 20
12525a69cdcSmillert 
12625a69cdcSmillert int	iflag;
12725a69cdcSmillert int	wordflag;
12825a69cdcSmillert int	msflag;		/* processing a source written using a mac package */
12925a69cdcSmillert int	mac;		/* which package */
13025a69cdcSmillert int	disp;
13125a69cdcSmillert int	parag;
13225a69cdcSmillert int	inmacro;
13325a69cdcSmillert int	intable;
13425a69cdcSmillert int	keepblock;	/* keep blocks of text; normally false when msflag */
13525a69cdcSmillert 
13625a69cdcSmillert char chars[128];  /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
13725a69cdcSmillert 
138*08e9b19aSmillert size_t linesz;
139*08e9b19aSmillert char *line;
14025a69cdcSmillert char *lp;
14125a69cdcSmillert 
14225a69cdcSmillert int c;
14325a69cdcSmillert int pc;
14425a69cdcSmillert int ldelim;
14525a69cdcSmillert int rdelim;
14625a69cdcSmillert 
14725a69cdcSmillert char fname[PATH_MAX];
14825a69cdcSmillert FILE *files[MAXFILES];
14925a69cdcSmillert FILE **filesp;
15025a69cdcSmillert FILE *infile;
15125a69cdcSmillert 
15225a69cdcSmillert int argc;
15325a69cdcSmillert char **argv;
15425a69cdcSmillert 
15525a69cdcSmillert /*
15625a69cdcSmillert  *	Macro processing
15725a69cdcSmillert  *
15825a69cdcSmillert  *	Macro table definitions
15925a69cdcSmillert  */
16025a69cdcSmillert typedef	int pacmac;		/* compressed macro name */
16125a69cdcSmillert int	argconcat = 0;		/* concat arguments together (-me only) */
16225a69cdcSmillert 
16325a69cdcSmillert #define	tomac(c1, c2)		((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
16425a69cdcSmillert #define	frommac(src, c1, c2)	(((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
16525a69cdcSmillert 
16625a69cdcSmillert struct mactab{
16725a69cdcSmillert 	int	condition;
16825a69cdcSmillert 	pacmac	macname;
16925a69cdcSmillert 	int	(*func)();	/* XXX - args */
17025a69cdcSmillert };
17125a69cdcSmillert 
17225a69cdcSmillert struct	mactab	troffmactab[];
17325a69cdcSmillert struct	mactab	ppmactab[];
17425a69cdcSmillert struct	mactab	msmactab[];
17525a69cdcSmillert struct	mactab	mmmactab[];
17625a69cdcSmillert struct	mactab	memactab[];
17725a69cdcSmillert struct	mactab	manmactab[];
17825a69cdcSmillert 
17925a69cdcSmillert /*
18025a69cdcSmillert  *	Macro table initialization
18125a69cdcSmillert  */
18225a69cdcSmillert #define	M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
18325a69cdcSmillert 
18425a69cdcSmillert /*
18525a69cdcSmillert  *	Flags for matching conditions other than
18625a69cdcSmillert  *	the macro name
18725a69cdcSmillert  */
18825a69cdcSmillert #define	NONE		0
18925a69cdcSmillert #define	FNEST		1		/* no nested files */
19025a69cdcSmillert #define	NOMAC		2		/* no macro */
19125a69cdcSmillert #define	MAC		3		/* macro */
19225a69cdcSmillert #define	PARAG		4		/* in a paragraph */
19325a69cdcSmillert #define	MSF		5		/* msflag is on */
19425a69cdcSmillert #define	NBLK		6		/* set if no blocks to be kept */
19525a69cdcSmillert 
19625a69cdcSmillert /*
19725a69cdcSmillert  *	Return codes from macro minions, determine where to jump,
19825a69cdcSmillert  *	how to repeat/reprocess text
19925a69cdcSmillert  */
20025a69cdcSmillert #define	COMX		1		/* goto comx */
20125a69cdcSmillert #define	COM		2		/* goto com */
20225a69cdcSmillert 
20325a69cdcSmillert int	 skeqn(void);
20425a69cdcSmillert int	 eof(void);
20525a69cdcSmillert int	 _C1(void);
20625a69cdcSmillert int	 _C(void);
20725a69cdcSmillert int	 EQ(void);
20825a69cdcSmillert int	 domacro(void);
20925a69cdcSmillert int	 PS(void);
21025a69cdcSmillert int	 skip(void);
21125a69cdcSmillert int	 intbl(void);
21225a69cdcSmillert int	 outtbl(void);
21325a69cdcSmillert int	 so(void);
21425a69cdcSmillert int	 nx(void);
21525a69cdcSmillert int	 skiptocom(void);
21625a69cdcSmillert int	 PP(pacmac);
21725a69cdcSmillert int	 AU(void);
21825a69cdcSmillert int	 SH(pacmac);
21925a69cdcSmillert int	 UX(void);
22025a69cdcSmillert int	 MMHU(pacmac);
22125a69cdcSmillert int	 mesnblock(pacmac);
22225a69cdcSmillert int	 mssnblock(pacmac);
22325a69cdcSmillert int	 nf(void);
22425a69cdcSmillert int	 ce(void);
22525a69cdcSmillert int	 meip(pacmac);
22625a69cdcSmillert int	 mepp(pacmac);
22725a69cdcSmillert int	 mesh(pacmac);
22825a69cdcSmillert int	 mefont(pacmac);
22925a69cdcSmillert int	 manfont(pacmac);
23025a69cdcSmillert int	 manpp(pacmac);
23125a69cdcSmillert int	 macsort(const void *, const void *);
23225a69cdcSmillert int	 sizetab(struct mactab *);
23325a69cdcSmillert void	 getfname(void);
23425a69cdcSmillert void	 textline(char *, int);
23525a69cdcSmillert void	 work(void);
23625a69cdcSmillert void	 regline(void (*)(char *, int), int);
23725a69cdcSmillert void	 macro(void);
23825a69cdcSmillert void	 tbl(void);
23925a69cdcSmillert void	 stbl(void);
24025a69cdcSmillert void	 eqn(void);
24125a69cdcSmillert void	 backsl(void);
24225a69cdcSmillert void	 sce(void);
24325a69cdcSmillert void	 refer(int);
24425a69cdcSmillert void	 inpic(void);
24525a69cdcSmillert void	 msputmac(char *, int);
24625a69cdcSmillert void	 msputwords(int);
24725a69cdcSmillert void	 meputmac(char *, int);
24825a69cdcSmillert void	 meputwords(int);
24925a69cdcSmillert void	 noblock(char, char);
25025a69cdcSmillert void	 defcomline(pacmac);
25125a69cdcSmillert void	 comline(void);
25225a69cdcSmillert void	 buildtab(struct mactab **, int *);
25325a69cdcSmillert FILE	*opn(char *);
25425a69cdcSmillert struct mactab *macfill(struct mactab *, struct mactab *);
25525a69cdcSmillert __dead void usage(void);
25625a69cdcSmillert 
25725a69cdcSmillert int
main(int ac,char ** av)25825a69cdcSmillert main(int ac, char **av)
25925a69cdcSmillert {
26025a69cdcSmillert 	int	i, ch;
26125a69cdcSmillert 	int	errflg = 0;
26225a69cdcSmillert 	int	kflag = NO;
26325a69cdcSmillert 
2640bd1216cSderaadt 	if (pledge("stdio rpath", NULL) == -1)
2650bd1216cSderaadt 		err(1, "pledge");
266a3c3e8edSderaadt 
26725a69cdcSmillert 	iflag = NO;
26825a69cdcSmillert 	wordflag = NO;
26925a69cdcSmillert 	msflag = NO;
27025a69cdcSmillert 	mac = ME;
27125a69cdcSmillert 	disp = NO;
27225a69cdcSmillert 	parag = NO;
27325a69cdcSmillert 	inmacro = NO;
27425a69cdcSmillert 	intable = NO;
27525a69cdcSmillert 	ldelim	= NOCHAR;
27625a69cdcSmillert 	rdelim	= NOCHAR;
27725a69cdcSmillert 	keepblock = YES;
27825a69cdcSmillert 
27925a69cdcSmillert 	while ((ch = getopt(ac, av, "ikpwm:")) != -1) {
28025a69cdcSmillert 		switch (ch) {
28125a69cdcSmillert 		case 'i':
28225a69cdcSmillert 			iflag = YES;
28325a69cdcSmillert 			break;
28425a69cdcSmillert 		case 'k':
28525a69cdcSmillert 			kflag = YES;
28625a69cdcSmillert 			break;
28725a69cdcSmillert 		case 'm':
28825a69cdcSmillert 			msflag = YES;
28925a69cdcSmillert 			keepblock = NO;
29025a69cdcSmillert 			switch (optarg[0]) {
29125a69cdcSmillert 			case 'm':
29225a69cdcSmillert 				mac = MM;
29325a69cdcSmillert 				break;
29425a69cdcSmillert 			case 's':
29525a69cdcSmillert 				mac = MS;
29625a69cdcSmillert 				break;
29725a69cdcSmillert 			case 'e':
29825a69cdcSmillert 				mac = ME;
29925a69cdcSmillert 				break;
30025a69cdcSmillert 			case 'a':
30125a69cdcSmillert 				mac = MA;
30225a69cdcSmillert 				break;
30325a69cdcSmillert 			case 'l':
30425a69cdcSmillert 				disp = YES;
30525a69cdcSmillert 				break;
30625a69cdcSmillert 			default:
30783977142Stedu 				errflg = 1;
30825a69cdcSmillert 				break;
30925a69cdcSmillert 			}
31083977142Stedu 			if (optarg[1] != '\0')
31183977142Stedu 				errflg = 1;
31225a69cdcSmillert 			break;
31325a69cdcSmillert 		case 'p':
31425a69cdcSmillert 			parag = YES;
31525a69cdcSmillert 			break;
31625a69cdcSmillert 		case 'w':
31725a69cdcSmillert 			wordflag = YES;
31825a69cdcSmillert 			kflag = YES;
31925a69cdcSmillert 			break;
32025a69cdcSmillert 		default:
32183977142Stedu 			errflg = 1;
32225a69cdcSmillert 		}
32325a69cdcSmillert 	}
32425a69cdcSmillert 	argc = ac - optind;
32525a69cdcSmillert 	argv = av + optind;
32625a69cdcSmillert 
32725a69cdcSmillert 	if (kflag)
32825a69cdcSmillert 		keepblock = YES;
32925a69cdcSmillert 	if (errflg)
33025a69cdcSmillert 		usage();
33125a69cdcSmillert 
33225a69cdcSmillert #ifdef DEBUG
33325a69cdcSmillert 	printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
33425a69cdcSmillert 		msflag, mactab[mac], keepblock, disp);
335dc955345Sdanh #endif /* DEBUG */
33625a69cdcSmillert 	if (argc == 0) {
33725a69cdcSmillert 		infile = stdin;
33825a69cdcSmillert 	} else {
33925a69cdcSmillert 		infile = opn(argv[0]);
34025a69cdcSmillert 		--argc;
34125a69cdcSmillert 		++argv;
34225a69cdcSmillert 	}
34325a69cdcSmillert 	files[0] = infile;
34425a69cdcSmillert 	filesp = &files[0];
34525a69cdcSmillert 
346*08e9b19aSmillert 	linesz = LINE_MAX;
347*08e9b19aSmillert 	if ((line = malloc(linesz)) == NULL)
348*08e9b19aSmillert 		err(1, NULL);
349*08e9b19aSmillert 
35025a69cdcSmillert 	for (i = 'a'; i <= 'z'; ++i)
35125a69cdcSmillert 		chars[i] = LETTER;
35225a69cdcSmillert 	for (i = 'A'; i <= 'Z'; ++i)
35325a69cdcSmillert 		chars[i] = LETTER;
35425a69cdcSmillert 	for (i = '0'; i <= '9'; ++i)
35525a69cdcSmillert 		chars[i] = DIGIT;
35625a69cdcSmillert 	chars['\''] = APOS;
35725a69cdcSmillert 	chars['&'] = APOS;
35825a69cdcSmillert 	chars['.'] = PUNCT;
35925a69cdcSmillert 	chars[','] = PUNCT;
36025a69cdcSmillert 	chars[';'] = PUNCT;
36125a69cdcSmillert 	chars['?'] = PUNCT;
36225a69cdcSmillert 	chars[':'] = PUNCT;
36325a69cdcSmillert 	work();
36425a69cdcSmillert 	exit(0);
36525a69cdcSmillert }
36625a69cdcSmillert 
36725a69cdcSmillert int
skeqn(void)36825a69cdcSmillert skeqn(void)
36925a69cdcSmillert {
37025a69cdcSmillert 
37125a69cdcSmillert 	while ((c = getc(infile)) != rdelim) {
37225a69cdcSmillert 		if (c == EOF)
37325a69cdcSmillert 			c = eof();
37425a69cdcSmillert 		else if (c == '"') {
37525a69cdcSmillert 			while ((c = getc(infile)) != '"') {
37625a69cdcSmillert 				if (c == EOF ||
37725a69cdcSmillert 				    (c == '\\' && (c = getc(infile)) == EOF))
37825a69cdcSmillert 					c = eof();
37925a69cdcSmillert 			}
38025a69cdcSmillert 		}
38125a69cdcSmillert 	}
38225a69cdcSmillert 	if (msflag)
38325a69cdcSmillert 		return((c = 'x'));
38425a69cdcSmillert 	return((c = ' '));
38525a69cdcSmillert }
38625a69cdcSmillert 
38725a69cdcSmillert FILE *
opn(char * p)38825a69cdcSmillert opn(char *p)
38925a69cdcSmillert {
39025a69cdcSmillert 	FILE *fd;
39125a69cdcSmillert 
39225a69cdcSmillert 	if ((fd = fopen(p, "r")) == NULL)
39325a69cdcSmillert 		err(1, "fopen %s", p);
39425a69cdcSmillert 
39525a69cdcSmillert 	return(fd);
39625a69cdcSmillert }
39725a69cdcSmillert 
39825a69cdcSmillert int
eof(void)39925a69cdcSmillert eof(void)
40025a69cdcSmillert {
40125a69cdcSmillert 
40225a69cdcSmillert 	if (infile != stdin)
40325a69cdcSmillert 		fclose(infile);
40425a69cdcSmillert 	if (filesp > files)
40525a69cdcSmillert 		infile = *--filesp;
40625a69cdcSmillert 	else if (argc > 0) {
40725a69cdcSmillert 		infile = opn(argv[0]);
40825a69cdcSmillert 		--argc;
40925a69cdcSmillert 		++argv;
41025a69cdcSmillert 	} else
41125a69cdcSmillert 		exit(0);
41225a69cdcSmillert 	return(C);
41325a69cdcSmillert }
41425a69cdcSmillert 
41525a69cdcSmillert void
getfname(void)41625a69cdcSmillert getfname(void)
41725a69cdcSmillert {
41825a69cdcSmillert 	char *p;
41925a69cdcSmillert 	struct chain {
42025a69cdcSmillert 		struct chain *nextp;
42125a69cdcSmillert 		char *datap;
42225a69cdcSmillert 	} *q;
42325a69cdcSmillert 	static struct chain *namechain= NULL;
42425a69cdcSmillert 
42525a69cdcSmillert 	while (C == ' ')
42625a69cdcSmillert 		;	/* nothing */
42725a69cdcSmillert 
42825a69cdcSmillert 	for (p = fname ; p - fname < sizeof(fname) && (*p = c) != '\n' &&
42925a69cdcSmillert 	    c != ' ' && c != '\t' && c != '\\'; ++p)
43025a69cdcSmillert 		C;
43125a69cdcSmillert 	*p = '\0';
43225a69cdcSmillert 	while (c != '\n')
43325a69cdcSmillert 		C;
43425a69cdcSmillert 
43525a69cdcSmillert 	/* see if this name has already been used */
43625a69cdcSmillert 	for (q = namechain ; q; q = q->nextp)
43725a69cdcSmillert 		if (strcmp(fname, q->datap) == 0) {
43825a69cdcSmillert 			fname[0] = '\0';
43925a69cdcSmillert 			return;
44025a69cdcSmillert 		}
44125a69cdcSmillert 
4429a97949aStedu 	q = malloc(sizeof(struct chain));
44325a69cdcSmillert 	if (q == NULL)
444e837b443Stom 		err(1, NULL);
44525a69cdcSmillert 	q->nextp = namechain;
44625a69cdcSmillert 	q->datap = strdup(fname);
44725a69cdcSmillert 	if (q->datap == NULL)
448e837b443Stom 		err(1, NULL);
44925a69cdcSmillert 	namechain = q;
45025a69cdcSmillert }
45125a69cdcSmillert 
45225a69cdcSmillert void
textline(char * str,int constant)45325a69cdcSmillert textline(char *str, int constant)
45425a69cdcSmillert {
45525a69cdcSmillert 
45625a69cdcSmillert 	if (wordflag) {
45725a69cdcSmillert 		msputwords(0);
45825a69cdcSmillert 		return;
45925a69cdcSmillert 	}
46025a69cdcSmillert 	puts(str);
46125a69cdcSmillert }
46225a69cdcSmillert 
46325a69cdcSmillert void
work(void)46425a69cdcSmillert work(void)
46525a69cdcSmillert {
46625a69cdcSmillert 
46725a69cdcSmillert 	for (;;) {
46825a69cdcSmillert 		C;
46925a69cdcSmillert #ifdef FULLDEBUG
47025a69cdcSmillert 		printf("Starting work with `%c'\n", c);
471dc955345Sdanh #endif /* FULLDEBUG */
47225a69cdcSmillert 		if (c == '.' || c == '\'')
47325a69cdcSmillert 			comline();
47425a69cdcSmillert 		else
47525a69cdcSmillert 			regline(textline, TWO);
47625a69cdcSmillert 	}
47725a69cdcSmillert }
47825a69cdcSmillert 
47925a69cdcSmillert void
regline(void (* pfunc)(char *,int),int constant)48025a69cdcSmillert regline(void (*pfunc)(char *, int), int constant)
48125a69cdcSmillert {
48225a69cdcSmillert 
48325a69cdcSmillert 	line[0] = c;
48425a69cdcSmillert 	lp = line;
485*08e9b19aSmillert 	for (;;) {
486*08e9b19aSmillert 		if (lp - line == linesz - 1) {
487*08e9b19aSmillert 			char *newline = reallocarray(line, linesz, 2);
488*08e9b19aSmillert 			if (newline == NULL)
489*08e9b19aSmillert 				err(1, NULL);
490*08e9b19aSmillert 			lp = newline + (lp - line);
491*08e9b19aSmillert 			line = newline;
492*08e9b19aSmillert 			linesz *= 2;
493*08e9b19aSmillert 		}
49425a69cdcSmillert 		if (c == '\\') {
49525a69cdcSmillert 			*lp = ' ';
49625a69cdcSmillert 			backsl();
49725a69cdcSmillert 		}
49825a69cdcSmillert 		if (c == '\n')
49925a69cdcSmillert 			break;
50025a69cdcSmillert 		if (intable && c == 'T') {
50125a69cdcSmillert 			*++lp = C;
50225a69cdcSmillert 			if (c == '{' || c == '}') {
50325a69cdcSmillert 				lp[-1] = ' ';
50425a69cdcSmillert 				*lp = C;
50525a69cdcSmillert 			}
50625a69cdcSmillert 		} else {
50725a69cdcSmillert 			*++lp = C;
50825a69cdcSmillert 		}
50925a69cdcSmillert 	}
51025a69cdcSmillert 	*lp = '\0';
51125a69cdcSmillert 
51225a69cdcSmillert 	if (line[0] != '\0')
51325a69cdcSmillert 		(*pfunc)(line, constant);
51425a69cdcSmillert }
51525a69cdcSmillert 
51625a69cdcSmillert void
macro(void)51725a69cdcSmillert macro(void)
51825a69cdcSmillert {
51925a69cdcSmillert 
52025a69cdcSmillert 	if (msflag) {
52125a69cdcSmillert 		do {
52225a69cdcSmillert 			SKIP;
52325a69cdcSmillert 		} while (C!='.' || C!='.' || C=='.');	/* look for  .. */
52425a69cdcSmillert 		if (c != '\n')
52525a69cdcSmillert 			SKIP;
52625a69cdcSmillert 		return;
52725a69cdcSmillert 	}
52825a69cdcSmillert 	SKIP;
52925a69cdcSmillert 	inmacro = YES;
53025a69cdcSmillert }
53125a69cdcSmillert 
53225a69cdcSmillert void
tbl(void)53325a69cdcSmillert tbl(void)
53425a69cdcSmillert {
53525a69cdcSmillert 
53625a69cdcSmillert 	while (C != '.')
53725a69cdcSmillert 		;	/* nothing */
53825a69cdcSmillert 	SKIP;
53925a69cdcSmillert 	intable = YES;
54025a69cdcSmillert }
54125a69cdcSmillert 
54225a69cdcSmillert void
stbl(void)54325a69cdcSmillert stbl(void)
54425a69cdcSmillert {
54525a69cdcSmillert 
54625a69cdcSmillert 	while (C != '.')
54725a69cdcSmillert 		;	/* nothing */
54825a69cdcSmillert 	SKIP_TO_COM;
54925a69cdcSmillert 	if (c != 'T' || C != 'E') {
55025a69cdcSmillert 		SKIP;
55125a69cdcSmillert 		pc = c;
55225a69cdcSmillert 		while (C != '.' || pc != '\n' || C != 'T' || C != 'E')
55325a69cdcSmillert 			pc = c;
55425a69cdcSmillert 	}
55525a69cdcSmillert }
55625a69cdcSmillert 
55725a69cdcSmillert void
eqn(void)55825a69cdcSmillert eqn(void)
55925a69cdcSmillert {
56025a69cdcSmillert 	int c1, c2;
56125a69cdcSmillert 	int dflg;
56225a69cdcSmillert 	char last;
56325a69cdcSmillert 
56425a69cdcSmillert 	last=0;
56525a69cdcSmillert 	dflg = 1;
56625a69cdcSmillert 	SKIP;
56725a69cdcSmillert 
56825a69cdcSmillert 	for (;;) {
56925a69cdcSmillert 		if (C1 == '.'  || c == '\'') {
57025a69cdcSmillert 			while (C1 == ' ' || c == '\t')
57125a69cdcSmillert 				;
57225a69cdcSmillert 			if (c == 'E' && C1 == 'N') {
57325a69cdcSmillert 				SKIP;
57425a69cdcSmillert 				if (msflag && dflg) {
57525a69cdcSmillert 					putchar('x');
57625a69cdcSmillert 					putchar(' ');
57725a69cdcSmillert 					if (last) {
57825a69cdcSmillert 						putchar(last);
57925a69cdcSmillert 						putchar('\n');
58025a69cdcSmillert 					}
58125a69cdcSmillert 				}
58225a69cdcSmillert 				return;
58325a69cdcSmillert 			}
58425a69cdcSmillert 		} else if (c == 'd') {
58525a69cdcSmillert 			/* look for delim */
58625a69cdcSmillert 			if (C1 == 'e' && C1 == 'l')
58725a69cdcSmillert 				if (C1 == 'i' && C1 == 'm') {
58825a69cdcSmillert 					while (C1 == ' ')
58925a69cdcSmillert 						;	/* nothing */
59025a69cdcSmillert 
59125a69cdcSmillert 					if ((c1 = c) == '\n' ||
59225a69cdcSmillert 					    (c2 = C1) == '\n' ||
59325a69cdcSmillert 					    (c1 == 'o' && c2 == 'f' && C1=='f')) {
59425a69cdcSmillert 						ldelim = NOCHAR;
59525a69cdcSmillert 						rdelim = NOCHAR;
59625a69cdcSmillert 					} else {
59725a69cdcSmillert 						ldelim = c1;
59825a69cdcSmillert 						rdelim = c2;
59925a69cdcSmillert 					}
60025a69cdcSmillert 				}
60125a69cdcSmillert 			dflg = 0;
60225a69cdcSmillert 		}
60325a69cdcSmillert 
60425a69cdcSmillert 		if (c != '\n')
60525a69cdcSmillert 			while (C1 != '\n') {
60625a69cdcSmillert 				if (chars[c] == PUNCT)
60725a69cdcSmillert 					last = c;
60825a69cdcSmillert 				else if (c != ' ')
60925a69cdcSmillert 					last = 0;
61025a69cdcSmillert 			}
61125a69cdcSmillert 	}
61225a69cdcSmillert }
61325a69cdcSmillert 
61425a69cdcSmillert /* skip over a complete backslash construction */
61525a69cdcSmillert void
backsl(void)61625a69cdcSmillert backsl(void)
61725a69cdcSmillert {
61825a69cdcSmillert 	int bdelim;
61925a69cdcSmillert 
62025a69cdcSmillert sw:
62125a69cdcSmillert 	switch (C) {
62225a69cdcSmillert 	case '"':
62325a69cdcSmillert 		SKIP;
62425a69cdcSmillert 		return;
62525a69cdcSmillert 
62625a69cdcSmillert 	case 's':
62725a69cdcSmillert 		if (C == '\\')
62825a69cdcSmillert 			backsl();
62925a69cdcSmillert 		else {
63025a69cdcSmillert 			while (C >= '0' && c <= '9')
63125a69cdcSmillert 				;	/* nothing */
63225a69cdcSmillert 			ungetc(c, infile);
63325a69cdcSmillert 			c = '0';
63425a69cdcSmillert 		}
63525a69cdcSmillert 		--lp;
63625a69cdcSmillert 		return;
63725a69cdcSmillert 
63825a69cdcSmillert 	case 'f':
63925a69cdcSmillert 	case 'n':
64025a69cdcSmillert 	case '*':
64125a69cdcSmillert 		if (C != '(')
64225a69cdcSmillert 			return;
64325a69cdcSmillert 
64425a69cdcSmillert 	case '(':
64525a69cdcSmillert 		if (msflag) {
64625a69cdcSmillert 			if (C == 'e') {
64725a69cdcSmillert 				if (C == 'm') {
64825a69cdcSmillert 					*lp = '-';
64925a69cdcSmillert 					return;
65025a69cdcSmillert 				}
65125a69cdcSmillert 			}
65225a69cdcSmillert 			else if (c != '\n')
65325a69cdcSmillert 				C;
65425a69cdcSmillert 			return;
65525a69cdcSmillert 		}
65625a69cdcSmillert 		if (C != '\n')
65725a69cdcSmillert 			C;
65825a69cdcSmillert 		return;
65925a69cdcSmillert 
66025a69cdcSmillert 	case '$':
66125a69cdcSmillert 		C;	/* discard argument number */
66225a69cdcSmillert 		return;
66325a69cdcSmillert 
66425a69cdcSmillert 	case 'b':
66525a69cdcSmillert 	case 'x':
66625a69cdcSmillert 	case 'v':
66725a69cdcSmillert 	case 'h':
66825a69cdcSmillert 	case 'w':
66925a69cdcSmillert 	case 'o':
67025a69cdcSmillert 	case 'l':
67125a69cdcSmillert 	case 'L':
67225a69cdcSmillert 		if ((bdelim = C) == '\n')
67325a69cdcSmillert 			return;
67425a69cdcSmillert 		while (C != '\n' && c != bdelim)
67525a69cdcSmillert 			if (c == '\\')
67625a69cdcSmillert 				backsl();
67725a69cdcSmillert 		return;
67825a69cdcSmillert 
67925a69cdcSmillert 	case '\\':
68025a69cdcSmillert 		if (inmacro)
68125a69cdcSmillert 			goto sw;
68225a69cdcSmillert 
68325a69cdcSmillert 	default:
68425a69cdcSmillert 		return;
68525a69cdcSmillert 	}
68625a69cdcSmillert }
68725a69cdcSmillert 
68825a69cdcSmillert void
sce(void)68925a69cdcSmillert sce(void)
69025a69cdcSmillert {
69125a69cdcSmillert 	char *ap;
69225a69cdcSmillert 	int n, i;
69325a69cdcSmillert 	char a[10];
69425a69cdcSmillert 
69525a69cdcSmillert 	for (ap = a; C != '\n'; ap++) {
69625a69cdcSmillert 		*ap = c;
69725a69cdcSmillert 		if (ap == &a[9]) {
69825a69cdcSmillert 			SKIP;
69925a69cdcSmillert 			ap = a;
70025a69cdcSmillert 			break;
70125a69cdcSmillert 		}
70225a69cdcSmillert 	}
70325a69cdcSmillert 	if (ap != a)
70425a69cdcSmillert 		n = atoi(a);
70525a69cdcSmillert 	else
70625a69cdcSmillert 		n = 1;
70725a69cdcSmillert 	for (i = 0; i < n;) {
70825a69cdcSmillert 		if (C == '.') {
70925a69cdcSmillert 			if (C == 'c') {
71025a69cdcSmillert 				if (C == 'e') {
71125a69cdcSmillert 					while (C == ' ')
71225a69cdcSmillert 						;	/* nothing */
71325a69cdcSmillert 					if (c == '0') {
71425a69cdcSmillert 						SKIP;
71525a69cdcSmillert 						break;
71625a69cdcSmillert 					} else
71725a69cdcSmillert 						SKIP;
71825a69cdcSmillert 				}
71925a69cdcSmillert 				else
72025a69cdcSmillert 					SKIP;
72125a69cdcSmillert 			} else if (c == 'P' || C == 'P') {
72225a69cdcSmillert 				if (c != '\n')
72325a69cdcSmillert 					SKIP;
72425a69cdcSmillert 				break;
72525a69cdcSmillert 			} else if (c != '\n')
72625a69cdcSmillert 				SKIP;
72725a69cdcSmillert 		} else {
72825a69cdcSmillert 			SKIP;
72925a69cdcSmillert 			i++;
73025a69cdcSmillert 		}
73125a69cdcSmillert 	}
73225a69cdcSmillert }
73325a69cdcSmillert 
73425a69cdcSmillert void
refer(int c1)73525a69cdcSmillert refer(int c1)
73625a69cdcSmillert {
73725a69cdcSmillert 	int c2;
73825a69cdcSmillert 
73925a69cdcSmillert 	if (c1 != '\n')
74025a69cdcSmillert 		SKIP;
74125a69cdcSmillert 
74225a69cdcSmillert 	for (c2 = -1;;) {
74325a69cdcSmillert 		if (C != '.')
74425a69cdcSmillert 			SKIP;
74525a69cdcSmillert 		else {
74625a69cdcSmillert 			if (C != ']')
74725a69cdcSmillert 				SKIP;
74825a69cdcSmillert 			else {
74925a69cdcSmillert 				while (C != '\n')
75025a69cdcSmillert 					c2 = c;
75125a69cdcSmillert 				if (c2 != -1 && chars[c2] == PUNCT)
75225a69cdcSmillert 					putchar(c2);
75325a69cdcSmillert 				return;
75425a69cdcSmillert 			}
75525a69cdcSmillert 		}
75625a69cdcSmillert 	}
75725a69cdcSmillert }
75825a69cdcSmillert 
75925a69cdcSmillert void
inpic(void)76025a69cdcSmillert inpic(void)
76125a69cdcSmillert {
76225a69cdcSmillert 	int c1;
7631e6d1964Smillert 	char *p1, *ep;
76425a69cdcSmillert 
76525a69cdcSmillert 	SKIP;
76625a69cdcSmillert 	p1 = line;
7671e6d1964Smillert 	ep = line + sizeof(line) - 1;
76825a69cdcSmillert 	c = '\n';
76925a69cdcSmillert 	for (;;) {
77025a69cdcSmillert 		c1 = c;
77125a69cdcSmillert 		if (C == '.' && c1 == '\n') {
77225a69cdcSmillert 			if (C != 'P') {
77325a69cdcSmillert 				if (c == '\n')
77425a69cdcSmillert 					continue;
77525a69cdcSmillert 				else {
77625a69cdcSmillert 					SKIP;
77725a69cdcSmillert 					c = '\n';
77825a69cdcSmillert 					continue;
77925a69cdcSmillert 				}
78025a69cdcSmillert 			}
78125a69cdcSmillert 			if (C != 'E') {
78225a69cdcSmillert 				if (c == '\n')
78325a69cdcSmillert 					continue;
78425a69cdcSmillert 				else {
78525a69cdcSmillert 					SKIP;
78625a69cdcSmillert 					c = '\n';
78725a69cdcSmillert 					continue;
78825a69cdcSmillert 				}
78925a69cdcSmillert 			}
79025a69cdcSmillert 			SKIP;
79125a69cdcSmillert 			return;
79225a69cdcSmillert 		}
79325a69cdcSmillert 		else if (c == '\"') {
79425a69cdcSmillert 			while (C != '\"') {
79525a69cdcSmillert 				if (c == '\\') {
79625a69cdcSmillert 					if (C == '\"')
79725a69cdcSmillert 						continue;
79825a69cdcSmillert 					ungetc(c, infile);
79925a69cdcSmillert 					backsl();
8001e6d1964Smillert 				} else if (p1 + 1 >= ep) {
8011e6d1964Smillert 					errx(1, ".PS length exceeds limit");
8021e6d1964Smillert 				} else {
80325a69cdcSmillert 					*p1++ = c;
80425a69cdcSmillert 				}
8051e6d1964Smillert 			}
80625a69cdcSmillert 			*p1++ = ' ';
80725a69cdcSmillert 		}
80825a69cdcSmillert 		else if (c == '\n' && p1 != line) {
80925a69cdcSmillert 			*p1 = '\0';
81025a69cdcSmillert 			if (wordflag)
81125a69cdcSmillert 				msputwords(NO);
81225a69cdcSmillert 			else {
81325a69cdcSmillert 				puts(line);
81425a69cdcSmillert 				putchar('\n');
81525a69cdcSmillert 			}
81625a69cdcSmillert 			p1 = line;
81725a69cdcSmillert 		}
81825a69cdcSmillert 	}
81925a69cdcSmillert }
82025a69cdcSmillert 
82125a69cdcSmillert #ifdef DEBUG
82225a69cdcSmillert int
_C1(void)82325a69cdcSmillert _C1(void)
82425a69cdcSmillert {
82525a69cdcSmillert 
82625a69cdcSmillert 	return(C1get);
82725a69cdcSmillert }
82825a69cdcSmillert 
82925a69cdcSmillert int
_C(void)83025a69cdcSmillert _C(void)
83125a69cdcSmillert {
83225a69cdcSmillert 
83325a69cdcSmillert 	return(Cget);
83425a69cdcSmillert }
835dc955345Sdanh #endif /* DEBUG */
83625a69cdcSmillert 
83725a69cdcSmillert /*
83825a69cdcSmillert  *	Put out a macro line, using ms and mm conventions.
83925a69cdcSmillert  */
84025a69cdcSmillert void
msputmac(char * s,int constant)84125a69cdcSmillert msputmac(char *s, int constant)
84225a69cdcSmillert {
84325a69cdcSmillert 	char *t;
84425a69cdcSmillert 	int found;
84525a69cdcSmillert 	int last;
84625a69cdcSmillert 
84725a69cdcSmillert 	last = 0;
84825a69cdcSmillert 	found = 0;
84925a69cdcSmillert 	if (wordflag) {
85025a69cdcSmillert 		msputwords(YES);
85125a69cdcSmillert 		return;
85225a69cdcSmillert 	}
85325a69cdcSmillert 	while (*s) {
85425a69cdcSmillert 		while (*s == ' ' || *s == '\t')
85525a69cdcSmillert 			putchar(*s++);
85625a69cdcSmillert 		for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
85725a69cdcSmillert 			;	/* nothing */
85825a69cdcSmillert 		if (*s == '\"')
85925a69cdcSmillert 			s++;
86025a69cdcSmillert 		if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
86125a69cdcSmillert 		    chars[(unsigned char)s[1]] == LETTER) {
86225a69cdcSmillert 			while (s < t)
86325a69cdcSmillert 				if (*s == '\"')
86425a69cdcSmillert 					s++;
86525a69cdcSmillert 				else
86625a69cdcSmillert 					putchar(*s++);
86725a69cdcSmillert 			last = *(t-1);
86825a69cdcSmillert 			found++;
86925a69cdcSmillert 		} else if (found && chars[(unsigned char)s[0]] == PUNCT &&
87025a69cdcSmillert 		    s[1] == '\0') {
87125a69cdcSmillert 			putchar(*s++);
87225a69cdcSmillert 		} else {
87325a69cdcSmillert 			last = *(t - 1);
87425a69cdcSmillert 			s = t;
87525a69cdcSmillert 		}
87625a69cdcSmillert 	}
87725a69cdcSmillert 	putchar('\n');
87825a69cdcSmillert 	if (msflag && chars[last] == PUNCT) {
87925a69cdcSmillert 		putchar(last);
88025a69cdcSmillert 		putchar('\n');
88125a69cdcSmillert 	}
88225a69cdcSmillert }
88325a69cdcSmillert 
88425a69cdcSmillert /*
88525a69cdcSmillert  *	put out words (for the -w option) with ms and mm conventions
88625a69cdcSmillert  */
88725a69cdcSmillert void
msputwords(int macline)88825a69cdcSmillert msputwords(int macline)
88925a69cdcSmillert {
89025a69cdcSmillert 	char *p, *p1;
89125a69cdcSmillert 	int i, nlet;
89225a69cdcSmillert 
89325a69cdcSmillert 	for (p1 = line;;) {
89425a69cdcSmillert 		/*
89525a69cdcSmillert 		 *	skip initial specials ampersands and apostrophes
89625a69cdcSmillert 		 */
89725a69cdcSmillert 		while (chars[(unsigned char)*p1] < DIGIT)
89825a69cdcSmillert 			if (*p1++ == '\0')
89925a69cdcSmillert 				return;
90025a69cdcSmillert 		nlet = 0;
90125a69cdcSmillert 		for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
90225a69cdcSmillert 			if (i == LETTER)
90325a69cdcSmillert 				++nlet;
90425a69cdcSmillert 
90525a69cdcSmillert 		if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
90625a69cdcSmillert 			/*
90725a69cdcSmillert 			 *	delete trailing ampersands and apostrophes
90825a69cdcSmillert 			 */
90925a69cdcSmillert 			while ((i = chars[(unsigned char)p[-1]]) == PUNCT ||
91025a69cdcSmillert 			    i == APOS )
91125a69cdcSmillert 				--p;
91225a69cdcSmillert 			while (p1 < p)
91325a69cdcSmillert 				putchar(*p1++);
91425a69cdcSmillert 			putchar('\n');
91525a69cdcSmillert 		} else {
91625a69cdcSmillert 			p1 = p;
91725a69cdcSmillert 		}
91825a69cdcSmillert 	}
91925a69cdcSmillert }
92025a69cdcSmillert 
92125a69cdcSmillert /*
92225a69cdcSmillert  *	put out a macro using the me conventions
92325a69cdcSmillert  */
92425a69cdcSmillert #define SKIPBLANK(cp)	while (*cp == ' ' || *cp == '\t') { cp++; }
92525a69cdcSmillert #define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
92625a69cdcSmillert 
92725a69cdcSmillert void
meputmac(char * cp,int constant)92825a69cdcSmillert meputmac(char *cp, int constant)
92925a69cdcSmillert {
93025a69cdcSmillert 	char	*np;
93125a69cdcSmillert 	int	found;
93225a69cdcSmillert 	int	argno;
93325a69cdcSmillert 	int	last;
93425a69cdcSmillert 	int	inquote;
93525a69cdcSmillert 
93625a69cdcSmillert 	last = 0;
93725a69cdcSmillert 	found = 0;
93825a69cdcSmillert 	if (wordflag) {
93925a69cdcSmillert 		meputwords(YES);
94025a69cdcSmillert 		return;
94125a69cdcSmillert 	}
94225a69cdcSmillert 	for (argno = 0; *cp; argno++) {
94325a69cdcSmillert 		SKIPBLANK(cp);
94425a69cdcSmillert 		inquote = (*cp == '"');
94525a69cdcSmillert 		if (inquote)
94625a69cdcSmillert 			cp++;
94725a69cdcSmillert 		for (np = cp; *np; np++) {
94825a69cdcSmillert 			switch (*np) {
94925a69cdcSmillert 			case '\n':
95025a69cdcSmillert 			case '\0':
95125a69cdcSmillert 				break;
95225a69cdcSmillert 
95325a69cdcSmillert 			case '\t':
95425a69cdcSmillert 			case ' ':
95525a69cdcSmillert 				if (inquote)
95625a69cdcSmillert 					continue;
95725a69cdcSmillert 				else
95825a69cdcSmillert 					goto endarg;
95925a69cdcSmillert 
96025a69cdcSmillert 			case '"':
96125a69cdcSmillert 				if (inquote && np[1] == '"') {
962f09d3110Smillert 					memmove(np, np + 1, strlen(np));
96325a69cdcSmillert 					np++;
96425a69cdcSmillert 					continue;
96525a69cdcSmillert 				} else {
96625a69cdcSmillert 					*np = ' ';	/* bye bye " */
96725a69cdcSmillert 					goto endarg;
96825a69cdcSmillert 				}
96925a69cdcSmillert 
97025a69cdcSmillert 			default:
97125a69cdcSmillert 				continue;
97225a69cdcSmillert 			}
97325a69cdcSmillert 		}
97425a69cdcSmillert 		endarg: ;
97525a69cdcSmillert 		/*
97625a69cdcSmillert 		 *	cp points at the first char in the arg
97725a69cdcSmillert 		 *	np points one beyond the last char in the arg
97825a69cdcSmillert 		 */
97925a69cdcSmillert 		if ((argconcat == 0) || (argconcat != argno))
98025a69cdcSmillert 			putchar(' ');
98125a69cdcSmillert #ifdef FULLDEBUG
98225a69cdcSmillert 		{
98325a69cdcSmillert 			char	*p;
98425a69cdcSmillert 			printf("[%d,%d: ", argno, np - cp);
98525a69cdcSmillert 			for (p = cp; p < np; p++) {
98625a69cdcSmillert 				putchar(*p);
98725a69cdcSmillert 			}
98825a69cdcSmillert 			printf("]");
98925a69cdcSmillert 		}
990dc955345Sdanh #endif /* FULLDEBUG */
99125a69cdcSmillert 		/*
99225a69cdcSmillert 		 *	Determine if the argument merits being printed
99325a69cdcSmillert 		 *
99425a69cdcSmillert 		 *	constant is the cut off point below which something
99525a69cdcSmillert 		 *	is not a word.
99625a69cdcSmillert 		 */
99725a69cdcSmillert 		if (((np - cp) > constant) &&
99825a69cdcSmillert 		    (inquote || (chars[(unsigned char)cp[0]] == LETTER))) {
99995ca2293Smiod 			for (; cp < np; cp++)
100025a69cdcSmillert 				putchar(*cp);
100125a69cdcSmillert 			last = np[-1];
100225a69cdcSmillert 			found++;
100325a69cdcSmillert 		} else if (found && (np - cp == 1) &&
100425a69cdcSmillert 		    chars[(unsigned char)*cp] == PUNCT) {
100525a69cdcSmillert 			putchar(*cp);
100625a69cdcSmillert 		} else {
100725a69cdcSmillert 			last = np[-1];
100825a69cdcSmillert 		}
100925a69cdcSmillert 		cp = np;
101025a69cdcSmillert 	}
101125a69cdcSmillert 	if (msflag && chars[last] == PUNCT)
101225a69cdcSmillert 		putchar(last);
101325a69cdcSmillert 	putchar('\n');
101425a69cdcSmillert }
101525a69cdcSmillert 
101625a69cdcSmillert /*
101725a69cdcSmillert  *	put out words (for the -w option) with ms and mm conventions
101825a69cdcSmillert  */
101925a69cdcSmillert void
meputwords(int macline)102025a69cdcSmillert meputwords(int macline)
102125a69cdcSmillert {
102225a69cdcSmillert 
102325a69cdcSmillert 	msputwords(macline);
102425a69cdcSmillert }
102525a69cdcSmillert 
102625a69cdcSmillert /*
102725a69cdcSmillert  *
102825a69cdcSmillert  *	Skip over a nested set of macros
102925a69cdcSmillert  *
103025a69cdcSmillert  *	Possible arguments to noblock are:
103125a69cdcSmillert  *
103225a69cdcSmillert  *	fi	end of unfilled text
103325a69cdcSmillert  *	PE	pic ending
103425a69cdcSmillert  *	DE	display ending
103525a69cdcSmillert  *
103625a69cdcSmillert  *	for ms and mm only:
103725a69cdcSmillert  *		KE	keep ending
103825a69cdcSmillert  *
103925a69cdcSmillert  *		NE	undocumented match to NS (for mm?)
104025a69cdcSmillert  *		LE	mm only: matches RL or *L (for lists)
104125a69cdcSmillert  *
104225a69cdcSmillert  *	for me:
104325a69cdcSmillert  *		([lqbzcdf]
104425a69cdcSmillert  */
104525a69cdcSmillert void
noblock(char a1,char a2)104625a69cdcSmillert noblock(char a1, char a2)
104725a69cdcSmillert {
104825a69cdcSmillert 	int c1,c2;
104925a69cdcSmillert 	int eqnf;
105025a69cdcSmillert 	int lct;
105125a69cdcSmillert 
105225a69cdcSmillert 	lct = 0;
105325a69cdcSmillert 	eqnf = 1;
105425a69cdcSmillert 	SKIP;
105525a69cdcSmillert 	for (;;) {
105625a69cdcSmillert 		while (C != '.')
105725a69cdcSmillert 			if (c == '\n')
105825a69cdcSmillert 				continue;
105925a69cdcSmillert 			else
106025a69cdcSmillert 				SKIP;
106125a69cdcSmillert 		if ((c1 = C) == '\n')
106225a69cdcSmillert 			continue;
106325a69cdcSmillert 		if ((c2 = C) == '\n')
106425a69cdcSmillert 			continue;
106525a69cdcSmillert 		if (c1 == a1 && c2 == a2) {
106625a69cdcSmillert 			SKIP;
106725a69cdcSmillert 			if (lct != 0) {
106825a69cdcSmillert 				lct--;
106925a69cdcSmillert 				continue;
107025a69cdcSmillert 			}
107125a69cdcSmillert 			if (eqnf)
107225a69cdcSmillert 				putchar('.');
107325a69cdcSmillert 			putchar('\n');
107425a69cdcSmillert 			return;
107525a69cdcSmillert 		} else if (a1 == 'L' && c2 == 'L') {
107625a69cdcSmillert 			lct++;
107725a69cdcSmillert 			SKIP;
107825a69cdcSmillert 		}
107925a69cdcSmillert 		/*
108025a69cdcSmillert 		 *	equations (EQ) nested within a display
108125a69cdcSmillert 		 */
108225a69cdcSmillert 		else if (c1 == 'E' && c2 == 'Q') {
108325a69cdcSmillert 			if ((mac == ME && a1 == ')')
108425a69cdcSmillert 			    || (mac != ME && a1 == 'D')) {
108525a69cdcSmillert 				eqn();
108625a69cdcSmillert 				eqnf=0;
108725a69cdcSmillert 			}
108825a69cdcSmillert 		}
108925a69cdcSmillert 		/*
109025a69cdcSmillert 		 *	turning on filling is done by the paragraphing
109125a69cdcSmillert 		 *	macros
109225a69cdcSmillert 		 */
109325a69cdcSmillert 		else if (a1 == 'f') {	/* .fi */
109425a69cdcSmillert 			if  ((mac == ME && (c2 == 'h' || c2 == 'p'))
109525a69cdcSmillert 			    || (mac != ME && (c1 == 'P' || c2 == 'P'))) {
109625a69cdcSmillert 				SKIP;
109725a69cdcSmillert 				return;
109825a69cdcSmillert 			}
109925a69cdcSmillert 		} else {
110025a69cdcSmillert 			SKIP;
110125a69cdcSmillert 		}
110225a69cdcSmillert 	}
110325a69cdcSmillert }
110425a69cdcSmillert 
110525a69cdcSmillert int
EQ(void)110625a69cdcSmillert EQ(void)
110725a69cdcSmillert {
110825a69cdcSmillert 
110925a69cdcSmillert 	eqn();
111025a69cdcSmillert 	return(0);
111125a69cdcSmillert }
111225a69cdcSmillert 
111325a69cdcSmillert int
domacro(void)111425a69cdcSmillert domacro(void)
111525a69cdcSmillert {
111625a69cdcSmillert 
111725a69cdcSmillert 	macro();
111825a69cdcSmillert 	return(0);
111925a69cdcSmillert }
112025a69cdcSmillert 
112125a69cdcSmillert int
PS(void)112225a69cdcSmillert PS(void)
112325a69cdcSmillert {
112425a69cdcSmillert 
112525a69cdcSmillert 	for (C; c == ' ' || c == '\t'; C)
112625a69cdcSmillert 		;	/* nothing */
112725a69cdcSmillert 
112825a69cdcSmillert 	if (c == '<') {		/* ".PS < file" -- don't expect a .PE */
112925a69cdcSmillert 		SKIP;
113025a69cdcSmillert 		return(0);
113125a69cdcSmillert 	}
113225a69cdcSmillert 	if (!msflag)
113325a69cdcSmillert 		inpic();
113425a69cdcSmillert 	else
113525a69cdcSmillert 		noblock('P', 'E');
113625a69cdcSmillert 	return(0);
113725a69cdcSmillert }
113825a69cdcSmillert 
113925a69cdcSmillert int
skip(void)114025a69cdcSmillert skip(void)
114125a69cdcSmillert {
114225a69cdcSmillert 
114325a69cdcSmillert 	SKIP;
114425a69cdcSmillert 	return(0);
114525a69cdcSmillert }
114625a69cdcSmillert 
114725a69cdcSmillert int
intbl(void)114825a69cdcSmillert intbl(void)
114925a69cdcSmillert {
115025a69cdcSmillert 
115125a69cdcSmillert 	if (msflag)
115225a69cdcSmillert 		stbl();
115325a69cdcSmillert 	else
115425a69cdcSmillert 		tbl();
115525a69cdcSmillert 	return(0);
115625a69cdcSmillert }
115725a69cdcSmillert 
115825a69cdcSmillert int
outtbl(void)115925a69cdcSmillert outtbl(void)
116025a69cdcSmillert {
116125a69cdcSmillert 
116225a69cdcSmillert 	intable = NO;
116325a69cdcSmillert 	return(0);
116425a69cdcSmillert }
116525a69cdcSmillert 
116625a69cdcSmillert int
so(void)116725a69cdcSmillert so(void)
116825a69cdcSmillert {
116925a69cdcSmillert 
117025a69cdcSmillert 	if (!iflag) {
117125a69cdcSmillert 		getfname();
117225a69cdcSmillert 		if (fname[0]) {
117325a69cdcSmillert 			if (++filesp - &files[0] > MAXFILES)
117425a69cdcSmillert 				err(1, "too many nested files (max %d)",
117525a69cdcSmillert 				    MAXFILES);
117625a69cdcSmillert 			infile = *filesp = opn(fname);
117725a69cdcSmillert 		}
117825a69cdcSmillert 	}
117925a69cdcSmillert 	return(0);
118025a69cdcSmillert }
118125a69cdcSmillert 
118225a69cdcSmillert int
nx(void)118325a69cdcSmillert nx(void)
118425a69cdcSmillert {
118525a69cdcSmillert 
118625a69cdcSmillert 	if (!iflag) {
118725a69cdcSmillert 		getfname();
118825a69cdcSmillert 		if (fname[0] == '\0')
118925a69cdcSmillert 			exit(0);
119025a69cdcSmillert 		if (infile != stdin)
119125a69cdcSmillert 			fclose(infile);
119225a69cdcSmillert 		infile = *filesp = opn(fname);
119325a69cdcSmillert 	}
119425a69cdcSmillert 	return(0);
119525a69cdcSmillert }
119625a69cdcSmillert 
119725a69cdcSmillert int
skiptocom(void)119825a69cdcSmillert skiptocom(void)
119925a69cdcSmillert {
120025a69cdcSmillert 
120125a69cdcSmillert 	SKIP_TO_COM;
120225a69cdcSmillert 	return(COMX);
120325a69cdcSmillert }
120425a69cdcSmillert 
120525a69cdcSmillert int
PP(pacmac c12)120625a69cdcSmillert PP(pacmac c12)
120725a69cdcSmillert {
120825a69cdcSmillert 	int c1, c2;
120925a69cdcSmillert 
121025a69cdcSmillert 	frommac(c12, c1, c2);
121125a69cdcSmillert 	printf(".%c%c", c1, c2);
121225a69cdcSmillert 	while (C != '\n')
121325a69cdcSmillert 		putchar(c);
121425a69cdcSmillert 	putchar('\n');
121525a69cdcSmillert 	return(0);
121625a69cdcSmillert }
121725a69cdcSmillert 
121825a69cdcSmillert int
AU(void)121925a69cdcSmillert AU(void)
122025a69cdcSmillert {
122125a69cdcSmillert 
122225a69cdcSmillert 	if (mac == MM)
122325a69cdcSmillert 		return(0);
122425a69cdcSmillert 	SKIP_TO_COM;
122525a69cdcSmillert 	return(COMX);
122625a69cdcSmillert }
122725a69cdcSmillert 
122825a69cdcSmillert int
SH(pacmac c12)122925a69cdcSmillert SH(pacmac c12)
123025a69cdcSmillert {
123125a69cdcSmillert 	int c1, c2;
123225a69cdcSmillert 
123325a69cdcSmillert 	frommac(c12, c1, c2);
123425a69cdcSmillert 
123525a69cdcSmillert 	if (parag) {
123625a69cdcSmillert 		printf(".%c%c", c1, c2);
123725a69cdcSmillert 		while (C != '\n')
123825a69cdcSmillert 			putchar(c);
123925a69cdcSmillert 		putchar(c);
124025a69cdcSmillert 		putchar('!');
124125a69cdcSmillert 		for (;;) {
124225a69cdcSmillert 			while (C != '\n')
124325a69cdcSmillert 				putchar(c);
124425a69cdcSmillert 			putchar('\n');
124525a69cdcSmillert 			if (C == '.')
124625a69cdcSmillert 				return(COM);
124725a69cdcSmillert 			putchar('!');
124825a69cdcSmillert 			putchar(c);
124925a69cdcSmillert 		}
125025a69cdcSmillert 		/*NOTREACHED*/
125125a69cdcSmillert 	} else {
125225a69cdcSmillert 		SKIP_TO_COM;
125325a69cdcSmillert 		return(COMX);
125425a69cdcSmillert 	}
125525a69cdcSmillert }
125625a69cdcSmillert 
125725a69cdcSmillert int
UX(void)125825a69cdcSmillert UX(void)
125925a69cdcSmillert {
126025a69cdcSmillert 
126125a69cdcSmillert 	if (wordflag)
126225a69cdcSmillert 		printf("UNIX\n");
126325a69cdcSmillert 	else
126425a69cdcSmillert 		printf("UNIX ");
126525a69cdcSmillert 	return(0);
126625a69cdcSmillert }
126725a69cdcSmillert 
126825a69cdcSmillert int
MMHU(pacmac c12)126925a69cdcSmillert MMHU(pacmac c12)
127025a69cdcSmillert {
127125a69cdcSmillert 	int c1, c2;
127225a69cdcSmillert 
127325a69cdcSmillert 	frommac(c12, c1, c2);
127425a69cdcSmillert 	if (parag) {
127525a69cdcSmillert 		printf(".%c%c", c1, c2);
127625a69cdcSmillert 		while (C != '\n')
127725a69cdcSmillert 			putchar(c);
127825a69cdcSmillert 		putchar('\n');
127925a69cdcSmillert 	} else {
128025a69cdcSmillert 		SKIP;
128125a69cdcSmillert 	}
128225a69cdcSmillert 	return(0);
128325a69cdcSmillert }
128425a69cdcSmillert 
128525a69cdcSmillert int
mesnblock(pacmac c12)128625a69cdcSmillert mesnblock(pacmac c12)
128725a69cdcSmillert {
128825a69cdcSmillert 	int c1, c2;
128925a69cdcSmillert 
129025a69cdcSmillert 	frommac(c12, c1, c2);
129125a69cdcSmillert 	noblock(')', c2);
129225a69cdcSmillert 	return(0);
129325a69cdcSmillert }
129425a69cdcSmillert 
129525a69cdcSmillert int
mssnblock(pacmac c12)129625a69cdcSmillert mssnblock(pacmac c12)
129725a69cdcSmillert {
129825a69cdcSmillert 	int c1, c2;
129925a69cdcSmillert 
130025a69cdcSmillert 	frommac(c12, c1, c2);
130125a69cdcSmillert 	noblock(c1, 'E');
130225a69cdcSmillert 	return(0);
130325a69cdcSmillert }
130425a69cdcSmillert 
130525a69cdcSmillert int
nf(void)130625a69cdcSmillert nf(void)
130725a69cdcSmillert {
130825a69cdcSmillert 
130925a69cdcSmillert 	noblock('f', 'i');
131025a69cdcSmillert 	return(0);
131125a69cdcSmillert }
131225a69cdcSmillert 
131325a69cdcSmillert int
ce(void)131425a69cdcSmillert ce(void)
131525a69cdcSmillert {
131625a69cdcSmillert 
131725a69cdcSmillert 	sce();
131825a69cdcSmillert 	return(0);
131925a69cdcSmillert }
132025a69cdcSmillert 
132125a69cdcSmillert int
meip(pacmac c12)132225a69cdcSmillert meip(pacmac c12)
132325a69cdcSmillert {
132425a69cdcSmillert 
132525a69cdcSmillert 	if (parag)
132625a69cdcSmillert 		mepp(c12);
132725a69cdcSmillert 	else if (wordflag)	/* save the tag */
132825a69cdcSmillert 		regline(meputmac, ONE);
132925a69cdcSmillert 	else
133025a69cdcSmillert 		SKIP;
133125a69cdcSmillert 	return(0);
133225a69cdcSmillert }
133325a69cdcSmillert 
133425a69cdcSmillert /*
133525a69cdcSmillert  *	only called for -me .pp or .sh, when parag is on
133625a69cdcSmillert  */
133725a69cdcSmillert int
mepp(pacmac c12)133825a69cdcSmillert mepp(pacmac c12)
133925a69cdcSmillert {
134025a69cdcSmillert 
134125a69cdcSmillert 	PP(c12);		/* eats the line */
134225a69cdcSmillert 	return(0);
134325a69cdcSmillert }
134425a69cdcSmillert 
134525a69cdcSmillert /*
134625a69cdcSmillert  *	Start of a section heading; output the section name if doing words
134725a69cdcSmillert  */
134825a69cdcSmillert int
mesh(pacmac c12)134925a69cdcSmillert mesh(pacmac c12)
135025a69cdcSmillert {
135125a69cdcSmillert 
135225a69cdcSmillert 	if (parag)
135325a69cdcSmillert 		mepp(c12);
135425a69cdcSmillert 	else if (wordflag)
135525a69cdcSmillert 		defcomline(c12);
135625a69cdcSmillert 	else
135725a69cdcSmillert 		SKIP;
135825a69cdcSmillert 	return(0);
135925a69cdcSmillert }
136025a69cdcSmillert 
136125a69cdcSmillert /*
136225a69cdcSmillert  *	process a font setting
136325a69cdcSmillert  */
136425a69cdcSmillert int
mefont(pacmac c12)136525a69cdcSmillert mefont(pacmac c12)
136625a69cdcSmillert {
136725a69cdcSmillert 
136825a69cdcSmillert 	argconcat = 1;
136925a69cdcSmillert 	defcomline(c12);
137025a69cdcSmillert 	argconcat = 0;
137125a69cdcSmillert 	return(0);
137225a69cdcSmillert }
137325a69cdcSmillert 
137425a69cdcSmillert int
manfont(pacmac c12)137525a69cdcSmillert manfont(pacmac c12)
137625a69cdcSmillert {
137725a69cdcSmillert 
137825a69cdcSmillert 	return(mefont(c12));
137925a69cdcSmillert }
138025a69cdcSmillert 
138125a69cdcSmillert int
manpp(pacmac c12)138225a69cdcSmillert manpp(pacmac c12)
138325a69cdcSmillert {
138425a69cdcSmillert 
138525a69cdcSmillert 	return(mepp(c12));
138625a69cdcSmillert }
138725a69cdcSmillert 
138825a69cdcSmillert void
defcomline(pacmac c12)138925a69cdcSmillert defcomline(pacmac c12)
139025a69cdcSmillert {
139125a69cdcSmillert 	int c1, c2;
139225a69cdcSmillert 
139325a69cdcSmillert 	frommac(c12, c1, c2);
139425a69cdcSmillert 	if (msflag && mac == MM && c2 == 'L') {
139525a69cdcSmillert 		if (disp || c1 == 'R') {
139625a69cdcSmillert 			noblock('L', 'E');
139725a69cdcSmillert 		} else {
139825a69cdcSmillert 			SKIP;
139925a69cdcSmillert 			putchar('.');
140025a69cdcSmillert 		}
140125a69cdcSmillert 	}
140225a69cdcSmillert 	else if (c1 == '.' && c2 == '.') {
140325a69cdcSmillert 		if (msflag) {
140425a69cdcSmillert 			SKIP;
140525a69cdcSmillert 			return;
140625a69cdcSmillert 		}
140725a69cdcSmillert 		while (C == '.')
140825a69cdcSmillert 			/*VOID*/;
140925a69cdcSmillert 	}
141025a69cdcSmillert 	++inmacro;
141125a69cdcSmillert 	/*
141225a69cdcSmillert 	 *	Process the arguments to the macro
141325a69cdcSmillert 	 */
141425a69cdcSmillert 	switch (mac) {
141525a69cdcSmillert 	default:
141625a69cdcSmillert 	case MM:
141725a69cdcSmillert 	case MS:
141825a69cdcSmillert 		if (c1 <= 'Z' && msflag)
141925a69cdcSmillert 			regline(msputmac, ONE);
142025a69cdcSmillert 		else
142125a69cdcSmillert 			regline(msputmac, TWO);
142225a69cdcSmillert 		break;
142325a69cdcSmillert 	case ME:
142425a69cdcSmillert 		regline(meputmac, ONE);
142525a69cdcSmillert 		break;
142625a69cdcSmillert 	}
142725a69cdcSmillert 	--inmacro;
142825a69cdcSmillert }
142925a69cdcSmillert 
143025a69cdcSmillert void
comline(void)143125a69cdcSmillert comline(void)
143225a69cdcSmillert {
143325a69cdcSmillert 	int	c1;
143425a69cdcSmillert 	int	c2;
143525a69cdcSmillert 	pacmac	c12;
143625a69cdcSmillert 	int	mid;
143725a69cdcSmillert 	int	lb, ub;
143825a69cdcSmillert 	int	hit;
143925a69cdcSmillert 	static	int	tabsize = 0;
1440c9899b11Skrw 	static	struct	mactab	*mactab = NULL;
144125a69cdcSmillert 	struct	mactab	*mp;
144225a69cdcSmillert 
144325a69cdcSmillert 	if (mactab == 0)
144425a69cdcSmillert 		 buildtab(&mactab, &tabsize);
144525a69cdcSmillert com:
144625a69cdcSmillert 	while (C == ' ' || c == '\t')
144725a69cdcSmillert 		;
144825a69cdcSmillert comx:
144925a69cdcSmillert 	if ((c1 = c) == '\n')
145025a69cdcSmillert 		return;
145125a69cdcSmillert 	c2 = C;
145225a69cdcSmillert 	if (c1 == '.' && c2 != '.')
145325a69cdcSmillert 		inmacro = NO;
145425a69cdcSmillert 	if (msflag && c1 == '[') {
145525a69cdcSmillert 		refer(c2);
145625a69cdcSmillert 		return;
145725a69cdcSmillert 	}
145825a69cdcSmillert 	if (parag && mac==MM && c1 == 'P' && c2 == '\n') {
145925a69cdcSmillert 		printf(".P\n");
146025a69cdcSmillert 		return;
146125a69cdcSmillert 	}
146225a69cdcSmillert 	if (c2 == '\n')
146325a69cdcSmillert 		return;
146425a69cdcSmillert 	/*
146525a69cdcSmillert 	 *	Single letter macro
146625a69cdcSmillert 	 */
146725a69cdcSmillert 	if (mac == ME && (c2 == ' ' || c2 == '\t') )
146825a69cdcSmillert 		c2 = ' ';
146925a69cdcSmillert 	c12 = tomac(c1, c2);
147025a69cdcSmillert 	/*
147125a69cdcSmillert 	 *	binary search through the table of macros
147225a69cdcSmillert 	 */
147325a69cdcSmillert 	lb = 0;
147425a69cdcSmillert 	ub = tabsize - 1;
147525a69cdcSmillert 	while (lb <= ub) {
147625a69cdcSmillert 		mid = (ub + lb) / 2;
147725a69cdcSmillert 		mp = &mactab[mid];
147825a69cdcSmillert 		if (mp->macname < c12)
147925a69cdcSmillert 			lb = mid + 1;
148025a69cdcSmillert 		else if (mp->macname > c12)
148125a69cdcSmillert 			ub = mid - 1;
148225a69cdcSmillert 		else {
148325a69cdcSmillert 			hit = 1;
148425a69cdcSmillert #ifdef FULLDEBUG
148525a69cdcSmillert 			printf("preliminary hit macro %c%c ", c1, c2);
1486dc955345Sdanh #endif /* FULLDEBUG */
148725a69cdcSmillert 			switch (mp->condition) {
148825a69cdcSmillert 			case NONE:
148925a69cdcSmillert 				hit = YES;
149025a69cdcSmillert 				break;
149125a69cdcSmillert 			case FNEST:
149225a69cdcSmillert 				hit = (filesp == files);
149325a69cdcSmillert 				break;
149425a69cdcSmillert 			case NOMAC:
149525a69cdcSmillert 				hit = !inmacro;
149625a69cdcSmillert 				break;
149725a69cdcSmillert 			case MAC:
149825a69cdcSmillert 				hit = inmacro;
149925a69cdcSmillert 				break;
150025a69cdcSmillert 			case PARAG:
150125a69cdcSmillert 				hit = parag;
150225a69cdcSmillert 				break;
150325a69cdcSmillert 			case NBLK:
150425a69cdcSmillert 				hit = !keepblock;
150525a69cdcSmillert 				break;
150625a69cdcSmillert 			default:
150725a69cdcSmillert 				hit = 0;
150825a69cdcSmillert 			}
150925a69cdcSmillert 
151025a69cdcSmillert 			if (hit) {
151125a69cdcSmillert #ifdef FULLDEBUG
151225a69cdcSmillert 				printf("MATCH\n");
1513dc955345Sdanh #endif /* FULLDEBUG */
151425a69cdcSmillert 				switch ((*(mp->func))(c12)) {
151525a69cdcSmillert 				default:
151625a69cdcSmillert 					return;
151725a69cdcSmillert 				case COMX:
151825a69cdcSmillert 					goto comx;
151925a69cdcSmillert 				case COM:
152025a69cdcSmillert 					goto com;
152125a69cdcSmillert 				}
152225a69cdcSmillert 			}
152325a69cdcSmillert #ifdef FULLDEBUG
152425a69cdcSmillert 			printf("FAIL\n");
1525dc955345Sdanh #endif /* FULLDEBUG */
152625a69cdcSmillert 			break;
152725a69cdcSmillert 		}
152825a69cdcSmillert 	}
152925a69cdcSmillert 	defcomline(c12);
153025a69cdcSmillert }
153125a69cdcSmillert 
153225a69cdcSmillert int
macsort(const void * p1,const void * p2)153325a69cdcSmillert macsort(const void *p1, const void *p2)
153425a69cdcSmillert {
153525a69cdcSmillert 	struct mactab *t1 = (struct mactab *)p1;
153625a69cdcSmillert 	struct mactab *t2 = (struct mactab *)p2;
153725a69cdcSmillert 
153825a69cdcSmillert 	return(t1->macname - t2->macname);
153925a69cdcSmillert }
154025a69cdcSmillert 
154125a69cdcSmillert int
sizetab(struct mactab * mp)154225a69cdcSmillert sizetab(struct mactab *mp)
154325a69cdcSmillert {
154425a69cdcSmillert 	int i;
154525a69cdcSmillert 
154625a69cdcSmillert 	i = 0;
154725a69cdcSmillert 	if (mp) {
154825a69cdcSmillert 		for (; mp->macname; mp++, i++)
154925a69cdcSmillert 			/*VOID*/ ;
155025a69cdcSmillert 	}
155125a69cdcSmillert 	return(i);
155225a69cdcSmillert }
155325a69cdcSmillert 
155425a69cdcSmillert struct mactab *
macfill(struct mactab * dst,struct mactab * src)155525a69cdcSmillert macfill(struct mactab *dst, struct mactab *src)
155625a69cdcSmillert {
155725a69cdcSmillert 
155825a69cdcSmillert 	if (src) {
155925a69cdcSmillert 		while (src->macname)
156025a69cdcSmillert 			*dst++ = *src++;
156125a69cdcSmillert 	}
156225a69cdcSmillert 	return(dst);
156325a69cdcSmillert }
156425a69cdcSmillert 
156525a69cdcSmillert __dead void
usage(void)156625a69cdcSmillert usage(void)
156725a69cdcSmillert {
156825a69cdcSmillert 	extern char *__progname;
156925a69cdcSmillert 
1570de4e3f8dSjmc 	fprintf(stderr, "usage: %s [-ikpw] [-m a | e | l | m | s] [file ...]\n", __progname);
157125a69cdcSmillert 	exit(1);
157225a69cdcSmillert }
157325a69cdcSmillert 
157425a69cdcSmillert void
buildtab(struct mactab ** r_back,int * r_size)157525a69cdcSmillert buildtab(struct mactab **r_back, int *r_size)
157625a69cdcSmillert {
157725a69cdcSmillert 	int	size;
157825a69cdcSmillert 	struct	mactab	*p, *p1, *p2;
157925a69cdcSmillert 	struct	mactab	*back;
158025a69cdcSmillert 
158125a69cdcSmillert 	size = sizetab(troffmactab) + sizetab(ppmactab);
158225a69cdcSmillert 	p1 = p2 = NULL;
158325a69cdcSmillert 	if (msflag) {
158425a69cdcSmillert 		switch (mac) {
158525a69cdcSmillert 		case ME:
158625a69cdcSmillert 			p1 = memactab;
158725a69cdcSmillert 			break;
158825a69cdcSmillert 		case MM:
158925a69cdcSmillert 			p1 = msmactab;
159025a69cdcSmillert 			p2 = mmmactab;
159125a69cdcSmillert 			break;
159225a69cdcSmillert 		case MS:
159325a69cdcSmillert 			p1 = msmactab;
159425a69cdcSmillert 			break;
159525a69cdcSmillert 		case MA:
159625a69cdcSmillert 			p1 = manmactab;
159725a69cdcSmillert 			break;
159825a69cdcSmillert 		default:
159925a69cdcSmillert 			break;
160025a69cdcSmillert 		}
160125a69cdcSmillert 	}
160225a69cdcSmillert 	size += sizetab(p1);
160325a69cdcSmillert 	size += sizetab(p2);
16049a97949aStedu 	back = calloc(size+2, sizeof(struct mactab));
160525a69cdcSmillert 	if (back == NULL)
1606e837b443Stom 		err(1, NULL);
160725a69cdcSmillert 
160825a69cdcSmillert 	p = macfill(back, troffmactab);
160925a69cdcSmillert 	p = macfill(p, ppmactab);
161025a69cdcSmillert 	p = macfill(p, p1);
161125a69cdcSmillert 	p = macfill(p, p2);
161225a69cdcSmillert 
161325a69cdcSmillert 	qsort(back, size, sizeof(struct mactab), macsort);
161425a69cdcSmillert 	*r_size = size;
161525a69cdcSmillert 	*r_back = back;
161625a69cdcSmillert }
161725a69cdcSmillert 
161825a69cdcSmillert /*
161925a69cdcSmillert  *	troff commands
162025a69cdcSmillert  */
162125a69cdcSmillert struct	mactab	troffmactab[] = {
162225a69cdcSmillert 	M(NONE,		'\\','"',	skip),	/* comment */
162325a69cdcSmillert 	M(NOMAC,	'd','e',	domacro),	/* define */
162425a69cdcSmillert 	M(NOMAC,	'i','g',	domacro),	/* ignore till .. */
162525a69cdcSmillert 	M(NOMAC,	'a','m',	domacro),	/* append macro */
162625a69cdcSmillert 	M(NBLK,		'n','f',	nf),	/* filled */
162725a69cdcSmillert 	M(NBLK,		'c','e',	ce),	/* centered */
162825a69cdcSmillert 
162925a69cdcSmillert 	M(NONE,		's','o',	so),	/* source a file */
163025a69cdcSmillert 	M(NONE,		'n','x',	nx),	/* go to next file */
163125a69cdcSmillert 
163225a69cdcSmillert 	M(NONE,		't','m',	skip),	/* print string on tty */
163325a69cdcSmillert 	M(NONE,		'h','w',	skip),	/* exception hyphen words */
163425a69cdcSmillert 	M(NONE,		0,0,		0)
163525a69cdcSmillert };
163625a69cdcSmillert 
163725a69cdcSmillert /*
163825a69cdcSmillert  *	Preprocessor output
163925a69cdcSmillert  */
164025a69cdcSmillert struct	mactab	ppmactab[] = {
164125a69cdcSmillert 	M(FNEST,	'E','Q',	EQ),	/* equation starting */
164225a69cdcSmillert 	M(FNEST,	'T','S',	intbl),	/* table starting */
164325a69cdcSmillert 	M(FNEST,	'T','C',	intbl),	/* alternative table? */
164425a69cdcSmillert 	M(FNEST,	'T','&',	intbl),	/* table reformatting */
164525a69cdcSmillert 	M(NONE,		'T','E',	outtbl),/* table ending */
164625a69cdcSmillert 	M(NONE,		'P','S',	PS),	/* picture starting */
164725a69cdcSmillert 	M(NONE,		0,0,		0)
164825a69cdcSmillert };
164925a69cdcSmillert 
165025a69cdcSmillert /*
165125a69cdcSmillert  *	Particular to ms and mm
165225a69cdcSmillert  */
165325a69cdcSmillert struct	mactab	msmactab[] = {
165425a69cdcSmillert 	M(NONE,		'T','L',	skiptocom),	/* title follows */
165525a69cdcSmillert 	M(NONE,		'F','S',	skiptocom),	/* start footnote */
165625a69cdcSmillert 	M(NONE,		'O','K',	skiptocom),	/* Other kws */
165725a69cdcSmillert 
165825a69cdcSmillert 	M(NONE,		'N','R',	skip),	/* undocumented */
165925a69cdcSmillert 	M(NONE,		'N','D',	skip),	/* use supplied date */
166025a69cdcSmillert 
166125a69cdcSmillert 	M(PARAG,	'P','P',	PP),	/* begin parag */
166225a69cdcSmillert 	M(PARAG,	'I','P',	PP),	/* begin indent parag, tag x */
166325a69cdcSmillert 	M(PARAG,	'L','P',	PP),	/* left blocked parag */
166425a69cdcSmillert 
166525a69cdcSmillert 	M(NONE,		'A','U',	AU),	/* author */
166625a69cdcSmillert 	M(NONE,		'A','I',	AU),	/* authors institution */
166725a69cdcSmillert 
166825a69cdcSmillert 	M(NONE,		'S','H',	SH),	/* section heading */
166925a69cdcSmillert 	M(NONE,		'S','N',	SH),	/* undocumented */
167025a69cdcSmillert 	M(NONE,		'U','X',	UX),	/* unix */
167125a69cdcSmillert 
167225a69cdcSmillert 	M(NBLK,		'D','S',	mssnblock),	/* start display text */
167325a69cdcSmillert 	M(NBLK,		'K','S',	mssnblock),	/* start keep */
167425a69cdcSmillert 	M(NBLK,		'K','F',	mssnblock),	/* start float keep */
167525a69cdcSmillert 	M(NONE,		0,0,		0)
167625a69cdcSmillert };
167725a69cdcSmillert 
167825a69cdcSmillert struct	mactab	mmmactab[] = {
167925a69cdcSmillert 	M(NONE,		'H',' ',	MMHU),	/* -mm ? */
168025a69cdcSmillert 	M(NONE,		'H','U',	MMHU),	/* -mm ? */
168125a69cdcSmillert 	M(PARAG,	'P',' ',	PP),	/* paragraph for -mm */
168225a69cdcSmillert 	M(NBLK,		'N','S',	mssnblock),	/* undocumented */
168325a69cdcSmillert 	M(NONE,		0,0,		0)
168425a69cdcSmillert };
168525a69cdcSmillert 
168625a69cdcSmillert struct	mactab	memactab[] = {
168725a69cdcSmillert 	M(PARAG,	'p','p',	mepp),
168825a69cdcSmillert 	M(PARAG,	'l','p',	mepp),
168925a69cdcSmillert 	M(PARAG,	'n','p',	mepp),
169025a69cdcSmillert 	M(NONE,		'i','p',	meip),
169125a69cdcSmillert 
169225a69cdcSmillert 	M(NONE,		's','h',	mesh),
169325a69cdcSmillert 	M(NONE,		'u','h',	mesh),
169425a69cdcSmillert 
169525a69cdcSmillert 	M(NBLK,		'(','l',	mesnblock),
169625a69cdcSmillert 	M(NBLK,		'(','q',	mesnblock),
169725a69cdcSmillert 	M(NBLK,		'(','b',	mesnblock),
169825a69cdcSmillert 	M(NBLK,		'(','z',	mesnblock),
169925a69cdcSmillert 	M(NBLK,		'(','c',	mesnblock),
170025a69cdcSmillert 
170125a69cdcSmillert 	M(NBLK,		'(','d',	mesnblock),
170225a69cdcSmillert 	M(NBLK,		'(','f',	mesnblock),
170325a69cdcSmillert 	M(NBLK,		'(','x',	mesnblock),
170425a69cdcSmillert 
170525a69cdcSmillert 	M(NONE,		'r',' ',	mefont),
170625a69cdcSmillert 	M(NONE,		'i',' ',	mefont),
170725a69cdcSmillert 	M(NONE,		'b',' ',	mefont),
170825a69cdcSmillert 	M(NONE,		'u',' ',	mefont),
170925a69cdcSmillert 	M(NONE,		'q',' ',	mefont),
171025a69cdcSmillert 	M(NONE,		'r','b',	mefont),
171125a69cdcSmillert 	M(NONE,		'b','i',	mefont),
171225a69cdcSmillert 	M(NONE,		'b','x',	mefont),
171325a69cdcSmillert 	M(NONE,		0,0,		0)
171425a69cdcSmillert };
171525a69cdcSmillert 
171625a69cdcSmillert struct	mactab	manmactab[] = {
171725a69cdcSmillert 	M(PARAG,	'B','I',	manfont),
171825a69cdcSmillert 	M(PARAG,	'B','R',	manfont),
171925a69cdcSmillert 	M(PARAG,	'I','B',	manfont),
172025a69cdcSmillert 	M(PARAG,	'I','R',	manfont),
172125a69cdcSmillert 	M(PARAG,	'R','B',	manfont),
172225a69cdcSmillert 	M(PARAG,	'R','I',	manfont),
172325a69cdcSmillert 
172425a69cdcSmillert 	M(PARAG,	'P','P',	manpp),
172525a69cdcSmillert 	M(PARAG,	'L','P',	manpp),
172625a69cdcSmillert 	M(PARAG,	'H','P',	manpp),
172725a69cdcSmillert 	M(NONE,		0,0,		0)
172825a69cdcSmillert };
1729