xref: /netbsd/usr.bin/deroff/deroff.c (revision 78876854)
1*78876854Smrg /*	$NetBSD: deroff.c,v 1.12 2019/02/03 03:19:29 mrg Exp $	*/
2cd4e76b8Sperry 
3cd4e76b8Sperry /* taken from: OpenBSD: deroff.c,v 1.6 2004/06/02 14:58:46 tom Exp */
4cd4e76b8Sperry 
5cd4e76b8Sperry /*-
6cd4e76b8Sperry  * Copyright (c) 1988, 1993
7cd4e76b8Sperry  *	The Regents of the University of California.  All rights reserved.
8cd4e76b8Sperry  *
9cd4e76b8Sperry  * Redistribution and use in source and binary forms, with or without
10cd4e76b8Sperry  * modification, are permitted provided that the following conditions
11cd4e76b8Sperry  * are met:
12cd4e76b8Sperry  * 1. Redistributions of source code must retain the above copyright
13cd4e76b8Sperry  *    notice, this list of conditions and the following disclaimer.
14cd4e76b8Sperry  * 2. Redistributions in binary form must reproduce the above copyright
15cd4e76b8Sperry  *    notice, this list of conditions and the following disclaimer in the
16cd4e76b8Sperry  *    documentation and/or other materials provided with the distribution.
17cd4e76b8Sperry  * 3. Neither the name of the University nor the names of its contributors
18cd4e76b8Sperry  *    may be used to endorse or promote products derived from this software
19cd4e76b8Sperry  *    without specific prior written permission.
20cd4e76b8Sperry  *
21cd4e76b8Sperry  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22cd4e76b8Sperry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23cd4e76b8Sperry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24cd4e76b8Sperry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25cd4e76b8Sperry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26cd4e76b8Sperry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27cd4e76b8Sperry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28cd4e76b8Sperry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29cd4e76b8Sperry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30cd4e76b8Sperry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31cd4e76b8Sperry  * SUCH DAMAGE.
32cd4e76b8Sperry  */
33cd4e76b8Sperry /*
34cd4e76b8Sperry  * Copyright (C) Caldera International Inc.  2001-2002.
35cd4e76b8Sperry  * All rights reserved.
36cd4e76b8Sperry  *
37cd4e76b8Sperry  * Redistribution and use in source and binary forms, with or without
38cd4e76b8Sperry  * modification, are permitted provided that the following conditions
39cd4e76b8Sperry  * are met:
40cd4e76b8Sperry  * 1. Redistributions of source code and documentation must retain the above
41cd4e76b8Sperry  *    copyright notice, this list of conditions and the following disclaimer.
42cd4e76b8Sperry  * 2. Redistributions in binary form must reproduce the above copyright
43cd4e76b8Sperry  *    notice, this list of conditions and the following disclaimer in the
44cd4e76b8Sperry  *    documentation and/or other materials provided with the distribution.
45cd4e76b8Sperry  * 3. All advertising materials mentioning features or use of this software
46cd4e76b8Sperry  *    must display the following acknowledgement:
47cd4e76b8Sperry  *	This product includes software developed or owned by Caldera
48cd4e76b8Sperry  *	International, Inc.
49cd4e76b8Sperry  * 4. Neither the name of Caldera International, Inc. nor the names of other
50cd4e76b8Sperry  *    contributors may be used to endorse or promote products derived from
51cd4e76b8Sperry  *    this software without specific prior written permission.
52cd4e76b8Sperry  *
53cd4e76b8Sperry  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
54cd4e76b8Sperry  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
55cd4e76b8Sperry  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
56cd4e76b8Sperry  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
57cd4e76b8Sperry  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
58cd4e76b8Sperry  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59cd4e76b8Sperry  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60cd4e76b8Sperry  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61cd4e76b8Sperry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62cd4e76b8Sperry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
63cd4e76b8Sperry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
64cd4e76b8Sperry  * POSSIBILITY OF SUCH DAMAGE.
65cd4e76b8Sperry  */
66cd4e76b8Sperry 
6736c7456dSperry #include <sys/cdefs.h>
68*78876854Smrg __RCSID("$NetBSD: deroff.c,v 1.12 2019/02/03 03:19:29 mrg Exp $");
693fa48f9eSjoerg 
70cd4e76b8Sperry #include <err.h>
71cd4e76b8Sperry #include <limits.h>
7235d7a878Slukem #include <stddef.h>
73cd4e76b8Sperry #include <stdio.h>
74cd4e76b8Sperry #include <stdlib.h>
75cd4e76b8Sperry #include <string.h>
76cd4e76b8Sperry #include <unistd.h>
77cd4e76b8Sperry 
78cd4e76b8Sperry /*
79cd4e76b8Sperry  *	Deroff command -- strip troff, eqn, and Tbl sequences from
80cd4e76b8Sperry  *	a file.  Has two flags argument, -w, to cause output one word per line
81cd4e76b8Sperry  *	rather than in the original format.
82cd4e76b8Sperry  *	-mm (or -ms) causes the corresponding macro's to be interpreted
83cd4e76b8Sperry  *	so that just sentences are output
84cd4e76b8Sperry  *	-ml  also gets rid of lists.
85cd4e76b8Sperry  *	Deroff follows .so and .nx commands, removes contents of macro
86cd4e76b8Sperry  *	definitions, equations (both .EQ ... .EN and $...$),
87cd4e76b8Sperry  *	Tbl command sequences, and Troff backslash constructions.
88cd4e76b8Sperry  *
89cd4e76b8Sperry  *	All input is through the Cget macro;
90cd4e76b8Sperry  *	the most recently read character is in c.
91cd4e76b8Sperry  *
92cd4e76b8Sperry  *	Modified by Robert Henry to process -me and -man macros.
93cd4e76b8Sperry  */
94cd4e76b8Sperry 
95cd4e76b8Sperry #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
96cd4e76b8Sperry #define C1get ( (c=getc(infile)) == EOF ? eof() :  c)
97cd4e76b8Sperry 
98cd4e76b8Sperry #ifdef DEBUG
99cd4e76b8Sperry #  define C	_C()
100cd4e76b8Sperry #  define C1	_C1()
101cd4e76b8Sperry #else /* not DEBUG */
102cd4e76b8Sperry #  define C	Cget
103cd4e76b8Sperry #  define C1	C1get
104cd4e76b8Sperry #endif /* not DEBUG */
105cd4e76b8Sperry 
106cd4e76b8Sperry #define SKIP while (C != '\n')
107cd4e76b8Sperry #define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c
108cd4e76b8Sperry 
109cd4e76b8Sperry #define	YES 1
110cd4e76b8Sperry #define	NO 0
111cd4e76b8Sperry #define	MS 0	/* -ms */
112cd4e76b8Sperry #define	MM 1	/* -mm */
113cd4e76b8Sperry #define	ME 2	/* -me */
114cd4e76b8Sperry #define	MA 3	/* -man */
115cd4e76b8Sperry 
116cd4e76b8Sperry #ifdef DEBUG
1179d59054aSjoerg static char *mactab[] = { "-ms", "-mm", "-me", "-ma" };
118cd4e76b8Sperry #endif /* DEBUG */
119cd4e76b8Sperry 
120cd4e76b8Sperry #define	ONE 1
121cd4e76b8Sperry #define	TWO 2
122cd4e76b8Sperry 
123cd4e76b8Sperry #define NOCHAR -2
124cd4e76b8Sperry #define SPECIAL 0
125cd4e76b8Sperry #define APOS 1
126cd4e76b8Sperry #define PUNCT 2
127cd4e76b8Sperry #define DIGIT 3
128cd4e76b8Sperry #define LETTER 4
129cd4e76b8Sperry 
130cd4e76b8Sperry #define MAXFILES 20
131cd4e76b8Sperry 
13297ccbe26Schristos static int	iflag;
13397ccbe26Schristos static int	wordflag;
13497ccbe26Schristos static int	msflag;	 /* processing a source written using a mac package */
13597ccbe26Schristos static int	mac;		/* which package */
13697ccbe26Schristos static int	disp;
13797ccbe26Schristos static int	parag;
13897ccbe26Schristos static int	inmacro;
13997ccbe26Schristos static int	intable;
14097ccbe26Schristos static int	keepblock; /* keep blocks of text; normally false when msflag */
141cd4e76b8Sperry 
14297ccbe26Schristos static char chars[128];  /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
143cd4e76b8Sperry 
14497ccbe26Schristos static char line[LINE_MAX];
14597ccbe26Schristos static char *lp;
146cd4e76b8Sperry 
14797ccbe26Schristos static int c;
14897ccbe26Schristos static int pc;
14997ccbe26Schristos static int ldelim;
15097ccbe26Schristos static int rdelim;
151cd4e76b8Sperry 
15297ccbe26Schristos static char fname[PATH_MAX];
15397ccbe26Schristos static FILE *files[MAXFILES];
15497ccbe26Schristos static FILE **filesp;
15597ccbe26Schristos static FILE *infile;
156cd4e76b8Sperry 
15797ccbe26Schristos static int argc;
15897ccbe26Schristos static char **argv;
159cd4e76b8Sperry 
160cd4e76b8Sperry /*
161cd4e76b8Sperry  *	Macro processing
162cd4e76b8Sperry  *
163cd4e76b8Sperry  *	Macro table definitions
164cd4e76b8Sperry  */
165cd4e76b8Sperry typedef	int pacmac;		/* compressed macro name */
16697ccbe26Schristos static int	argconcat = 0;	/* concat arguments together (-me only) */
167cd4e76b8Sperry 
168cd4e76b8Sperry #define	tomac(c1, c2)		((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
169ed7f0ec9Schristos #define	frommac(src, c1, c2)	(((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF), __USE(c1), __USE(c2))
170cd4e76b8Sperry 
171cd4e76b8Sperry struct mactab {
172cd4e76b8Sperry 	int	condition;
173cd4e76b8Sperry 	pacmac	macname;
17497ccbe26Schristos 	int	(*func)(pacmac);
175cd4e76b8Sperry };
176cd4e76b8Sperry 
17797ccbe26Schristos static const struct	mactab	troffmactab[];
17897ccbe26Schristos static const struct	mactab	ppmactab[];
17997ccbe26Schristos static const struct	mactab	msmactab[];
18097ccbe26Schristos static const struct	mactab	mmmactab[];
18197ccbe26Schristos static const struct	mactab	memactab[];
18297ccbe26Schristos static const struct	mactab	manmactab[];
183cd4e76b8Sperry 
184cd4e76b8Sperry /*
185cd4e76b8Sperry  *	Macro table initialization
186cd4e76b8Sperry  */
187cd4e76b8Sperry #define	M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
188cd4e76b8Sperry 
189cd4e76b8Sperry /*
190cd4e76b8Sperry  *	Flags for matching conditions other than
191cd4e76b8Sperry  *	the macro name
192cd4e76b8Sperry  */
193cd4e76b8Sperry #define	NONE		0
194cd4e76b8Sperry #define	FNEST		1		/* no nested files */
195cd4e76b8Sperry #define	NOMAC		2		/* no macro */
196cd4e76b8Sperry #define	MAC		3		/* macro */
197cd4e76b8Sperry #define	PARAG		4		/* in a paragraph */
198cd4e76b8Sperry #define	MSF		5		/* msflag is on */
199cd4e76b8Sperry #define	NBLK		6		/* set if no blocks to be kept */
200cd4e76b8Sperry 
201cd4e76b8Sperry /*
202cd4e76b8Sperry  *	Return codes from macro minions, determine where to jump,
203cd4e76b8Sperry  *	how to repeat/reprocess text
204cd4e76b8Sperry  */
205cd4e76b8Sperry #define	COMX		1		/* goto comx */
206cd4e76b8Sperry #define	COM		2		/* goto com */
207cd4e76b8Sperry 
20897ccbe26Schristos static int	 skeqn(void);
20997ccbe26Schristos static int	 eof(void);
21097ccbe26Schristos #ifdef DEBUG
21197ccbe26Schristos static int	 _C1(void);
21297ccbe26Schristos static int	 _C(void);
21397ccbe26Schristos #endif
21497ccbe26Schristos static int	 EQ(pacmac);
21597ccbe26Schristos static int	 domacro(pacmac);
21697ccbe26Schristos static int	 PS(pacmac);
21797ccbe26Schristos static int	 skip(pacmac);
21897ccbe26Schristos static int	 intbl(pacmac);
21997ccbe26Schristos static int	 outtbl(pacmac);
22097ccbe26Schristos static int	 so(pacmac);
22197ccbe26Schristos static int	 nx(pacmac);
22297ccbe26Schristos static int	 skiptocom(pacmac);
22397ccbe26Schristos static int	 PP(pacmac);
22497ccbe26Schristos static int	 AU(pacmac);
22597ccbe26Schristos static int	 SH(pacmac);
22697ccbe26Schristos static int	 UX(pacmac);
22797ccbe26Schristos static int	 MMHU(pacmac);
22897ccbe26Schristos static int	 mesnblock(pacmac);
22997ccbe26Schristos static int	 mssnblock(pacmac);
23097ccbe26Schristos static int	 nf(pacmac);
23197ccbe26Schristos static int	 ce(pacmac);
23297ccbe26Schristos static int	 meip(pacmac);
23397ccbe26Schristos static int	 mepp(pacmac);
23497ccbe26Schristos static int	 mesh(pacmac);
23597ccbe26Schristos static int	 mefont(pacmac);
23697ccbe26Schristos static int	 manfont(pacmac);
23797ccbe26Schristos static int	 manpp(pacmac);
23897ccbe26Schristos static int	 macsort(const void *, const void *);
23997ccbe26Schristos static int	 sizetab(const struct mactab *);
24097ccbe26Schristos static void	 getfname(void);
24197ccbe26Schristos static void	 textline(char *, int);
2429d59054aSjoerg static void	 work(void) __dead;
24397ccbe26Schristos static void	 regline(void (*)(char *, int), int);
24497ccbe26Schristos static void	 macro(void);
24597ccbe26Schristos static void	 tbl(void);
24697ccbe26Schristos static void	 stbl(void);
24797ccbe26Schristos static void	 eqn(void);
24897ccbe26Schristos static void	 backsl(void);
24997ccbe26Schristos static void	 sce(void);
25097ccbe26Schristos static void	 refer(int);
25197ccbe26Schristos static void	 inpic(void);
25297ccbe26Schristos static void	 msputmac(char *, int);
25397ccbe26Schristos static void	 msputwords(int);
25497ccbe26Schristos static void	 meputmac(char *, int);
25597ccbe26Schristos static void	 meputwords(int);
25697ccbe26Schristos static void	 noblock(char, char);
25797ccbe26Schristos static void	 defcomline(pacmac);
25897ccbe26Schristos static void	 comline(void);
25997ccbe26Schristos static void	 buildtab(const struct mactab **, int *);
26097ccbe26Schristos static FILE	*opn(char *);
26197ccbe26Schristos static struct mactab *macfill(struct mactab *, const struct mactab *);
2628b0f9554Sperry static void usage(void) __dead;
263cd4e76b8Sperry 
264cd4e76b8Sperry int
main(int ac,char ** av)265cd4e76b8Sperry main(int ac, char **av)
266cd4e76b8Sperry {
267cd4e76b8Sperry 	int	i, ch;
268cd4e76b8Sperry 	int	errflg = 0;
269cd4e76b8Sperry 	int	kflag = NO;
270cd4e76b8Sperry 
271cd4e76b8Sperry 	iflag = NO;
272cd4e76b8Sperry 	wordflag = NO;
273cd4e76b8Sperry 	msflag = NO;
274cd4e76b8Sperry 	mac = ME;
275cd4e76b8Sperry 	disp = NO;
276cd4e76b8Sperry 	parag = NO;
277cd4e76b8Sperry 	inmacro = NO;
278cd4e76b8Sperry 	intable = NO;
279cd4e76b8Sperry 	ldelim	= NOCHAR;
280cd4e76b8Sperry 	rdelim	= NOCHAR;
281cd4e76b8Sperry 	keepblock = YES;
282cd4e76b8Sperry 
283cd4e76b8Sperry 	while ((ch = getopt(ac, av, "ikpwm:")) != -1) {
284cd4e76b8Sperry 		switch (ch) {
285cd4e76b8Sperry 		case 'i':
286cd4e76b8Sperry 			iflag = YES;
287cd4e76b8Sperry 			break;
288cd4e76b8Sperry 		case 'k':
289cd4e76b8Sperry 			kflag = YES;
290cd4e76b8Sperry 			break;
291cd4e76b8Sperry 		case 'm':
292cd4e76b8Sperry 			msflag = YES;
293cd4e76b8Sperry 			keepblock = NO;
294cd4e76b8Sperry 			switch (optarg[0]) {
295cd4e76b8Sperry 			case 'm':
296cd4e76b8Sperry 				mac = MM;
297cd4e76b8Sperry 				break;
298cd4e76b8Sperry 			case 's':
299cd4e76b8Sperry 				mac = MS;
300cd4e76b8Sperry 				break;
301cd4e76b8Sperry 			case 'e':
302cd4e76b8Sperry 				mac = ME;
303cd4e76b8Sperry 				break;
304cd4e76b8Sperry 			case 'a':
305cd4e76b8Sperry 				mac = MA;
306cd4e76b8Sperry 				break;
307cd4e76b8Sperry 			case 'l':
308cd4e76b8Sperry 				disp = YES;
309cd4e76b8Sperry 				break;
310cd4e76b8Sperry 			default:
311cd4e76b8Sperry 				errflg++;
312cd4e76b8Sperry 				break;
313cd4e76b8Sperry 			}
314cd4e76b8Sperry 			if (errflg == 0 && optarg[1] != '\0')
315cd4e76b8Sperry 				errflg++;
316cd4e76b8Sperry 			break;
317cd4e76b8Sperry 		case 'p':
318cd4e76b8Sperry 			parag = YES;
319cd4e76b8Sperry 			break;
320cd4e76b8Sperry 		case 'w':
321cd4e76b8Sperry 			wordflag = YES;
322cd4e76b8Sperry 			kflag = YES;
323cd4e76b8Sperry 			break;
324cd4e76b8Sperry 		default:
325cd4e76b8Sperry 			errflg++;
326cd4e76b8Sperry 		}
327cd4e76b8Sperry 	}
328cd4e76b8Sperry 	argc = ac - optind;
329cd4e76b8Sperry 	argv = av + optind;
330cd4e76b8Sperry 
331cd4e76b8Sperry 	if (kflag)
332cd4e76b8Sperry 		keepblock = YES;
333cd4e76b8Sperry 	if (errflg)
334cd4e76b8Sperry 		usage();
335cd4e76b8Sperry 
336cd4e76b8Sperry #ifdef DEBUG
337cd4e76b8Sperry 	printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
338cd4e76b8Sperry 		msflag, mactab[mac], keepblock, disp);
339cd4e76b8Sperry #endif /* DEBUG */
340cd4e76b8Sperry 	if (argc == 0) {
341cd4e76b8Sperry 		infile = stdin;
342cd4e76b8Sperry 	} else {
343cd4e76b8Sperry 		infile = opn(argv[0]);
344cd4e76b8Sperry 		--argc;
345cd4e76b8Sperry 		++argv;
346cd4e76b8Sperry 	}
347cd4e76b8Sperry 	files[0] = infile;
348cd4e76b8Sperry 	filesp = &files[0];
349cd4e76b8Sperry 
350cd4e76b8Sperry 	for (i = 'a'; i <= 'z' ; ++i)
351cd4e76b8Sperry 		chars[i] = LETTER;
352cd4e76b8Sperry 	for (i = 'A'; i <= 'Z'; ++i)
353cd4e76b8Sperry 		chars[i] = LETTER;
354cd4e76b8Sperry 	for (i = '0'; i <= '9'; ++i)
355cd4e76b8Sperry 		chars[i] = DIGIT;
356cd4e76b8Sperry 	chars['\''] = APOS;
357cd4e76b8Sperry 	chars['&'] = APOS;
358cd4e76b8Sperry 	chars['.'] = PUNCT;
359cd4e76b8Sperry 	chars[','] = PUNCT;
360cd4e76b8Sperry 	chars[';'] = PUNCT;
361cd4e76b8Sperry 	chars['?'] = PUNCT;
362cd4e76b8Sperry 	chars[':'] = PUNCT;
363cd4e76b8Sperry 	work();
36497ccbe26Schristos 	return 0;
365cd4e76b8Sperry }
366cd4e76b8Sperry 
36797ccbe26Schristos static int
skeqn(void)368cd4e76b8Sperry skeqn(void)
369cd4e76b8Sperry {
370cd4e76b8Sperry 
371cd4e76b8Sperry 	while ((c = getc(infile)) != rdelim) {
372cd4e76b8Sperry 		if (c == EOF)
373cd4e76b8Sperry 			c = eof();
374cd4e76b8Sperry 		else if (c == '"') {
375cd4e76b8Sperry 			while ((c = getc(infile)) != '"') {
376cd4e76b8Sperry 				if (c == EOF ||
377cd4e76b8Sperry 				    (c == '\\' && (c = getc(infile)) == EOF))
378cd4e76b8Sperry 					c = eof();
379cd4e76b8Sperry 			}
380cd4e76b8Sperry 		}
381cd4e76b8Sperry 	}
382cd4e76b8Sperry 	if (msflag)
38397ccbe26Schristos 		return c == 'x';
38497ccbe26Schristos 	return c == ' ';
385cd4e76b8Sperry }
386cd4e76b8Sperry 
38797ccbe26Schristos static FILE *
opn(char * p)388cd4e76b8Sperry opn(char *p)
389cd4e76b8Sperry {
390cd4e76b8Sperry 	FILE *fd;
391cd4e76b8Sperry 
392cd4e76b8Sperry 	if ((fd = fopen(p, "r")) == NULL)
393cd4e76b8Sperry 		err(1, "fopen %s", p);
394cd4e76b8Sperry 
39597ccbe26Schristos 	return fd;
396cd4e76b8Sperry }
397cd4e76b8Sperry 
39897ccbe26Schristos static int
eof(void)399cd4e76b8Sperry eof(void)
400cd4e76b8Sperry {
401cd4e76b8Sperry 
402cd4e76b8Sperry 	if (infile != stdin)
403cd4e76b8Sperry 		fclose(infile);
404cd4e76b8Sperry 	if (filesp > files)
405cd4e76b8Sperry 		infile = *--filesp;
406cd4e76b8Sperry 	else if (argc > 0) {
407cd4e76b8Sperry 		infile = opn(argv[0]);
408cd4e76b8Sperry 		--argc;
409cd4e76b8Sperry 		++argv;
410cd4e76b8Sperry 	} else
411cd4e76b8Sperry 		exit(0);
41297ccbe26Schristos 	return C;
413cd4e76b8Sperry }
414cd4e76b8Sperry 
41597ccbe26Schristos static void
getfname(void)416cd4e76b8Sperry getfname(void)
417cd4e76b8Sperry {
418cd4e76b8Sperry 	char *p;
419cd4e76b8Sperry 	struct chain {
420cd4e76b8Sperry 		struct chain *nextp;
421cd4e76b8Sperry 		char *datap;
422cd4e76b8Sperry 	} *q;
423cd4e76b8Sperry 	static struct chain *namechain= NULL;
424cd4e76b8Sperry 
425cd4e76b8Sperry 	while (C == ' ')
426cd4e76b8Sperry 		;	/* nothing */
427cd4e76b8Sperry 
42835d7a878Slukem 	for (p = fname ; p - fname < (ptrdiff_t)sizeof(fname) &&
42935d7a878Slukem 	    (*p = c) != '\n' &&
430cd4e76b8Sperry 	    c != ' ' && c != '\t' && c != '\\'; ++p)
431cd4e76b8Sperry 		C;
432cd4e76b8Sperry 	*p = '\0';
433cd4e76b8Sperry 	while (c != '\n')
434cd4e76b8Sperry 		C;
435cd4e76b8Sperry 
436cd4e76b8Sperry 	/* see if this name has already been used */
437cd4e76b8Sperry 	for (q = namechain ; q; q = q->nextp)
438cd4e76b8Sperry 		if (strcmp(fname, q->datap) == 0) {
439cd4e76b8Sperry 			fname[0] = '\0';
440cd4e76b8Sperry 			return;
441cd4e76b8Sperry 		}
442cd4e76b8Sperry 
443cd4e76b8Sperry 	q = (struct chain *) malloc(sizeof(struct chain));
444cd4e76b8Sperry 	if (q == NULL)
445cd4e76b8Sperry 		err(1, NULL);
446cd4e76b8Sperry 	q->nextp = namechain;
447cd4e76b8Sperry 	q->datap = strdup(fname);
448cd4e76b8Sperry 	if (q->datap == NULL)
449cd4e76b8Sperry 		err(1, NULL);
450cd4e76b8Sperry 	namechain = q;
451cd4e76b8Sperry }
452cd4e76b8Sperry 
453cd4e76b8Sperry /*ARGSUSED*/
45497ccbe26Schristos static void
textline(char * str,int constant)455cd4e76b8Sperry textline(char *str, int constant)
456cd4e76b8Sperry {
457cd4e76b8Sperry 
458cd4e76b8Sperry 	if (wordflag) {
459cd4e76b8Sperry 		msputwords(0);
460cd4e76b8Sperry 		return;
461cd4e76b8Sperry 	}
462cd4e76b8Sperry 	puts(str);
463cd4e76b8Sperry }
464cd4e76b8Sperry 
4659d59054aSjoerg static void
work(void)466cd4e76b8Sperry work(void)
467cd4e76b8Sperry {
468cd4e76b8Sperry 
469cd4e76b8Sperry 	for (;;) {
470cd4e76b8Sperry 		C;
471cd4e76b8Sperry #ifdef FULLDEBUG
472cd4e76b8Sperry 		printf("Starting work with `%c'\n", c);
473cd4e76b8Sperry #endif /* FULLDEBUG */
474cd4e76b8Sperry 		if (c == '.' || c == '\'')
475cd4e76b8Sperry 			comline();
476cd4e76b8Sperry 		else
477cd4e76b8Sperry 			regline(textline, TWO);
478cd4e76b8Sperry 	}
479cd4e76b8Sperry }
480cd4e76b8Sperry 
48197ccbe26Schristos static void
regline(void (* pfunc)(char *,int),int constant)482cd4e76b8Sperry regline(void (*pfunc)(char *, int), int constant)
483cd4e76b8Sperry {
484cd4e76b8Sperry 
485cd4e76b8Sperry 	line[0] = c;
486cd4e76b8Sperry 	lp = line;
48735d7a878Slukem 	while (lp - line < (ptrdiff_t)sizeof(line)) {
488cd4e76b8Sperry 		if (c == '\\') {
489cd4e76b8Sperry 			*lp = ' ';
490cd4e76b8Sperry 			backsl();
491cd4e76b8Sperry 		}
492cd4e76b8Sperry 		if (c == '\n')
493cd4e76b8Sperry 			break;
494cd4e76b8Sperry 		if (intable && c == 'T') {
495cd4e76b8Sperry 			*++lp = C;
496cd4e76b8Sperry 			if (c == '{' || c == '}') {
497cd4e76b8Sperry 				lp[-1] = ' ';
498cd4e76b8Sperry 				*lp = C;
499cd4e76b8Sperry 			}
500cd4e76b8Sperry 		} else {
501cd4e76b8Sperry 			*++lp = C;
502cd4e76b8Sperry 		}
503cd4e76b8Sperry 	}
504cd4e76b8Sperry 	*lp = '\0';
505cd4e76b8Sperry 
506cd4e76b8Sperry 	if (line[0] != '\0')
507cd4e76b8Sperry 		(*pfunc)(line, constant);
508cd4e76b8Sperry }
509cd4e76b8Sperry 
51097ccbe26Schristos static void
macro(void)511cd4e76b8Sperry macro(void)
512cd4e76b8Sperry {
513cd4e76b8Sperry 
514cd4e76b8Sperry 	if (msflag) {
515cd4e76b8Sperry 		do {
516cd4e76b8Sperry 			SKIP;
517cd4e76b8Sperry 		} while (C!='.' || C!='.' || C=='.');	/* look for  .. */
518cd4e76b8Sperry 		if (c != '\n')
519cd4e76b8Sperry 			SKIP;
520cd4e76b8Sperry 		return;
521cd4e76b8Sperry 	}
522cd4e76b8Sperry 	SKIP;
523cd4e76b8Sperry 	inmacro = YES;
524cd4e76b8Sperry }
525cd4e76b8Sperry 
52697ccbe26Schristos static void
tbl(void)527cd4e76b8Sperry tbl(void)
528cd4e76b8Sperry {
529cd4e76b8Sperry 
530cd4e76b8Sperry 	while (C != '.')
531cd4e76b8Sperry 		;	/* nothing */
532cd4e76b8Sperry 	SKIP;
533cd4e76b8Sperry 	intable = YES;
534cd4e76b8Sperry }
535cd4e76b8Sperry 
53697ccbe26Schristos static void
stbl(void)537cd4e76b8Sperry stbl(void)
538cd4e76b8Sperry {
539cd4e76b8Sperry 
540cd4e76b8Sperry 	while (C != '.')
541cd4e76b8Sperry 		;	/* nothing */
542cd4e76b8Sperry 	SKIP_TO_COM;
543cd4e76b8Sperry 	if (c != 'T' || C != 'E') {
544cd4e76b8Sperry 		SKIP;
545cd4e76b8Sperry 		pc = c;
546cd4e76b8Sperry 		while (C != '.' || pc != '\n' || C != 'T' || C != 'E')
547cd4e76b8Sperry 			pc = c;
548cd4e76b8Sperry 	}
549cd4e76b8Sperry }
550cd4e76b8Sperry 
55197ccbe26Schristos static void
eqn(void)552cd4e76b8Sperry eqn(void)
553cd4e76b8Sperry {
554cd4e76b8Sperry 	int c1, c2;
555cd4e76b8Sperry 	int dflg;
556cd4e76b8Sperry 	char last;
557cd4e76b8Sperry 
558cd4e76b8Sperry 	last=0;
559cd4e76b8Sperry 	dflg = 1;
560cd4e76b8Sperry 	SKIP;
561cd4e76b8Sperry 
562cd4e76b8Sperry 	for (;;) {
563cd4e76b8Sperry 		if (C1 == '.'  || c == '\'') {
564cd4e76b8Sperry 			while (C1 == ' ' || c == '\t')
565cd4e76b8Sperry 				;
566cd4e76b8Sperry 			if (c == 'E' && C1 == 'N') {
567cd4e76b8Sperry 				SKIP;
568cd4e76b8Sperry 				if (msflag && dflg) {
569cd4e76b8Sperry 					putchar('x');
570cd4e76b8Sperry 					putchar(' ');
571cd4e76b8Sperry 					if (last) {
572cd4e76b8Sperry 						putchar(last);
573cd4e76b8Sperry 						putchar('\n');
574cd4e76b8Sperry 					}
575cd4e76b8Sperry 				}
576cd4e76b8Sperry 				return;
577cd4e76b8Sperry 			}
578cd4e76b8Sperry 		} else if (c == 'd') {
579cd4e76b8Sperry 			/* look for delim */
580cd4e76b8Sperry 			if (C1 == 'e' && C1 == 'l')
581cd4e76b8Sperry 				if (C1 == 'i' && C1 == 'm') {
582cd4e76b8Sperry 					while (C1 == ' ')
583cd4e76b8Sperry 						;	/* nothing */
584cd4e76b8Sperry 
585cd4e76b8Sperry 					if ((c1 = c) == '\n' ||
586cd4e76b8Sperry 					    (c2 = C1) == '\n' ||
587cd4e76b8Sperry 					    (c1 == 'o' && c2 == 'f' && C1=='f')) {
588cd4e76b8Sperry 						ldelim = NOCHAR;
589cd4e76b8Sperry 						rdelim = NOCHAR;
590cd4e76b8Sperry 					} else {
591cd4e76b8Sperry 						ldelim = c1;
592cd4e76b8Sperry 						rdelim = c2;
593cd4e76b8Sperry 					}
594cd4e76b8Sperry 				}
595cd4e76b8Sperry 			dflg = 0;
596cd4e76b8Sperry 		}
597cd4e76b8Sperry 
598cd4e76b8Sperry 		if (c != '\n')
599cd4e76b8Sperry 			while (C1 != '\n') {
600cd4e76b8Sperry 				if (chars[c] == PUNCT)
601cd4e76b8Sperry 					last = c;
602cd4e76b8Sperry 				else if (c != ' ')
603cd4e76b8Sperry 					last = 0;
604cd4e76b8Sperry 			}
605cd4e76b8Sperry 	}
606cd4e76b8Sperry }
607cd4e76b8Sperry 
608cd4e76b8Sperry /* skip over a complete backslash construction */
60997ccbe26Schristos static void
backsl(void)610cd4e76b8Sperry backsl(void)
611cd4e76b8Sperry {
612cd4e76b8Sperry 	int bdelim;
613cd4e76b8Sperry 
614cd4e76b8Sperry sw:
615cd4e76b8Sperry 	switch (C) {
616cd4e76b8Sperry 	case '"':
617cd4e76b8Sperry 		SKIP;
618cd4e76b8Sperry 		return;
619cd4e76b8Sperry 
620cd4e76b8Sperry 	case 's':
621cd4e76b8Sperry 		if (C == '\\')
622cd4e76b8Sperry 			backsl();
623cd4e76b8Sperry 		else {
624cd4e76b8Sperry 			while (C >= '0' && c <= '9')
625cd4e76b8Sperry 				;	/* nothing */
626cd4e76b8Sperry 			ungetc(c, infile);
627cd4e76b8Sperry 			c = '0';
628cd4e76b8Sperry 		}
629cd4e76b8Sperry 		--lp;
630cd4e76b8Sperry 		return;
631cd4e76b8Sperry 
632cd4e76b8Sperry 	case 'f':
633cd4e76b8Sperry 	case 'n':
634cd4e76b8Sperry 	case '*':
635cd4e76b8Sperry 		if (C != '(')
636cd4e76b8Sperry 			return;
637cd4e76b8Sperry 
638*78876854Smrg 		/* FALLTHROUGH */
639cd4e76b8Sperry 	case '(':
640cd4e76b8Sperry 		if (msflag) {
641cd4e76b8Sperry 			if (C == 'e') {
642cd4e76b8Sperry 				if (C == 'm') {
643cd4e76b8Sperry 					*lp = '-';
644cd4e76b8Sperry 					return;
645cd4e76b8Sperry 				}
646cd4e76b8Sperry 			}
647cd4e76b8Sperry 			else if (c != '\n')
648cd4e76b8Sperry 				C;
649cd4e76b8Sperry 			return;
650cd4e76b8Sperry 		}
651cd4e76b8Sperry 		if (C != '\n')
652cd4e76b8Sperry 			C;
653cd4e76b8Sperry 		return;
654cd4e76b8Sperry 
655cd4e76b8Sperry 	case '$':
656cd4e76b8Sperry 		C;	/* discard argument number */
657cd4e76b8Sperry 		return;
658cd4e76b8Sperry 
659cd4e76b8Sperry 	case 'b':
660cd4e76b8Sperry 	case 'x':
661cd4e76b8Sperry 	case 'v':
662cd4e76b8Sperry 	case 'h':
663cd4e76b8Sperry 	case 'w':
664cd4e76b8Sperry 	case 'o':
665cd4e76b8Sperry 	case 'l':
666cd4e76b8Sperry 	case 'L':
667cd4e76b8Sperry 		if ((bdelim = C) == '\n')
668cd4e76b8Sperry 			return;
669cd4e76b8Sperry 		while (C != '\n' && c != bdelim)
670cd4e76b8Sperry 			if (c == '\\')
671cd4e76b8Sperry 				backsl();
672cd4e76b8Sperry 		return;
673cd4e76b8Sperry 
674cd4e76b8Sperry 	case '\\':
675cd4e76b8Sperry 		if (inmacro)
676cd4e76b8Sperry 			goto sw;
677cd4e76b8Sperry 
678cd4e76b8Sperry 	default:
679cd4e76b8Sperry 		return;
680cd4e76b8Sperry 	}
681cd4e76b8Sperry }
682cd4e76b8Sperry 
68397ccbe26Schristos static void
sce(void)684cd4e76b8Sperry sce(void)
685cd4e76b8Sperry {
686cd4e76b8Sperry 	char *ap;
687cd4e76b8Sperry 	int n, i;
688cd4e76b8Sperry 	char a[10];
689cd4e76b8Sperry 
690cd4e76b8Sperry 	for (ap = a; C != '\n'; ap++) {
691cd4e76b8Sperry 		*ap = c;
692cd4e76b8Sperry 		if (ap == &a[9]) {
693cd4e76b8Sperry 			SKIP;
694cd4e76b8Sperry 			ap = a;
695cd4e76b8Sperry 			break;
696cd4e76b8Sperry 		}
697cd4e76b8Sperry 	}
698cd4e76b8Sperry 	if (ap != a)
699cd4e76b8Sperry 		n = atoi(a);
700cd4e76b8Sperry 	else
701cd4e76b8Sperry 		n = 1;
702cd4e76b8Sperry 	for (i = 0; i < n;) {
703cd4e76b8Sperry 		if (C == '.') {
704cd4e76b8Sperry 			if (C == 'c') {
705cd4e76b8Sperry 				if (C == 'e') {
706cd4e76b8Sperry 					while (C == ' ')
707cd4e76b8Sperry 						;	/* nothing */
708cd4e76b8Sperry 					if (c == '0') {
709cd4e76b8Sperry 						SKIP;
710cd4e76b8Sperry 						break;
711cd4e76b8Sperry 					} else
712cd4e76b8Sperry 						SKIP;
713cd4e76b8Sperry 				}
714cd4e76b8Sperry 				else
715cd4e76b8Sperry 					SKIP;
716cd4e76b8Sperry 			} else if (c == 'P' || C == 'P') {
717cd4e76b8Sperry 				if (c != '\n')
718cd4e76b8Sperry 					SKIP;
719cd4e76b8Sperry 				break;
720cd4e76b8Sperry 			} else if (c != '\n')
721cd4e76b8Sperry 				SKIP;
722cd4e76b8Sperry 		} else {
723cd4e76b8Sperry 			SKIP;
724cd4e76b8Sperry 			i++;
725cd4e76b8Sperry 		}
726cd4e76b8Sperry 	}
727cd4e76b8Sperry }
728cd4e76b8Sperry 
72997ccbe26Schristos static void
refer(int c1)730cd4e76b8Sperry refer(int c1)
731cd4e76b8Sperry {
732cd4e76b8Sperry 	int c2;
733cd4e76b8Sperry 
734cd4e76b8Sperry 	if (c1 != '\n')
735cd4e76b8Sperry 		SKIP;
736cd4e76b8Sperry 
737cd4e76b8Sperry 	for (c2 = -1;;) {
738cd4e76b8Sperry 		if (C != '.')
739cd4e76b8Sperry 			SKIP;
740cd4e76b8Sperry 		else {
741cd4e76b8Sperry 			if (C != ']')
742cd4e76b8Sperry 				SKIP;
743cd4e76b8Sperry 			else {
744cd4e76b8Sperry 				while (C != '\n')
745cd4e76b8Sperry 					c2 = c;
746cd4e76b8Sperry 				if (c2 != -1 && chars[c2] == PUNCT)
747cd4e76b8Sperry 					putchar(c2);
748cd4e76b8Sperry 				return;
749cd4e76b8Sperry 			}
750cd4e76b8Sperry 		}
751cd4e76b8Sperry 	}
752cd4e76b8Sperry }
753cd4e76b8Sperry 
75497ccbe26Schristos static void
inpic(void)755cd4e76b8Sperry inpic(void)
756cd4e76b8Sperry {
757cd4e76b8Sperry 	int c1;
758cd4e76b8Sperry 	char *p1;
759cd4e76b8Sperry 
760cd4e76b8Sperry 	SKIP;
761cd4e76b8Sperry 	p1 = line;
762cd4e76b8Sperry 	c = '\n';
763cd4e76b8Sperry 	for (;;) {
764cd4e76b8Sperry 		c1 = c;
765cd4e76b8Sperry 		if (C == '.' && c1 == '\n') {
766cd4e76b8Sperry 			if (C != 'P') {
767cd4e76b8Sperry 				if (c == '\n')
768cd4e76b8Sperry 					continue;
769cd4e76b8Sperry 				else {
770cd4e76b8Sperry 					SKIP;
771cd4e76b8Sperry 					c = '\n';
772cd4e76b8Sperry 					continue;
773cd4e76b8Sperry 				}
774cd4e76b8Sperry 			}
775cd4e76b8Sperry 			if (C != 'E') {
776cd4e76b8Sperry 				if (c == '\n')
777cd4e76b8Sperry 					continue;
778cd4e76b8Sperry 				else {
779cd4e76b8Sperry 					SKIP;
780cd4e76b8Sperry 					c = '\n';
781cd4e76b8Sperry 					continue;
782cd4e76b8Sperry 				}
783cd4e76b8Sperry 			}
784cd4e76b8Sperry 			SKIP;
785cd4e76b8Sperry 			return;
786cd4e76b8Sperry 		}
787cd4e76b8Sperry 		else if (c == '\"') {
788cd4e76b8Sperry 			while (C != '\"') {
789cd4e76b8Sperry 				if (c == '\\') {
790cd4e76b8Sperry 					if (C == '\"')
791cd4e76b8Sperry 						continue;
792cd4e76b8Sperry 					ungetc(c, infile);
793cd4e76b8Sperry 					backsl();
794cd4e76b8Sperry 				} else
795cd4e76b8Sperry 					*p1++ = c;
796cd4e76b8Sperry 			}
797cd4e76b8Sperry 			*p1++ = ' ';
798cd4e76b8Sperry 		}
799cd4e76b8Sperry 		else if (c == '\n' && p1 != line) {
800cd4e76b8Sperry 			*p1 = '\0';
801cd4e76b8Sperry 			if (wordflag)
802cd4e76b8Sperry 				msputwords(NO);
803cd4e76b8Sperry 			else {
804cd4e76b8Sperry 				puts(line);
805cd4e76b8Sperry 				putchar('\n');
806cd4e76b8Sperry 			}
807cd4e76b8Sperry 			p1 = line;
808cd4e76b8Sperry 		}
809cd4e76b8Sperry 	}
810cd4e76b8Sperry }
811cd4e76b8Sperry 
812cd4e76b8Sperry #ifdef DEBUG
81397ccbe26Schristos static int
_C1(void)814cd4e76b8Sperry _C1(void)
815cd4e76b8Sperry {
816cd4e76b8Sperry 
81767bd9cb7Swiz 	return C1get;
818cd4e76b8Sperry }
819cd4e76b8Sperry 
82097ccbe26Schristos static int
_C(void)821cd4e76b8Sperry _C(void)
822cd4e76b8Sperry {
823cd4e76b8Sperry 
82467bd9cb7Swiz 	return Cget;
825cd4e76b8Sperry }
826cd4e76b8Sperry #endif /* DEBUG */
827cd4e76b8Sperry 
828cd4e76b8Sperry /*
829cd4e76b8Sperry  *	Put out a macro line, using ms and mm conventions.
830cd4e76b8Sperry  */
83197ccbe26Schristos static void
msputmac(char * s,int constant)832cd4e76b8Sperry msputmac(char *s, int constant)
833cd4e76b8Sperry {
834cd4e76b8Sperry 	char *t;
835cd4e76b8Sperry 	int found;
836cd4e76b8Sperry 	int last;
837cd4e76b8Sperry 
838cd4e76b8Sperry 	last = 0;
839cd4e76b8Sperry 	found = 0;
840cd4e76b8Sperry 	if (wordflag) {
841cd4e76b8Sperry 		msputwords(YES);
842cd4e76b8Sperry 		return;
843cd4e76b8Sperry 	}
844cd4e76b8Sperry 	while (*s) {
845cd4e76b8Sperry 		while (*s == ' ' || *s == '\t')
846cd4e76b8Sperry 			putchar(*s++);
847cd4e76b8Sperry 		for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t)
848cd4e76b8Sperry 			;	/* nothing */
849cd4e76b8Sperry 		if (*s == '\"')
850cd4e76b8Sperry 			s++;
851cd4e76b8Sperry 		if (t > s + constant && chars[(unsigned char)s[0]] == LETTER &&
852cd4e76b8Sperry 		    chars[(unsigned char)s[1]] == LETTER) {
853cd4e76b8Sperry 			while (s < t)
854cd4e76b8Sperry 				if (*s == '\"')
855cd4e76b8Sperry 					s++;
856cd4e76b8Sperry 				else
857cd4e76b8Sperry 					putchar(*s++);
858cd4e76b8Sperry 			last = *(t-1);
859cd4e76b8Sperry 			found++;
860cd4e76b8Sperry 		} else if (found && chars[(unsigned char)s[0]] == PUNCT &&
861cd4e76b8Sperry 		    s[1] == '\0') {
862cd4e76b8Sperry 			putchar(*s++);
863cd4e76b8Sperry 		} else {
864cd4e76b8Sperry 			last = *(t - 1);
865cd4e76b8Sperry 			s = t;
866cd4e76b8Sperry 		}
867cd4e76b8Sperry 	}
868cd4e76b8Sperry 	putchar('\n');
869cd4e76b8Sperry 	if (msflag && chars[last] == PUNCT) {
870cd4e76b8Sperry 		putchar(last);
871cd4e76b8Sperry 		putchar('\n');
872cd4e76b8Sperry 	}
873cd4e76b8Sperry }
874cd4e76b8Sperry 
875cd4e76b8Sperry /*
876cd4e76b8Sperry  *	put out words (for the -w option) with ms and mm conventions
877cd4e76b8Sperry  */
87897ccbe26Schristos static void
msputwords(int macline)879cd4e76b8Sperry msputwords(int macline)
880cd4e76b8Sperry {
881cd4e76b8Sperry 	char *p, *p1;
882cd4e76b8Sperry 	int i, nlet;
883cd4e76b8Sperry 
884cd4e76b8Sperry 	for (p1 = line;;) {
885cd4e76b8Sperry 		/*
886cd4e76b8Sperry 		 *	skip initial specials ampersands and apostrophes
887cd4e76b8Sperry 		 */
888cd4e76b8Sperry 		while (chars[(unsigned char)*p1] < DIGIT)
889cd4e76b8Sperry 			if (*p1++ == '\0')
890cd4e76b8Sperry 				return;
891cd4e76b8Sperry 		nlet = 0;
892cd4e76b8Sperry 		for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p)
893cd4e76b8Sperry 			if (i == LETTER)
894cd4e76b8Sperry 				++nlet;
895cd4e76b8Sperry 
896cd4e76b8Sperry 		if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) {
897cd4e76b8Sperry 			/*
898cd4e76b8Sperry 			 *	delete trailing ampersands and apostrophes
899cd4e76b8Sperry 			 */
900cd4e76b8Sperry 			while ((i = chars[(unsigned char)p[-1]]) == PUNCT ||
901cd4e76b8Sperry 			    i == APOS )
902cd4e76b8Sperry 				--p;
903cd4e76b8Sperry 			while (p1 < p)
904cd4e76b8Sperry 				putchar(*p1++);
905cd4e76b8Sperry 			putchar('\n');
906cd4e76b8Sperry 		} else {
907cd4e76b8Sperry 			p1 = p;
908cd4e76b8Sperry 		}
909cd4e76b8Sperry 	}
910cd4e76b8Sperry }
911cd4e76b8Sperry 
912cd4e76b8Sperry /*
913cd4e76b8Sperry  *	put out a macro using the me conventions
914cd4e76b8Sperry  */
915cd4e76b8Sperry #define SKIPBLANK(cp)	while (*cp == ' ' || *cp == '\t') { cp++; }
916cd4e76b8Sperry #define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
917cd4e76b8Sperry 
91897ccbe26Schristos static void
meputmac(char * cp,int constant)919cd4e76b8Sperry meputmac(char *cp, int constant)
920cd4e76b8Sperry {
921cd4e76b8Sperry 	char	*np;
922cd4e76b8Sperry 	int	found;
923cd4e76b8Sperry 	int	argno;
924cd4e76b8Sperry 	int	last;
925cd4e76b8Sperry 	int	inquote;
926cd4e76b8Sperry 
927cd4e76b8Sperry 	last = 0;
928cd4e76b8Sperry 	found = 0;
929cd4e76b8Sperry 	if (wordflag) {
930cd4e76b8Sperry 		meputwords(YES);
931cd4e76b8Sperry 		return;
932cd4e76b8Sperry 	}
933cd4e76b8Sperry 	for (argno = 0; *cp; argno++) {
934cd4e76b8Sperry 		SKIPBLANK(cp);
935cd4e76b8Sperry 		inquote = (*cp == '"');
936cd4e76b8Sperry 		if (inquote)
937cd4e76b8Sperry 			cp++;
938cd4e76b8Sperry 		for (np = cp; *np; np++) {
939cd4e76b8Sperry 			switch (*np) {
940cd4e76b8Sperry 			case '\n':
941cd4e76b8Sperry 			case '\0':
942cd4e76b8Sperry 				break;
943cd4e76b8Sperry 
944cd4e76b8Sperry 			case '\t':
945cd4e76b8Sperry 			case ' ':
946cd4e76b8Sperry 				if (inquote)
947cd4e76b8Sperry 					continue;
948cd4e76b8Sperry 				else
949cd4e76b8Sperry 					goto endarg;
950cd4e76b8Sperry 
951cd4e76b8Sperry 			case '"':
952cd4e76b8Sperry 				if (inquote && np[1] == '"') {
953cd4e76b8Sperry 					memmove(np, np + 1, strlen(np));
954cd4e76b8Sperry 					np++;
955cd4e76b8Sperry 					continue;
956cd4e76b8Sperry 				} else {
957cd4e76b8Sperry 					*np = ' '; 	/* bye bye " */
958cd4e76b8Sperry 					goto endarg;
959cd4e76b8Sperry 				}
960cd4e76b8Sperry 
961cd4e76b8Sperry 			default:
962cd4e76b8Sperry 				continue;
963cd4e76b8Sperry 			}
964cd4e76b8Sperry 		}
965cd4e76b8Sperry 		endarg: ;
966cd4e76b8Sperry 		/*
967cd4e76b8Sperry 		 *	cp points at the first char in the arg
968cd4e76b8Sperry 		 *	np points one beyond the last char in the arg
969cd4e76b8Sperry 		 */
970cd4e76b8Sperry 		if ((argconcat == 0) || (argconcat != argno))
971cd4e76b8Sperry 			putchar(' ');
972cd4e76b8Sperry #ifdef FULLDEBUG
973cd4e76b8Sperry 		{
974cd4e76b8Sperry 			char	*p;
975cd4e76b8Sperry 			printf("[%d,%d: ", argno, np - cp);
976cd4e76b8Sperry 			for (p = cp; p < np; p++) {
977cd4e76b8Sperry 				putchar(*p);
978cd4e76b8Sperry 			}
979cd4e76b8Sperry 			printf("]");
980cd4e76b8Sperry 		}
981cd4e76b8Sperry #endif /* FULLDEBUG */
982cd4e76b8Sperry 		/*
983cd4e76b8Sperry 		 *	Determine if the argument merits being printed
984cd4e76b8Sperry 		 *
985cd4e76b8Sperry 		 *	constant is the cut off point below which something
986cd4e76b8Sperry 		 *	is not a word.
987cd4e76b8Sperry 		 */
988cd4e76b8Sperry 		if (((np - cp) > constant) &&
989cd4e76b8Sperry 		    (inquote || (chars[(unsigned char)cp[0]] == LETTER))) {
990118a5817Sjoerg 			for (; cp < np; cp++)
991cd4e76b8Sperry 				putchar(*cp);
992cd4e76b8Sperry 			last = np[-1];
993cd4e76b8Sperry 			found++;
994cd4e76b8Sperry 		} else if (found && (np - cp == 1) &&
995cd4e76b8Sperry 		    chars[(unsigned char)*cp] == PUNCT) {
996cd4e76b8Sperry 			putchar(*cp);
997cd4e76b8Sperry 		} else {
998cd4e76b8Sperry 			last = np[-1];
999cd4e76b8Sperry 		}
1000cd4e76b8Sperry 		cp = np;
1001cd4e76b8Sperry 	}
1002cd4e76b8Sperry 	if (msflag && chars[last] == PUNCT)
1003cd4e76b8Sperry 		putchar(last);
1004cd4e76b8Sperry 	putchar('\n');
1005cd4e76b8Sperry }
1006cd4e76b8Sperry 
1007cd4e76b8Sperry /*
1008cd4e76b8Sperry  *	put out words (for the -w option) with ms and mm conventions
1009cd4e76b8Sperry  */
101097ccbe26Schristos static void
meputwords(int macline)1011cd4e76b8Sperry meputwords(int macline)
1012cd4e76b8Sperry {
1013cd4e76b8Sperry 
1014cd4e76b8Sperry 	msputwords(macline);
1015cd4e76b8Sperry }
1016cd4e76b8Sperry 
1017cd4e76b8Sperry /*
1018cd4e76b8Sperry  *
1019cd4e76b8Sperry  *	Skip over a nested set of macros
1020cd4e76b8Sperry  *
1021cd4e76b8Sperry  *	Possible arguments to noblock are:
1022cd4e76b8Sperry  *
1023cd4e76b8Sperry  *	fi	end of unfilled text
1024cd4e76b8Sperry  *	PE	pic ending
1025cd4e76b8Sperry  *	DE	display ending
1026cd4e76b8Sperry  *
1027cd4e76b8Sperry  *	for ms and mm only:
1028cd4e76b8Sperry  *		KE	keep ending
1029cd4e76b8Sperry  *
1030cd4e76b8Sperry  *		NE	undocumented match to NS (for mm?)
1031cd4e76b8Sperry  *		LE	mm only: matches RL or *L (for lists)
1032cd4e76b8Sperry  *
1033cd4e76b8Sperry  *	for me:
1034cd4e76b8Sperry  *		([lqbzcdf]
1035cd4e76b8Sperry  */
103697ccbe26Schristos static void
noblock(char a1,char a2)1037cd4e76b8Sperry noblock(char a1, char a2)
1038cd4e76b8Sperry {
1039cd4e76b8Sperry 	int c1,c2;
1040cd4e76b8Sperry 	int eqnf;
1041cd4e76b8Sperry 	int lct;
1042cd4e76b8Sperry 
1043cd4e76b8Sperry 	lct = 0;
1044cd4e76b8Sperry 	eqnf = 1;
1045cd4e76b8Sperry 	SKIP;
1046cd4e76b8Sperry 	for (;;) {
1047cd4e76b8Sperry 		while (C != '.')
1048cd4e76b8Sperry 			if (c == '\n')
1049cd4e76b8Sperry 				continue;
1050cd4e76b8Sperry 			else
1051cd4e76b8Sperry 				SKIP;
1052cd4e76b8Sperry 		if ((c1 = C) == '\n')
1053cd4e76b8Sperry 			continue;
1054cd4e76b8Sperry 		if ((c2 = C) == '\n')
1055cd4e76b8Sperry 			continue;
1056cd4e76b8Sperry 		if (c1 == a1 && c2 == a2) {
1057cd4e76b8Sperry 			SKIP;
1058cd4e76b8Sperry 			if (lct != 0) {
1059cd4e76b8Sperry 				lct--;
1060cd4e76b8Sperry 				continue;
1061cd4e76b8Sperry 			}
1062cd4e76b8Sperry 			if (eqnf)
1063cd4e76b8Sperry 				putchar('.');
1064cd4e76b8Sperry 			putchar('\n');
1065cd4e76b8Sperry 			return;
1066cd4e76b8Sperry 		} else if (a1 == 'L' && c2 == 'L') {
1067cd4e76b8Sperry 			lct++;
1068cd4e76b8Sperry 			SKIP;
1069cd4e76b8Sperry 		}
1070cd4e76b8Sperry 		/*
1071cd4e76b8Sperry 		 *	equations (EQ) nested within a display
1072cd4e76b8Sperry 		 */
1073cd4e76b8Sperry 		else if (c1 == 'E' && c2 == 'Q') {
1074cd4e76b8Sperry 			if ((mac == ME && a1 == ')')
1075cd4e76b8Sperry 			    || (mac != ME && a1 == 'D')) {
1076cd4e76b8Sperry 				eqn();
1077cd4e76b8Sperry 				eqnf=0;
1078cd4e76b8Sperry 			}
1079cd4e76b8Sperry 		}
1080cd4e76b8Sperry 		/*
1081cd4e76b8Sperry 		 *	turning on filling is done by the paragraphing
1082cd4e76b8Sperry 		 *	macros
1083cd4e76b8Sperry 		 */
1084cd4e76b8Sperry 		else if (a1 == 'f') {	/* .fi */
1085cd4e76b8Sperry 			if  ((mac == ME && (c2 == 'h' || c2 == 'p'))
1086cd4e76b8Sperry 			    || (mac != ME && (c1 == 'P' || c2 == 'P'))) {
1087cd4e76b8Sperry 				SKIP;
1088cd4e76b8Sperry 				return;
1089cd4e76b8Sperry 			}
1090cd4e76b8Sperry 		} else {
1091cd4e76b8Sperry 			SKIP;
1092cd4e76b8Sperry 		}
1093cd4e76b8Sperry 	}
1094cd4e76b8Sperry }
1095cd4e76b8Sperry 
109697ccbe26Schristos static int
109797ccbe26Schristos /*ARGSUSED*/
EQ(pacmac unused)109897ccbe26Schristos EQ(pacmac unused)
1099cd4e76b8Sperry {
1100cd4e76b8Sperry 
1101cd4e76b8Sperry 	eqn();
110297ccbe26Schristos 	return 0;
1103cd4e76b8Sperry }
1104cd4e76b8Sperry 
110597ccbe26Schristos static int
110697ccbe26Schristos /*ARGSUSED*/
domacro(pacmac unused)110797ccbe26Schristos domacro(pacmac unused)
1108cd4e76b8Sperry {
1109cd4e76b8Sperry 
1110cd4e76b8Sperry 	macro();
111197ccbe26Schristos 	return 0;
1112cd4e76b8Sperry }
1113cd4e76b8Sperry 
111497ccbe26Schristos static int
111597ccbe26Schristos /*ARGSUSED*/
PS(pacmac unused)111697ccbe26Schristos PS(pacmac unused)
1117cd4e76b8Sperry {
1118cd4e76b8Sperry 
1119cd4e76b8Sperry 	for (C; c == ' ' || c == '\t'; C)
1120cd4e76b8Sperry 		;	/* nothing */
1121cd4e76b8Sperry 
1122cd4e76b8Sperry 	if (c == '<') {		/* ".PS < file" -- don't expect a .PE */
1123cd4e76b8Sperry 		SKIP;
112497ccbe26Schristos 		return 0;
1125cd4e76b8Sperry 	}
1126cd4e76b8Sperry 	if (!msflag)
1127cd4e76b8Sperry 		inpic();
1128cd4e76b8Sperry 	else
1129cd4e76b8Sperry 		noblock('P', 'E');
113097ccbe26Schristos 	return 0;
1131cd4e76b8Sperry }
1132cd4e76b8Sperry 
113397ccbe26Schristos static int
113497ccbe26Schristos /*ARGSUSED*/
skip(pacmac unused)113597ccbe26Schristos skip(pacmac unused)
1136cd4e76b8Sperry {
1137cd4e76b8Sperry 
1138cd4e76b8Sperry 	SKIP;
113997ccbe26Schristos 	return 0;
1140cd4e76b8Sperry }
1141cd4e76b8Sperry 
114297ccbe26Schristos static int
114397ccbe26Schristos /*ARGSUSED*/
intbl(pacmac unused)114497ccbe26Schristos intbl(pacmac unused)
1145cd4e76b8Sperry {
1146cd4e76b8Sperry 
1147cd4e76b8Sperry 	if (msflag)
1148cd4e76b8Sperry 		stbl();
1149cd4e76b8Sperry 	else
1150cd4e76b8Sperry 		tbl();
115197ccbe26Schristos 	return 0;
1152cd4e76b8Sperry }
1153cd4e76b8Sperry 
115497ccbe26Schristos static int
115597ccbe26Schristos /*ARGSUSED*/
outtbl(pacmac unused)115697ccbe26Schristos outtbl(pacmac unused)
1157cd4e76b8Sperry {
1158cd4e76b8Sperry 
1159cd4e76b8Sperry 	intable = NO;
116097ccbe26Schristos 	return 0;
1161cd4e76b8Sperry }
1162cd4e76b8Sperry 
11639d59054aSjoerg static int
116497ccbe26Schristos /*ARGSUSED*/
so(pacmac unused)116597ccbe26Schristos so(pacmac unused)
1166cd4e76b8Sperry {
1167cd4e76b8Sperry 
1168cd4e76b8Sperry 	if (!iflag) {
1169cd4e76b8Sperry 		getfname();
1170cd4e76b8Sperry 		if (fname[0]) {
1171cd4e76b8Sperry 			if (++filesp - &files[0] > MAXFILES)
1172cd4e76b8Sperry 				err(1, "too many nested files (max %d)",
1173cd4e76b8Sperry 				    MAXFILES);
1174cd4e76b8Sperry 			infile = *filesp = opn(fname);
1175cd4e76b8Sperry 		}
1176cd4e76b8Sperry 	}
117797ccbe26Schristos 	return 0;
1178cd4e76b8Sperry }
1179cd4e76b8Sperry 
118097ccbe26Schristos static int
118197ccbe26Schristos /*ARGSUSED*/
nx(pacmac unused)118297ccbe26Schristos nx(pacmac unused)
1183cd4e76b8Sperry {
1184cd4e76b8Sperry 
1185cd4e76b8Sperry 	if (!iflag) {
1186cd4e76b8Sperry 		getfname();
1187cd4e76b8Sperry 		if (fname[0] == '\0')
1188cd4e76b8Sperry 			exit(0);
1189cd4e76b8Sperry 		if (infile != stdin)
1190cd4e76b8Sperry 			fclose(infile);
1191cd4e76b8Sperry 		infile = *filesp = opn(fname);
1192cd4e76b8Sperry 	}
119397ccbe26Schristos 	return 0;
1194cd4e76b8Sperry }
1195cd4e76b8Sperry 
119697ccbe26Schristos static int
119797ccbe26Schristos /*ARGSUSED*/
skiptocom(pacmac unused)119897ccbe26Schristos skiptocom(pacmac unused)
1199cd4e76b8Sperry {
1200cd4e76b8Sperry 
1201cd4e76b8Sperry 	SKIP_TO_COM;
120297ccbe26Schristos 	return COMX;
1203cd4e76b8Sperry }
1204cd4e76b8Sperry 
120597ccbe26Schristos static int
PP(pacmac c12)1206cd4e76b8Sperry PP(pacmac c12)
1207cd4e76b8Sperry {
1208cd4e76b8Sperry 	int c1, c2;
1209cd4e76b8Sperry 
1210cd4e76b8Sperry 	frommac(c12, c1, c2);
1211cd4e76b8Sperry 	printf(".%c%c", c1, c2);
1212cd4e76b8Sperry 	while (C != '\n')
1213cd4e76b8Sperry 		putchar(c);
1214cd4e76b8Sperry 	putchar('\n');
121597ccbe26Schristos 	return 0;
1216cd4e76b8Sperry }
1217cd4e76b8Sperry 
121897ccbe26Schristos static int
121997ccbe26Schristos /*ARGSUSED*/
AU(pacmac unused)122097ccbe26Schristos AU(pacmac unused)
1221cd4e76b8Sperry {
1222cd4e76b8Sperry 
1223cd4e76b8Sperry 	if (mac == MM)
122497ccbe26Schristos 		return 0;
1225cd4e76b8Sperry 	SKIP_TO_COM;
122697ccbe26Schristos 	return COMX;
1227cd4e76b8Sperry }
1228cd4e76b8Sperry 
122997ccbe26Schristos static int
SH(pacmac c12)1230cd4e76b8Sperry SH(pacmac c12)
1231cd4e76b8Sperry {
1232cd4e76b8Sperry 	int c1, c2;
1233cd4e76b8Sperry 
1234cd4e76b8Sperry 	frommac(c12, c1, c2);
1235cd4e76b8Sperry 
1236cd4e76b8Sperry 	if (parag) {
1237cd4e76b8Sperry 		printf(".%c%c", c1, c2);
1238cd4e76b8Sperry 		while (C != '\n')
1239cd4e76b8Sperry 			putchar(c);
1240cd4e76b8Sperry 		putchar(c);
1241cd4e76b8Sperry 		putchar('!');
1242cd4e76b8Sperry 		for (;;) {
1243cd4e76b8Sperry 			while (C != '\n')
1244cd4e76b8Sperry 				putchar(c);
1245cd4e76b8Sperry 			putchar('\n');
1246cd4e76b8Sperry 			if (C == '.')
124797ccbe26Schristos 				return COM;
1248cd4e76b8Sperry 			putchar('!');
1249cd4e76b8Sperry 			putchar(c);
1250cd4e76b8Sperry 		}
1251cd4e76b8Sperry 		/*NOTREACHED*/
1252cd4e76b8Sperry 	} else {
1253cd4e76b8Sperry 		SKIP_TO_COM;
125497ccbe26Schristos 		return COMX;
1255cd4e76b8Sperry 	}
1256cd4e76b8Sperry }
1257cd4e76b8Sperry 
125897ccbe26Schristos static int
125997ccbe26Schristos /*ARGSUSED*/
UX(pacmac unused)126097ccbe26Schristos UX(pacmac unused)
1261cd4e76b8Sperry {
1262cd4e76b8Sperry 
1263cd4e76b8Sperry 	if (wordflag)
1264cd4e76b8Sperry 		printf("UNIX\n");
1265cd4e76b8Sperry 	else
1266cd4e76b8Sperry 		printf("UNIX ");
126797ccbe26Schristos 	return 0;
1268cd4e76b8Sperry }
1269cd4e76b8Sperry 
127097ccbe26Schristos static int
MMHU(pacmac c12)1271cd4e76b8Sperry MMHU(pacmac c12)
1272cd4e76b8Sperry {
1273cd4e76b8Sperry 	int c1, c2;
1274cd4e76b8Sperry 
1275cd4e76b8Sperry 	frommac(c12, c1, c2);
1276cd4e76b8Sperry 	if (parag) {
1277cd4e76b8Sperry 		printf(".%c%c", c1, c2);
1278cd4e76b8Sperry 		while (C != '\n')
1279cd4e76b8Sperry 			putchar(c);
1280cd4e76b8Sperry 		putchar('\n');
1281cd4e76b8Sperry 	} else {
1282cd4e76b8Sperry 		SKIP;
1283cd4e76b8Sperry 	}
128497ccbe26Schristos 	return 0;
1285cd4e76b8Sperry }
1286cd4e76b8Sperry 
128797ccbe26Schristos static int
mesnblock(pacmac c12)1288cd4e76b8Sperry mesnblock(pacmac c12)
1289cd4e76b8Sperry {
1290cd4e76b8Sperry 	int c1, c2;
1291cd4e76b8Sperry 
1292cd4e76b8Sperry 	frommac(c12, c1, c2);
1293cd4e76b8Sperry 	noblock(')', c2);
129497ccbe26Schristos 	return 0;
1295cd4e76b8Sperry }
1296cd4e76b8Sperry 
129797ccbe26Schristos static int
mssnblock(pacmac c12)1298cd4e76b8Sperry mssnblock(pacmac c12)
1299cd4e76b8Sperry {
1300cd4e76b8Sperry 	int c1, c2;
1301cd4e76b8Sperry 
1302cd4e76b8Sperry 	frommac(c12, c1, c2);
1303cd4e76b8Sperry 	noblock(c1, 'E');
130497ccbe26Schristos 	return 0;
1305cd4e76b8Sperry }
1306cd4e76b8Sperry 
130797ccbe26Schristos static int
130897ccbe26Schristos /*ARGUSED*/
nf(pacmac unused)130997ccbe26Schristos nf(pacmac unused)
1310cd4e76b8Sperry {
1311cd4e76b8Sperry 
1312cd4e76b8Sperry 	noblock('f', 'i');
131397ccbe26Schristos 	return 0;
1314cd4e76b8Sperry }
1315cd4e76b8Sperry 
131697ccbe26Schristos static int
131797ccbe26Schristos /*ARGUSED*/
ce(pacmac unused)131897ccbe26Schristos ce(pacmac unused)
1319cd4e76b8Sperry {
1320cd4e76b8Sperry 
1321cd4e76b8Sperry 	sce();
132297ccbe26Schristos 	return 0;
1323cd4e76b8Sperry }
1324cd4e76b8Sperry 
132597ccbe26Schristos static int
meip(pacmac c12)1326cd4e76b8Sperry meip(pacmac c12)
1327cd4e76b8Sperry {
1328cd4e76b8Sperry 
1329cd4e76b8Sperry 	if (parag)
1330cd4e76b8Sperry 		mepp(c12);
1331cd4e76b8Sperry 	else if (wordflag)	/* save the tag */
1332cd4e76b8Sperry 		regline(meputmac, ONE);
1333cd4e76b8Sperry 	else
1334cd4e76b8Sperry 		SKIP;
133597ccbe26Schristos 	return 0;
1336cd4e76b8Sperry }
1337cd4e76b8Sperry 
1338cd4e76b8Sperry /*
1339cd4e76b8Sperry  *	only called for -me .pp or .sh, when parag is on
1340cd4e76b8Sperry  */
134197ccbe26Schristos static int
mepp(pacmac c12)1342cd4e76b8Sperry mepp(pacmac c12)
1343cd4e76b8Sperry {
1344cd4e76b8Sperry 
1345cd4e76b8Sperry 	PP(c12);		/* eats the line */
134697ccbe26Schristos 	return 0;
1347cd4e76b8Sperry }
1348cd4e76b8Sperry 
1349cd4e76b8Sperry /*
1350cd4e76b8Sperry  *	Start of a section heading; output the section name if doing words
1351cd4e76b8Sperry  */
135297ccbe26Schristos static int
mesh(pacmac c12)1353cd4e76b8Sperry mesh(pacmac c12)
1354cd4e76b8Sperry {
1355cd4e76b8Sperry 
1356cd4e76b8Sperry 	if (parag)
1357cd4e76b8Sperry 		mepp(c12);
1358cd4e76b8Sperry 	else if (wordflag)
1359cd4e76b8Sperry 		defcomline(c12);
1360cd4e76b8Sperry 	else
1361cd4e76b8Sperry 		SKIP;
136297ccbe26Schristos 	return 0;
1363cd4e76b8Sperry }
1364cd4e76b8Sperry 
1365cd4e76b8Sperry /*
1366cd4e76b8Sperry  *	process a font setting
1367cd4e76b8Sperry  */
136897ccbe26Schristos static int
mefont(pacmac c12)1369cd4e76b8Sperry mefont(pacmac c12)
1370cd4e76b8Sperry {
1371cd4e76b8Sperry 
1372cd4e76b8Sperry 	argconcat = 1;
1373cd4e76b8Sperry 	defcomline(c12);
1374cd4e76b8Sperry 	argconcat = 0;
137597ccbe26Schristos 	return 0;
1376cd4e76b8Sperry }
1377cd4e76b8Sperry 
137897ccbe26Schristos static int
manfont(pacmac c12)1379cd4e76b8Sperry manfont(pacmac c12)
1380cd4e76b8Sperry {
1381cd4e76b8Sperry 
138297ccbe26Schristos 	return mefont(c12);
1383cd4e76b8Sperry }
1384cd4e76b8Sperry 
138597ccbe26Schristos static int
manpp(pacmac c12)1386cd4e76b8Sperry manpp(pacmac c12)
1387cd4e76b8Sperry {
1388cd4e76b8Sperry 
138997ccbe26Schristos 	return mepp(c12);
1390cd4e76b8Sperry }
1391cd4e76b8Sperry 
139297ccbe26Schristos static void
defcomline(pacmac c12)1393cd4e76b8Sperry defcomline(pacmac c12)
1394cd4e76b8Sperry {
1395cd4e76b8Sperry 	int c1, c2;
1396cd4e76b8Sperry 
1397cd4e76b8Sperry 	frommac(c12, c1, c2);
1398cd4e76b8Sperry 	if (msflag && mac == MM && c2 == 'L') {
1399cd4e76b8Sperry 		if (disp || c1 == 'R') {
1400cd4e76b8Sperry 			noblock('L', 'E');
1401cd4e76b8Sperry 		} else {
1402cd4e76b8Sperry 			SKIP;
1403cd4e76b8Sperry 			putchar('.');
1404cd4e76b8Sperry 		}
1405cd4e76b8Sperry 	}
1406cd4e76b8Sperry 	else if (c1 == '.' && c2 == '.') {
1407cd4e76b8Sperry 		if (msflag) {
1408cd4e76b8Sperry 			SKIP;
1409cd4e76b8Sperry 			return;
1410cd4e76b8Sperry 		}
1411cd4e76b8Sperry 		while (C == '.')
1412cd4e76b8Sperry 			/*VOID*/;
1413cd4e76b8Sperry 	}
1414cd4e76b8Sperry 	++inmacro;
1415cd4e76b8Sperry 	/*
1416cd4e76b8Sperry 	 *	Process the arguments to the macro
1417cd4e76b8Sperry 	 */
1418cd4e76b8Sperry 	switch (mac) {
1419cd4e76b8Sperry 	default:
1420cd4e76b8Sperry 	case MM:
1421cd4e76b8Sperry 	case MS:
1422cd4e76b8Sperry 		if (c1 <= 'Z' && msflag)
1423cd4e76b8Sperry 			regline(msputmac, ONE);
1424cd4e76b8Sperry 		else
1425cd4e76b8Sperry 			regline(msputmac, TWO);
1426cd4e76b8Sperry 		break;
1427cd4e76b8Sperry 	case ME:
1428cd4e76b8Sperry 		regline(meputmac, ONE);
1429cd4e76b8Sperry 		break;
1430cd4e76b8Sperry 	}
1431cd4e76b8Sperry 	--inmacro;
1432cd4e76b8Sperry }
1433cd4e76b8Sperry 
143497ccbe26Schristos static void
comline(void)1435cd4e76b8Sperry comline(void)
1436cd4e76b8Sperry {
1437cd4e76b8Sperry 	int	c1;
1438cd4e76b8Sperry 	int	c2;
1439cd4e76b8Sperry 	pacmac	c12;
1440cd4e76b8Sperry 	int	mid;
1441cd4e76b8Sperry 	int	lb, ub;
1442cd4e76b8Sperry 	int	hit;
1443cd4e76b8Sperry 	static	int	tabsize = 0;
144497ccbe26Schristos 	static	const struct mactab	*mactab = NULL;
144597ccbe26Schristos 	const struct mactab	*mp;
1446cd4e76b8Sperry 
1447cd4e76b8Sperry 	if (mactab == 0)
1448cd4e76b8Sperry 		 buildtab(&mactab, &tabsize);
1449cd4e76b8Sperry com:
1450cd4e76b8Sperry 	while (C == ' ' || c == '\t')
1451cd4e76b8Sperry 		;
1452cd4e76b8Sperry comx:
1453cd4e76b8Sperry 	if ((c1 = c) == '\n')
1454cd4e76b8Sperry 		return;
1455cd4e76b8Sperry 	c2 = C;
1456cd4e76b8Sperry 	if (c1 == '.' && c2 != '.')
1457cd4e76b8Sperry 		inmacro = NO;
1458cd4e76b8Sperry 	if (msflag && c1 == '[') {
1459cd4e76b8Sperry 		refer(c2);
1460cd4e76b8Sperry 		return;
1461cd4e76b8Sperry 	}
1462cd4e76b8Sperry 	if (parag && mac==MM && c1 == 'P' && c2 == '\n') {
1463cd4e76b8Sperry 		printf(".P\n");
1464cd4e76b8Sperry 		return;
1465cd4e76b8Sperry 	}
1466cd4e76b8Sperry 	if (c2 == '\n')
1467cd4e76b8Sperry 		return;
1468cd4e76b8Sperry 	/*
1469cd4e76b8Sperry 	 *	Single letter macro
1470cd4e76b8Sperry 	 */
1471cd4e76b8Sperry 	if (mac == ME && (c2 == ' ' || c2 == '\t') )
1472cd4e76b8Sperry 		c2 = ' ';
1473cd4e76b8Sperry 	c12 = tomac(c1, c2);
1474cd4e76b8Sperry 	/*
1475cd4e76b8Sperry 	 *	binary search through the table of macros
1476cd4e76b8Sperry 	 */
1477cd4e76b8Sperry 	lb = 0;
1478cd4e76b8Sperry 	ub = tabsize - 1;
1479cd4e76b8Sperry 	while (lb <= ub) {
1480cd4e76b8Sperry 		mid = (ub + lb) / 2;
1481cd4e76b8Sperry 		mp = &mactab[mid];
1482cd4e76b8Sperry 		if (mp->macname < c12)
1483cd4e76b8Sperry 			lb = mid + 1;
1484cd4e76b8Sperry 		else if (mp->macname > c12)
1485cd4e76b8Sperry 			ub = mid - 1;
1486cd4e76b8Sperry 		else {
1487cd4e76b8Sperry 			hit = 1;
1488cd4e76b8Sperry #ifdef FULLDEBUG
1489cd4e76b8Sperry 			printf("preliminary hit macro %c%c ", c1, c2);
1490cd4e76b8Sperry #endif /* FULLDEBUG */
1491cd4e76b8Sperry 			switch (mp->condition) {
1492cd4e76b8Sperry 			case NONE:
1493cd4e76b8Sperry 				hit = YES;
1494cd4e76b8Sperry 				break;
1495cd4e76b8Sperry 			case FNEST:
1496cd4e76b8Sperry 				hit = (filesp == files);
1497cd4e76b8Sperry 				break;
1498cd4e76b8Sperry 			case NOMAC:
1499cd4e76b8Sperry 				hit = !inmacro;
1500cd4e76b8Sperry 				break;
1501cd4e76b8Sperry 			case MAC:
1502cd4e76b8Sperry 				hit = inmacro;
1503cd4e76b8Sperry 				break;
1504cd4e76b8Sperry 			case PARAG:
1505cd4e76b8Sperry 				hit = parag;
1506cd4e76b8Sperry 				break;
1507cd4e76b8Sperry 			case NBLK:
1508cd4e76b8Sperry 				hit = !keepblock;
1509cd4e76b8Sperry 				break;
1510cd4e76b8Sperry 			default:
1511cd4e76b8Sperry 				hit = 0;
1512cd4e76b8Sperry 			}
1513cd4e76b8Sperry 
1514cd4e76b8Sperry 			if (hit) {
1515cd4e76b8Sperry #ifdef FULLDEBUG
1516cd4e76b8Sperry 				printf("MATCH\n");
1517cd4e76b8Sperry #endif /* FULLDEBUG */
1518cd4e76b8Sperry 				switch ((*(mp->func))(c12)) {
1519cd4e76b8Sperry 				default:
1520cd4e76b8Sperry 					return;
1521cd4e76b8Sperry 				case COMX:
1522cd4e76b8Sperry 					goto comx;
1523cd4e76b8Sperry 				case COM:
1524cd4e76b8Sperry 					goto com;
1525cd4e76b8Sperry 				}
1526cd4e76b8Sperry 			}
1527cd4e76b8Sperry #ifdef FULLDEBUG
1528cd4e76b8Sperry 			printf("FAIL\n");
1529cd4e76b8Sperry #endif /* FULLDEBUG */
1530cd4e76b8Sperry 			break;
1531cd4e76b8Sperry 		}
1532cd4e76b8Sperry 	}
1533cd4e76b8Sperry 	defcomline(c12);
1534cd4e76b8Sperry }
1535cd4e76b8Sperry 
153697ccbe26Schristos static int
macsort(const void * p1,const void * p2)1537cd4e76b8Sperry macsort(const void *p1, const void *p2)
1538cd4e76b8Sperry {
153997ccbe26Schristos 	const struct mactab *t1 = p1;
154097ccbe26Schristos 	const struct mactab *t2 = p2;
1541cd4e76b8Sperry 
154297ccbe26Schristos 	return t1->macname - t2->macname;
1543cd4e76b8Sperry }
1544cd4e76b8Sperry 
154597ccbe26Schristos static int
sizetab(const struct mactab * mp)154697ccbe26Schristos sizetab(const struct mactab *mp)
1547cd4e76b8Sperry {
1548cd4e76b8Sperry 	int i;
1549cd4e76b8Sperry 
1550cd4e76b8Sperry 	i = 0;
1551cd4e76b8Sperry 	if (mp) {
1552cd4e76b8Sperry 		for (; mp->macname; mp++, i++)
1553cd4e76b8Sperry 			/*VOID*/ ;
1554cd4e76b8Sperry 	}
155597ccbe26Schristos 	return i;
1556cd4e76b8Sperry }
1557cd4e76b8Sperry 
155897ccbe26Schristos static struct mactab *
macfill(struct mactab * dst,const struct mactab * src)155997ccbe26Schristos macfill(struct mactab *dst, const struct mactab *src)
1560cd4e76b8Sperry {
1561cd4e76b8Sperry 
1562cd4e76b8Sperry 	if (src) {
1563cd4e76b8Sperry 		while (src->macname)
1564cd4e76b8Sperry 			*dst++ = *src++;
1565cd4e76b8Sperry 	}
156697ccbe26Schristos 	return dst;
1567cd4e76b8Sperry }
1568cd4e76b8Sperry 
156997ccbe26Schristos static void
usage(void)1570cd4e76b8Sperry usage(void)
1571cd4e76b8Sperry {
1572cd4e76b8Sperry 	extern char *__progname;
1573cd4e76b8Sperry 
1574d3a0b4c8Swiz 	fprintf(stderr, "usage: %s [-ikpw ] [ -m a | e | l | m | s] [file ...]\n", __progname);
1575cd4e76b8Sperry 	exit(1);
1576cd4e76b8Sperry }
1577cd4e76b8Sperry 
157897ccbe26Schristos static void
buildtab(const struct mactab ** r_back,int * r_size)157997ccbe26Schristos buildtab(const struct mactab **r_back, int *r_size)
1580cd4e76b8Sperry {
158197ccbe26Schristos 	size_t	size;
158297ccbe26Schristos 	const struct	mactab	*p1, *p2;
158397ccbe26Schristos 	struct	mactab	*back, *p;
1584cd4e76b8Sperry 
1585cd4e76b8Sperry 	size = sizetab(troffmactab) + sizetab(ppmactab);
1586cd4e76b8Sperry 	p1 = p2 = NULL;
1587cd4e76b8Sperry 	if (msflag) {
1588cd4e76b8Sperry 		switch (mac) {
1589cd4e76b8Sperry 		case ME:
1590cd4e76b8Sperry 			p1 = memactab;
1591cd4e76b8Sperry 			break;
1592cd4e76b8Sperry 		case MM:
1593cd4e76b8Sperry 			p1 = msmactab;
1594cd4e76b8Sperry 			p2 = mmmactab;
1595cd4e76b8Sperry 			break;
1596cd4e76b8Sperry 		case MS:
1597cd4e76b8Sperry 			p1 = msmactab;
1598cd4e76b8Sperry 			break;
1599cd4e76b8Sperry 		case MA:
1600cd4e76b8Sperry 			p1 = manmactab;
1601cd4e76b8Sperry 			break;
1602cd4e76b8Sperry 		default:
1603cd4e76b8Sperry 			break;
1604cd4e76b8Sperry 		}
1605cd4e76b8Sperry 	}
1606cd4e76b8Sperry 	size += sizetab(p1);
1607cd4e76b8Sperry 	size += sizetab(p2);
160897ccbe26Schristos 	back = calloc(size + 2, sizeof(struct mactab));
1609cd4e76b8Sperry 	if (back == NULL)
1610cd4e76b8Sperry 		err(1, NULL);
1611cd4e76b8Sperry 
1612cd4e76b8Sperry 	p = macfill(back, troffmactab);
1613cd4e76b8Sperry 	p = macfill(p, ppmactab);
1614cd4e76b8Sperry 	p = macfill(p, p1);
1615cd4e76b8Sperry 	p = macfill(p, p2);
1616cd4e76b8Sperry 
1617cd4e76b8Sperry 	qsort(back, size, sizeof(struct mactab), macsort);
1618cd4e76b8Sperry 	*r_size = size;
1619cd4e76b8Sperry 	*r_back = back;
1620cd4e76b8Sperry }
1621cd4e76b8Sperry 
1622cd4e76b8Sperry /*
1623cd4e76b8Sperry  *	troff commands
1624cd4e76b8Sperry  */
162597ccbe26Schristos static const struct mactab	troffmactab[] = {
1626cd4e76b8Sperry 	M(NONE,		'\\','"',	skip),	/* comment */
1627cd4e76b8Sperry 	M(NOMAC,	'd','e',	domacro),	/* define */
1628cd4e76b8Sperry 	M(NOMAC,	'i','g',	domacro),	/* ignore till .. */
1629cd4e76b8Sperry 	M(NOMAC,	'a','m',	domacro),	/* append macro */
1630cd4e76b8Sperry 	M(NBLK,		'n','f',	nf),	/* filled */
1631cd4e76b8Sperry 	M(NBLK,		'c','e',	ce),	/* centered */
1632cd4e76b8Sperry 
1633cd4e76b8Sperry 	M(NONE,		's','o',	so),	/* source a file */
1634cd4e76b8Sperry 	M(NONE,		'n','x',	nx),	/* go to next file */
1635cd4e76b8Sperry 
1636cd4e76b8Sperry 	M(NONE,		't','m',	skip),	/* print string on tty */
1637cd4e76b8Sperry 	M(NONE,		'h','w',	skip),	/* exception hyphen words */
1638cd4e76b8Sperry 	M(NONE,		0,0,		0)
1639cd4e76b8Sperry };
1640cd4e76b8Sperry 
1641cd4e76b8Sperry /*
1642cd4e76b8Sperry  *	Preprocessor output
1643cd4e76b8Sperry  */
164497ccbe26Schristos static const struct mactab	ppmactab[] = {
1645cd4e76b8Sperry 	M(FNEST,	'E','Q',	EQ),	/* equation starting */
1646cd4e76b8Sperry 	M(FNEST,	'T','S',	intbl),	/* table starting */
1647cd4e76b8Sperry 	M(FNEST,	'T','C',	intbl),	/* alternative table? */
1648cd4e76b8Sperry 	M(FNEST,	'T','&',	intbl),	/* table reformatting */
1649cd4e76b8Sperry 	M(NONE,		'T','E',	outtbl),/* table ending */
1650cd4e76b8Sperry 	M(NONE,		'P','S',	PS),	/* picture starting */
1651cd4e76b8Sperry 	M(NONE,		0,0,		0)
1652cd4e76b8Sperry };
1653cd4e76b8Sperry 
1654cd4e76b8Sperry /*
1655cd4e76b8Sperry  *	Particular to ms and mm
1656cd4e76b8Sperry  */
165797ccbe26Schristos static const struct mactab	msmactab[] = {
1658cd4e76b8Sperry 	M(NONE,		'T','L',	skiptocom),	/* title follows */
1659cd4e76b8Sperry 	M(NONE,		'F','S',	skiptocom),	/* start footnote */
1660cd4e76b8Sperry 	M(NONE,		'O','K',	skiptocom),	/* Other kws */
1661cd4e76b8Sperry 
1662cd4e76b8Sperry 	M(NONE,		'N','R',	skip),	/* undocumented */
1663cd4e76b8Sperry 	M(NONE,		'N','D',	skip),	/* use supplied date */
1664cd4e76b8Sperry 
1665cd4e76b8Sperry 	M(PARAG,	'P','P',	PP),	/* begin parag */
1666cd4e76b8Sperry 	M(PARAG,	'I','P',	PP),	/* begin indent parag, tag x */
1667cd4e76b8Sperry 	M(PARAG,	'L','P',	PP),	/* left blocked parag */
1668cd4e76b8Sperry 
1669cd4e76b8Sperry 	M(NONE,		'A','U',	AU),	/* author */
1670cd4e76b8Sperry 	M(NONE,		'A','I',	AU),	/* authors institution */
1671cd4e76b8Sperry 
1672cd4e76b8Sperry 	M(NONE,		'S','H',	SH),	/* section heading */
1673cd4e76b8Sperry 	M(NONE,		'S','N',	SH),	/* undocumented */
1674cd4e76b8Sperry 	M(NONE,		'U','X',	UX),	/* unix */
1675cd4e76b8Sperry 
1676cd4e76b8Sperry 	M(NBLK,		'D','S',	mssnblock),	/* start display text */
1677cd4e76b8Sperry 	M(NBLK,		'K','S',	mssnblock),	/* start keep */
1678cd4e76b8Sperry 	M(NBLK,		'K','F',	mssnblock),	/* start float keep */
1679cd4e76b8Sperry 	M(NONE,		0,0,		0)
1680cd4e76b8Sperry };
1681cd4e76b8Sperry 
168297ccbe26Schristos static const struct mactab	mmmactab[] = {
1683cd4e76b8Sperry 	M(NONE,		'H',' ',	MMHU),	/* -mm ? */
1684cd4e76b8Sperry 	M(NONE,		'H','U',	MMHU),	/* -mm ? */
1685cd4e76b8Sperry 	M(PARAG,	'P',' ',	PP),	/* paragraph for -mm */
1686cd4e76b8Sperry 	M(NBLK,		'N','S',	mssnblock),	/* undocumented */
1687cd4e76b8Sperry 	M(NONE,		0,0,		0)
1688cd4e76b8Sperry };
1689cd4e76b8Sperry 
169097ccbe26Schristos static const struct mactab	memactab[] = {
1691cd4e76b8Sperry 	M(PARAG,	'p','p',	mepp),
1692cd4e76b8Sperry 	M(PARAG,	'l','p',	mepp),
1693cd4e76b8Sperry 	M(PARAG,	'n','p',	mepp),
1694cd4e76b8Sperry 	M(NONE,		'i','p',	meip),
1695cd4e76b8Sperry 
1696cd4e76b8Sperry 	M(NONE,		's','h',	mesh),
1697cd4e76b8Sperry 	M(NONE,		'u','h',	mesh),
1698cd4e76b8Sperry 
1699cd4e76b8Sperry 	M(NBLK,		'(','l',	mesnblock),
1700cd4e76b8Sperry 	M(NBLK,		'(','q',	mesnblock),
1701cd4e76b8Sperry 	M(NBLK,		'(','b',	mesnblock),
1702cd4e76b8Sperry 	M(NBLK,		'(','z',	mesnblock),
1703cd4e76b8Sperry 	M(NBLK,		'(','c',	mesnblock),
1704cd4e76b8Sperry 
1705cd4e76b8Sperry 	M(NBLK,		'(','d',	mesnblock),
1706cd4e76b8Sperry 	M(NBLK,		'(','f',	mesnblock),
1707cd4e76b8Sperry 	M(NBLK,		'(','x',	mesnblock),
1708cd4e76b8Sperry 
1709cd4e76b8Sperry 	M(NONE,		'r',' ',	mefont),
1710cd4e76b8Sperry 	M(NONE,		'i',' ',	mefont),
1711cd4e76b8Sperry 	M(NONE,		'b',' ',	mefont),
1712cd4e76b8Sperry 	M(NONE,		'u',' ',	mefont),
1713cd4e76b8Sperry 	M(NONE,		'q',' ',	mefont),
1714cd4e76b8Sperry 	M(NONE,		'r','b',	mefont),
1715cd4e76b8Sperry 	M(NONE,		'b','i',	mefont),
1716cd4e76b8Sperry 	M(NONE,		'b','x',	mefont),
1717cd4e76b8Sperry 	M(NONE,		0,0,		0)
1718cd4e76b8Sperry };
1719cd4e76b8Sperry 
172097ccbe26Schristos static const struct mactab	manmactab[] = {
1721cd4e76b8Sperry 	M(PARAG,	'B','I',	manfont),
1722cd4e76b8Sperry 	M(PARAG,	'B','R',	manfont),
1723cd4e76b8Sperry 	M(PARAG,	'I','B',	manfont),
1724cd4e76b8Sperry 	M(PARAG,	'I','R',	manfont),
1725cd4e76b8Sperry 	M(PARAG,	'R','B',	manfont),
1726cd4e76b8Sperry 	M(PARAG,	'R','I',	manfont),
1727cd4e76b8Sperry 
1728cd4e76b8Sperry 	M(PARAG,	'P','P',	manpp),
1729cd4e76b8Sperry 	M(PARAG,	'L','P',	manpp),
1730cd4e76b8Sperry 	M(PARAG,	'H','P',	manpp),
1731cd4e76b8Sperry 	M(NONE,		0,0,		0)
1732cd4e76b8Sperry };
1733