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