xref: /onnv-gate/usr/src/cmd/deroff/deroff.c (revision 381:1a7f0e46092a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
27*381Smuffin /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*381Smuffin /*	  All Rights Reserved  	*/
29*381Smuffin 
300Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <assert.h>
330Sstevel@tonic-gate #include <errno.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <locale.h>
380Sstevel@tonic-gate #include <sys/varargs.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * Deroff command -- strip troff, eqn, and Tbl sequences from a file.
420Sstevel@tonic-gate  * Has three flags argument, -w, to cause output one word per line
430Sstevel@tonic-gate  * rather than in the original format.
440Sstevel@tonic-gate  * -mm (or -ms) causes the corresponding macro's to be interpreted
450Sstevel@tonic-gate  * so that just sentences are output
460Sstevel@tonic-gate  * -ml  also gets rid of lists.
470Sstevel@tonic-gate  * -i causes deroff to ignore .so and .nx commands.
480Sstevel@tonic-gate  * Deroff follows .so and .nx commands, removes contents of macro
490Sstevel@tonic-gate  * definitions, equations (both .EQ ... .EN and $...$),
500Sstevel@tonic-gate  * Tbl command sequences, and Troff backslash constructions.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * All input is through the C macro; the most recently read character
530Sstevel@tonic-gate  * is in c.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	C	((c = getc(infile)) == EOF ? eof() : \
570Sstevel@tonic-gate 		    ((c == ldelim) && (filesp == files) ? skeqn() : c))
580Sstevel@tonic-gate #define	C1	((c = getc(infile)) == EOF ? eof() : c)
590Sstevel@tonic-gate #define	SKIP	while (C != '\n')
600Sstevel@tonic-gate #define	SKIP_TO_COM	SKIP; SKIP; pc = c; \
610Sstevel@tonic-gate 			while ((C != '.') || (pc != '\n') || \
620Sstevel@tonic-gate 			    (C > 'Z')) { \
630Sstevel@tonic-gate 				pc = c; \
640Sstevel@tonic-gate 			}
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #define	YES 1
670Sstevel@tonic-gate #define	NO 0
680Sstevel@tonic-gate #define	MS 0
690Sstevel@tonic-gate #define	MM 1
700Sstevel@tonic-gate #define	ONE 1
710Sstevel@tonic-gate #define	TWO 2
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #define	NOCHAR -2
740Sstevel@tonic-gate #define	SPECIAL 0
750Sstevel@tonic-gate #define	APOS 1
760Sstevel@tonic-gate #define	DIGIT 2
770Sstevel@tonic-gate #define	LETTER 3
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #define	MAXLINESZ	512
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static int wordflag = NO;
820Sstevel@tonic-gate static int msflag = NO;
830Sstevel@tonic-gate static int iflag = NO;
840Sstevel@tonic-gate static int mac = MM;
850Sstevel@tonic-gate static int disp = 0;
860Sstevel@tonic-gate static int inmacro = NO;
870Sstevel@tonic-gate static int intable = NO;
880Sstevel@tonic-gate static int lindx;
890Sstevel@tonic-gate static size_t linesize = MAXLINESZ;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static char chars[128];  /* SPECIAL, APOS, DIGIT, or LETTER */
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static char *line = NULL;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static char c;
960Sstevel@tonic-gate static int pc;
970Sstevel@tonic-gate static int ldelim	= NOCHAR;
980Sstevel@tonic-gate static int rdelim	= NOCHAR;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate static int argc;
1010Sstevel@tonic-gate static char **argv;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate extern int optind;
1040Sstevel@tonic-gate extern char *optarg;
1050Sstevel@tonic-gate static char fname[50];
1060Sstevel@tonic-gate static FILE *files[15];
1070Sstevel@tonic-gate static FILE **filesp;
1080Sstevel@tonic-gate static FILE *infile;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate static void backsl(void);
1110Sstevel@tonic-gate static void comline(void);
1120Sstevel@tonic-gate static char *copys(char *);
1130Sstevel@tonic-gate static int eof(void);
1140Sstevel@tonic-gate static void eqn(void);
1150Sstevel@tonic-gate static void fatal(const char *, ...);
1160Sstevel@tonic-gate static void fatal_msg(char *);
1170Sstevel@tonic-gate static void getfname(void);
1180Sstevel@tonic-gate static void macro(void);
1190Sstevel@tonic-gate static FILE *opn(char *);
1200Sstevel@tonic-gate static void putmac(char *, int);
1210Sstevel@tonic-gate static void putwords(int);
1220Sstevel@tonic-gate static void regline(int, int);
1230Sstevel@tonic-gate static void sce(void);
124*381Smuffin static int skeqn(void);
1250Sstevel@tonic-gate static void sdis(char, char);
1260Sstevel@tonic-gate static void stbl(void);
1270Sstevel@tonic-gate static void tbl(void);
1280Sstevel@tonic-gate static void usage(void);
129*381Smuffin static void work(void)	__NORETURN;
1300Sstevel@tonic-gate 
131*381Smuffin int
main(int ac,char ** av)1320Sstevel@tonic-gate main(int ac, char **av)
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	int i;
1350Sstevel@tonic-gate 	int errflg = 0;
1360Sstevel@tonic-gate 	int optchar;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1390Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1400Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
1410Sstevel@tonic-gate #endif
1420Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1430Sstevel@tonic-gate 	argc = ac;
1440Sstevel@tonic-gate 	argv = av;
1450Sstevel@tonic-gate 	while ((optchar = getopt(argc, argv, "wim:")) != EOF) {
1460Sstevel@tonic-gate 		switch (optchar) {
1470Sstevel@tonic-gate 		case 'w':
1480Sstevel@tonic-gate 			wordflag = YES;
1490Sstevel@tonic-gate 			break;
1500Sstevel@tonic-gate 		case 'm':
1510Sstevel@tonic-gate 			msflag = YES;
1520Sstevel@tonic-gate 			if (*optarg == 'm')
1530Sstevel@tonic-gate 				mac = MM;
1540Sstevel@tonic-gate 			else if (*optarg == 's')
1550Sstevel@tonic-gate 				mac = MS;
1560Sstevel@tonic-gate 			else if (*optarg == 'l')
1570Sstevel@tonic-gate 				disp = 1;
1580Sstevel@tonic-gate 			else
1590Sstevel@tonic-gate 				errflg++;
1600Sstevel@tonic-gate 			break;
1610Sstevel@tonic-gate 		case 'i':
1620Sstevel@tonic-gate 			iflag = YES;
1630Sstevel@tonic-gate 			break;
1640Sstevel@tonic-gate 		case '?':
1650Sstevel@tonic-gate 			errflg++;
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 	}
168*381Smuffin 	if (errflg) {
1690Sstevel@tonic-gate 		usage();
170*381Smuffin 		return (1);
171*381Smuffin 	}
1720Sstevel@tonic-gate 	if (optind == argc)
1730Sstevel@tonic-gate 		infile = stdin;
1740Sstevel@tonic-gate 	else
1750Sstevel@tonic-gate 		infile = opn(argv[optind++]);
1760Sstevel@tonic-gate 	files[0] = infile;
1770Sstevel@tonic-gate 	filesp = &files[0];
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	for (i = 'a'; i <= 'z'; ++i)
1800Sstevel@tonic-gate 		chars[i] = LETTER;
1810Sstevel@tonic-gate 	for (i = 'A'; i <= 'Z'; ++i)
1820Sstevel@tonic-gate 		chars[i] = LETTER;
1830Sstevel@tonic-gate 	for (i = '0'; i <= '9'; ++i)
1840Sstevel@tonic-gate 		chars[i] = DIGIT;
1850Sstevel@tonic-gate 	chars['\''] = APOS;
1860Sstevel@tonic-gate 	chars['&'] = APOS;
1870Sstevel@tonic-gate 	work();
188*381Smuffin 	/* NOTREACHED */
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static int
skeqn(void)193*381Smuffin skeqn(void)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	while ((c = getc(infile)) != rdelim) {
1960Sstevel@tonic-gate 		if (c == EOF) {
1970Sstevel@tonic-gate 			c = eof();
1980Sstevel@tonic-gate 		} else if (c == '"') {
1990Sstevel@tonic-gate 			while ((c = getc(infile)) != '"') {
2000Sstevel@tonic-gate 				if (c == EOF) {
2010Sstevel@tonic-gate 					c = eof();
2020Sstevel@tonic-gate 				} else if (c == '\\') {
2030Sstevel@tonic-gate 					if ((c = getc(infile)) == EOF) {
2040Sstevel@tonic-gate 						c = eof();
2050Sstevel@tonic-gate 					}
2060Sstevel@tonic-gate 				}
2070Sstevel@tonic-gate 			}
2080Sstevel@tonic-gate 		}
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	if (msflag) {
2110Sstevel@tonic-gate 		return (c = 'x');
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	return (c = ' ');
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate /* Functions calling opn() should ensure 'p' is non-null */
2180Sstevel@tonic-gate static FILE *
opn(char * p)2190Sstevel@tonic-gate opn(char *p)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	FILE *fd;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	assert(p != NULL);
2240Sstevel@tonic-gate 	if ((fd = fopen(p, "r")) == NULL)
2250Sstevel@tonic-gate 		fatal(gettext("Cannot open file %s: %s\n"), p, strerror(errno));
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	return (fd);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate static int
eof(void)2330Sstevel@tonic-gate eof(void)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	if (infile != stdin)
2360Sstevel@tonic-gate 		(void) fclose(infile);
2370Sstevel@tonic-gate 	if (filesp > files) {
2380Sstevel@tonic-gate 		infile = *--filesp;
2390Sstevel@tonic-gate 	} else if (optind < argc) {
2400Sstevel@tonic-gate 		infile = opn(argv[optind++]);
2410Sstevel@tonic-gate 	} else {
2420Sstevel@tonic-gate 		exit(0);
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	return (C);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate static void
getfname(void)2510Sstevel@tonic-gate getfname(void)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	char *p;
2540Sstevel@tonic-gate 	struct chain {
2550Sstevel@tonic-gate 		struct chain *nextp;
2560Sstevel@tonic-gate 		char *datap;
2570Sstevel@tonic-gate 	};
2580Sstevel@tonic-gate 	struct chain *q;
2590Sstevel@tonic-gate 	static struct chain *namechain = NULL;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	while (C == ' ')
2620Sstevel@tonic-gate 		;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	for (p = fname; ((*p = c) != '\n') && (c != ' ') && (c != '\t') &&
2650Sstevel@tonic-gate 	    (c != '\\'); ++p) {
2660Sstevel@tonic-gate 		(void) C;
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 	*p = '\0';
2690Sstevel@tonic-gate 	while (c != '\n') {
2700Sstevel@tonic-gate 		(void) C;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/* see if this name has already been used */
2740Sstevel@tonic-gate 	for (q = namechain; q; q = q->nextp)
2750Sstevel@tonic-gate 		if (strcmp(fname, q->datap) != 0) {
2760Sstevel@tonic-gate 			fname[0] = '\0';
2770Sstevel@tonic-gate 			return;
2780Sstevel@tonic-gate 		}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	q = (struct chain *)calloc(1, sizeof (*namechain));
2810Sstevel@tonic-gate 	q->nextp = namechain;
2820Sstevel@tonic-gate 	q->datap = copys(fname);
2830Sstevel@tonic-gate 	namechain = q;
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * Functions calling fatal() should ensure 'format' and
2890Sstevel@tonic-gate  * arguments are non-null.
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate static void
fatal(const char * format,...)2920Sstevel@tonic-gate fatal(const char *format, ...)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	va_list	alist;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	assert(format != NULL);
2970Sstevel@tonic-gate 	(void) fputs(gettext("deroff: "), stderr);
2980Sstevel@tonic-gate 	va_start(alist, format);
2990Sstevel@tonic-gate 	(void) vfprintf(stderr, format, alist);
3000Sstevel@tonic-gate 	exit(1);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate /* Functions calling fatal_msg() should ensure 's' is non-null */
3040Sstevel@tonic-gate static void
fatal_msg(char * s)3050Sstevel@tonic-gate fatal_msg(char *s)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	assert(s != NULL);
3080Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("deroff: %s\n"), s);
3090Sstevel@tonic-gate 	exit(1);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate static void
usage(void)3130Sstevel@tonic-gate usage(void)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	(void) fputs(gettext(
3160Sstevel@tonic-gate 	    "usage: deroff [ -w ] [ -m (m s l) ] [ -i ] "
3170Sstevel@tonic-gate 	    "[ file ] ... \n"), stderr);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate static void
work(void)3210Sstevel@tonic-gate work(void)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	for (;;) {
3250Sstevel@tonic-gate 		if ((C == '.') || (c == '\''))
3260Sstevel@tonic-gate 			comline();
3270Sstevel@tonic-gate 		else
3280Sstevel@tonic-gate 			regline(NO, TWO);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate static void
regline(int macline,int cnst)3340Sstevel@tonic-gate regline(int macline, int cnst)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	if (line == NULL) {
3380Sstevel@tonic-gate 		if ((line = (char *)malloc(linesize * sizeof (char))) == NULL) {
3390Sstevel@tonic-gate 			fatal_msg(gettext("Cannot allocate memory"));
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	lindx = 0;
3440Sstevel@tonic-gate 	line[lindx] = c;
3450Sstevel@tonic-gate 	for (;;) {
3460Sstevel@tonic-gate 		if (c == '\\') {
3470Sstevel@tonic-gate 			line[lindx] = ' ';
3480Sstevel@tonic-gate 			backsl();
3490Sstevel@tonic-gate 			if (c == '%') {	/* no blank for hyphenation char */
3500Sstevel@tonic-gate 				lindx--;
3510Sstevel@tonic-gate 			}
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 		if (c == '\n') {
3540Sstevel@tonic-gate 			break;
3550Sstevel@tonic-gate 		}
3560Sstevel@tonic-gate 		/*
3570Sstevel@tonic-gate 		 * We're just about to add another character to the line
3580Sstevel@tonic-gate 		 * buffer so ensure we don't overrun it.
3590Sstevel@tonic-gate 		 */
3600Sstevel@tonic-gate 		if (++lindx >= linesize - 1) {
3610Sstevel@tonic-gate 			linesize = linesize * 2;
3620Sstevel@tonic-gate 			if ((line = (char *)realloc(line,
3630Sstevel@tonic-gate 			    linesize * sizeof (char))) == NULL) {
3640Sstevel@tonic-gate 				fatal_msg(gettext("Cannot allocate memory"));
3650Sstevel@tonic-gate 			}
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 		if (intable && (c == 'T')) {
3680Sstevel@tonic-gate 			line[lindx] = C;
3690Sstevel@tonic-gate 			if ((c == '{') || (c == '}')) {
3700Sstevel@tonic-gate 				line[lindx - 1] = ' ';
3710Sstevel@tonic-gate 				line[lindx] = C;
3720Sstevel@tonic-gate 			}
3730Sstevel@tonic-gate 		} else {
3740Sstevel@tonic-gate 			line[lindx] = C;
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	line[lindx] = '\0';
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (line[0] != '\0') {
3810Sstevel@tonic-gate 		if (wordflag) {
3820Sstevel@tonic-gate 			putwords(macline);
3830Sstevel@tonic-gate 		} else if (macline) {
3840Sstevel@tonic-gate 			putmac(line, cnst);
3850Sstevel@tonic-gate 		} else {
3860Sstevel@tonic-gate 			(void) puts(line);
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate static void
putmac(char * s,int cnst)3950Sstevel@tonic-gate putmac(char *s, int cnst)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	char *t;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	while (*s) {
4000Sstevel@tonic-gate 		while ((*s == ' ') || (*s == '\t')) {
4010Sstevel@tonic-gate 			(void) putchar(*s++);
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 		for (t = s; (*t != ' ') && (*t != '\t') && (*t != '\0'); ++t)
4040Sstevel@tonic-gate 			;
4050Sstevel@tonic-gate 		if (*s == '\"')
4060Sstevel@tonic-gate 			s++;
4070Sstevel@tonic-gate 		if ((t > s + cnst) && (chars[s[0]] == LETTER) &&
4080Sstevel@tonic-gate 		    (chars[s[1]] == LETTER)) {
4090Sstevel@tonic-gate 			while (s < t) {
4100Sstevel@tonic-gate 				if (*s == '\"')
4110Sstevel@tonic-gate 					s++;
4120Sstevel@tonic-gate 				else
4130Sstevel@tonic-gate 					(void) putchar(*s++);
4140Sstevel@tonic-gate 			}
4150Sstevel@tonic-gate 		} else {
4160Sstevel@tonic-gate 			s = t;
4170Sstevel@tonic-gate 		}
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 	(void) putchar('\n');
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static void
putwords(int macline)4250Sstevel@tonic-gate putwords(int macline)	/* break into words for -w option */
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	char *p, *p1;
4280Sstevel@tonic-gate 	int i, nlet;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	for (p1 = line; ; ) {
4310Sstevel@tonic-gate 		/* skip initial specials ampersands and apostrophes */
4320Sstevel@tonic-gate 		while (chars[*p1] < DIGIT) {
4330Sstevel@tonic-gate 			if (*p1++ == '\0')
4340Sstevel@tonic-gate 				return;
4350Sstevel@tonic-gate 		}
4360Sstevel@tonic-gate 		nlet = 0;
4370Sstevel@tonic-gate 		for (p = p1; (i = chars[*p]) != SPECIAL; ++p) {
4380Sstevel@tonic-gate 			if (i == LETTER)
4390Sstevel@tonic-gate 				++nlet;
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		if ((!macline && (nlet > 1)) /* MDM definition of word */ ||
4430Sstevel@tonic-gate 		    (macline && (nlet > 2) && (chars[p1[0]] == LETTER) &&
4440Sstevel@tonic-gate 		    (chars[p1[1]] == LETTER))) {
4450Sstevel@tonic-gate 			/* delete trailing ampersands and apostrophes */
4460Sstevel@tonic-gate 			while ((p[-1] == '\'') || (p[-1] == '&')) {
4470Sstevel@tonic-gate 				--p;
4480Sstevel@tonic-gate 			}
4490Sstevel@tonic-gate 			while (p1 < p) {
4500Sstevel@tonic-gate 				(void) putchar(*p1++);
4510Sstevel@tonic-gate 			}
4520Sstevel@tonic-gate 			(void) putchar('\n');
4530Sstevel@tonic-gate 		} else {
4540Sstevel@tonic-gate 			p1 = p;
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate static void
comline(void)4620Sstevel@tonic-gate comline(void)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	int c1, c2;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate com:
4670Sstevel@tonic-gate 	while ((C == ' ') || (c == '\t'))
4680Sstevel@tonic-gate 		;
4690Sstevel@tonic-gate comx:
4700Sstevel@tonic-gate 	if ((c1 = c) == '\n')
4710Sstevel@tonic-gate 		return;
4720Sstevel@tonic-gate 	c2 = C;
4730Sstevel@tonic-gate 	if ((c1 == '.') && (c2 != '.'))
4740Sstevel@tonic-gate 		inmacro = NO;
4750Sstevel@tonic-gate 	if (c2 == '\n')
4760Sstevel@tonic-gate 		return;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if ((c1 == 'E') && (c2 == 'Q') && (filesp == files)) {
4790Sstevel@tonic-gate 		eqn();
4800Sstevel@tonic-gate 	} else if ((c1 == 'T') && ((c2 == 'S') || (c2 == 'C') ||
4810Sstevel@tonic-gate 	    (c2 == '&')) && (filesp == files)) {
4820Sstevel@tonic-gate 		if (msflag) {
4830Sstevel@tonic-gate 			stbl();
4840Sstevel@tonic-gate 		} else {
4850Sstevel@tonic-gate 			tbl();
4860Sstevel@tonic-gate 		}
4870Sstevel@tonic-gate 	} else if ((c1 == 'T') && (c2 == 'E')) {
4880Sstevel@tonic-gate 		intable = NO;
4890Sstevel@tonic-gate 	} else if (!inmacro && (c1 == 'd') && (c2 == 'e')) {
4900Sstevel@tonic-gate 		macro();
4910Sstevel@tonic-gate 	} else if (!inmacro && (c1 == 'i') && (c2 == 'g')) {
4920Sstevel@tonic-gate 		macro();
4930Sstevel@tonic-gate 	} else if (!inmacro && (c1 == 'a') && (c2 == 'm')) {
4940Sstevel@tonic-gate 		macro();
4950Sstevel@tonic-gate 	} else if ((c1 == 's') && (c2 == 'o')) {
4960Sstevel@tonic-gate 		if (iflag) {
4970Sstevel@tonic-gate 			SKIP;
4980Sstevel@tonic-gate 		} else {
4990Sstevel@tonic-gate 			getfname();
5000Sstevel@tonic-gate 			if (fname[0]) {
5010Sstevel@tonic-gate 				infile = *++filesp = opn(fname);
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 	} else if ((c1 == 'n') && (c2 == 'x')) {
5050Sstevel@tonic-gate 		if (iflag) {
5060Sstevel@tonic-gate 			SKIP;
5070Sstevel@tonic-gate 		} else {
5080Sstevel@tonic-gate 			getfname();
5090Sstevel@tonic-gate 			if (fname[0] == '\0') {
5100Sstevel@tonic-gate 				exit(0);
5110Sstevel@tonic-gate 			}
5120Sstevel@tonic-gate 			if (infile != stdin) {
5130Sstevel@tonic-gate 				(void) fclose(infile);
5140Sstevel@tonic-gate 			}
5150Sstevel@tonic-gate 			infile = *filesp = opn(fname);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 	} else if ((c1 == 'h') && (c2 == 'w')) {
5180Sstevel@tonic-gate 		SKIP;
5190Sstevel@tonic-gate 	} else if (msflag && (c1 == 'T') && (c2 == 'L')) {
5200Sstevel@tonic-gate 		SKIP_TO_COM;
5210Sstevel@tonic-gate 		goto comx;
5220Sstevel@tonic-gate 	} else if (msflag && (c1 == 'N') && (c2 == 'R')) {
5230Sstevel@tonic-gate 		SKIP;
5240Sstevel@tonic-gate 	} else if (msflag && (c1 == 'A') && ((c2 == 'U') || (c2 == 'I'))) {
5250Sstevel@tonic-gate 		if (mac == MM) {
5260Sstevel@tonic-gate 			SKIP;
5270Sstevel@tonic-gate 		} else {
5280Sstevel@tonic-gate 			SKIP_TO_COM;
5290Sstevel@tonic-gate 			goto comx;
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 	} else if (msflag && (c1 == 'F') && (c2 == 'S')) {
5320Sstevel@tonic-gate 		SKIP_TO_COM;
5330Sstevel@tonic-gate 		goto comx;
5340Sstevel@tonic-gate 	} else if (msflag && (c1 == 'S') && (c2 == 'H')) {
5350Sstevel@tonic-gate 		SKIP_TO_COM;
5360Sstevel@tonic-gate 		goto comx;
5370Sstevel@tonic-gate 	} else if (msflag && (c1 == 'N') && (c2 == 'H')) {
5380Sstevel@tonic-gate 		SKIP_TO_COM;
5390Sstevel@tonic-gate 		goto comx;
5400Sstevel@tonic-gate 	} else if (msflag && (c1 == 'O') && (c2 == 'K')) {
5410Sstevel@tonic-gate 		SKIP_TO_COM;
5420Sstevel@tonic-gate 		goto comx;
5430Sstevel@tonic-gate 	} else if (msflag && (c1 == 'N') && (c2 == 'D')) {
5440Sstevel@tonic-gate 		SKIP;
5450Sstevel@tonic-gate 	} else if (msflag && (mac == MM) && (c1 == 'H') &&
5460Sstevel@tonic-gate 	    ((c2 == ' ') || (c2 == 'U'))) {
5470Sstevel@tonic-gate 		SKIP;
5480Sstevel@tonic-gate 	} else if (msflag && (mac == MM) && (c2 == 'L')) {
5490Sstevel@tonic-gate 		if (disp || (c1 == 'R')) {
5500Sstevel@tonic-gate 			sdis('L', 'E');
5510Sstevel@tonic-gate 		} else {
5520Sstevel@tonic-gate 			SKIP;
5530Sstevel@tonic-gate 			(void) putchar('.');
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 	} else if (msflag && ((c1 == 'D') || (c1 == 'N') ||
5560Sstevel@tonic-gate 	    (c1 == 'K') || (c1 == 'P')) && (c2 == 'S')) {
5570Sstevel@tonic-gate 		sdis(c1, 'E');		/* removed RS-RE */
5580Sstevel@tonic-gate 	} else if (msflag && (c1 == 'K' && c2 == 'F')) {
5590Sstevel@tonic-gate 		sdis(c1, 'E');
5600Sstevel@tonic-gate 	} else if (msflag && (c1 == 'n') && (c2 == 'f')) {
5610Sstevel@tonic-gate 		sdis('f', 'i');
5620Sstevel@tonic-gate 	} else if (msflag && (c1 == 'c') && (c2 == 'e')) {
5630Sstevel@tonic-gate 		sce();
5640Sstevel@tonic-gate 	} else {
5650Sstevel@tonic-gate 		if ((c1 == '.') && (c2 == '.')) {
5660Sstevel@tonic-gate 			while (C == '.')
5670Sstevel@tonic-gate 				;
5680Sstevel@tonic-gate 		}
5690Sstevel@tonic-gate 		++inmacro;
5700Sstevel@tonic-gate 		if ((c1 <= 'Z') && msflag) {
5710Sstevel@tonic-gate 			regline(YES, ONE);
5720Sstevel@tonic-gate 		} else {
5730Sstevel@tonic-gate 			regline(YES, TWO);
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 		--inmacro;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static void
macro(void)5820Sstevel@tonic-gate macro(void)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	if (msflag) {
5850Sstevel@tonic-gate 		/* look for  .. */
5860Sstevel@tonic-gate 		do {
5870Sstevel@tonic-gate 			SKIP;
5880Sstevel@tonic-gate 		} while ((C != '.') || (C != '.') || (C == '.'));
5890Sstevel@tonic-gate 		if (c != '\n') {
5900Sstevel@tonic-gate 			SKIP;
5910Sstevel@tonic-gate 		}
5920Sstevel@tonic-gate 		return;
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 	SKIP;
5950Sstevel@tonic-gate 	inmacro = YES;
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate static void
sdis(char a1,char a2)6020Sstevel@tonic-gate sdis(char a1, char a2)
6030Sstevel@tonic-gate {
6040Sstevel@tonic-gate 	int c1, c2;
6050Sstevel@tonic-gate 	int eqnf;
6060Sstevel@tonic-gate 	int notdone = 1;
6070Sstevel@tonic-gate 	eqnf = 1;
6080Sstevel@tonic-gate 	SKIP;
6090Sstevel@tonic-gate 	while (notdone) {
6100Sstevel@tonic-gate 		while (C != '.')
6110Sstevel@tonic-gate 			SKIP;
6120Sstevel@tonic-gate 		if ((c1 = C) == '\n')
6130Sstevel@tonic-gate 			continue;
6140Sstevel@tonic-gate 		if ((c2 = C) == '\n')
6150Sstevel@tonic-gate 			continue;
6160Sstevel@tonic-gate 		if ((c1 == a1) && (c2 == a2)) {
6170Sstevel@tonic-gate 			SKIP;
6180Sstevel@tonic-gate 			if (eqnf)
6190Sstevel@tonic-gate 				(void) putchar('.');
6200Sstevel@tonic-gate 			(void) putchar('\n');
6210Sstevel@tonic-gate 			return;
6220Sstevel@tonic-gate 		} else if ((a1 == 'D') && (c1 == 'E') && (c2 == 'Q')) {
6230Sstevel@tonic-gate 			eqn();
6240Sstevel@tonic-gate 			eqnf = 0;
6250Sstevel@tonic-gate 		} else {
6260Sstevel@tonic-gate 			SKIP;
6270Sstevel@tonic-gate 		}
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate static void
tbl(void)6320Sstevel@tonic-gate tbl(void)
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate 	while (C != '.')
6350Sstevel@tonic-gate 		;
6360Sstevel@tonic-gate 	SKIP;
6370Sstevel@tonic-gate 	intable = YES;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate static void
stbl(void)6410Sstevel@tonic-gate stbl(void)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	while (C != '.')
6440Sstevel@tonic-gate 		;
6450Sstevel@tonic-gate 	SKIP_TO_COM;
6460Sstevel@tonic-gate 	if ((c != 'T') || (C != 'E')) {
6470Sstevel@tonic-gate 		SKIP;
6480Sstevel@tonic-gate 		pc = c;
6490Sstevel@tonic-gate 		while ((C != '.') || (pc != '\n') ||
6500Sstevel@tonic-gate 		    (C != 'T') || (C != 'E')) {
6510Sstevel@tonic-gate 			pc = c;
6520Sstevel@tonic-gate 		}
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate static void
eqn(void)6570Sstevel@tonic-gate eqn(void)
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate 	int c1, c2;
6600Sstevel@tonic-gate 	int dflg;
6610Sstevel@tonic-gate 	int last;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	last = 0;
6640Sstevel@tonic-gate 	dflg = 1;
6650Sstevel@tonic-gate 	SKIP;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	for (;;) {
6680Sstevel@tonic-gate 		if ((C1 == '.') || (c == '\'')) {
6690Sstevel@tonic-gate 			while ((C1 == ' ') || (c == '\t'))
6700Sstevel@tonic-gate 				;
6710Sstevel@tonic-gate 			if ((c == 'E') && (C1 == 'N')) {
6720Sstevel@tonic-gate 				SKIP;
6730Sstevel@tonic-gate 				if (msflag && dflg) {
6740Sstevel@tonic-gate 					(void) putchar('x');
6750Sstevel@tonic-gate 					(void) putchar(' ');
6760Sstevel@tonic-gate 					if (last) {
6770Sstevel@tonic-gate 						(void) putchar('.');
6780Sstevel@tonic-gate 						(void) putchar(' ');
6790Sstevel@tonic-gate 					}
6800Sstevel@tonic-gate 				}
6810Sstevel@tonic-gate 				return;
6820Sstevel@tonic-gate 			}
6830Sstevel@tonic-gate 		} else if (c == 'd') {	/* look for delim */
6840Sstevel@tonic-gate 			if ((C1 == 'e') && (C1 == 'l')) {
6850Sstevel@tonic-gate 				if ((C1 == 'i') && (C1 == 'm')) {
6860Sstevel@tonic-gate 					while (C1 == ' ')
6870Sstevel@tonic-gate 						;
6880Sstevel@tonic-gate 					if (((c1 = c) == '\n') ||
6890Sstevel@tonic-gate 					    ((c2 = C1) == '\n') ||
6900Sstevel@tonic-gate 					    ((c1 == 'o') && (c2 == 'f') &&
6910Sstevel@tonic-gate 					    (C1 == 'f'))) {
6920Sstevel@tonic-gate 						ldelim = NOCHAR;
6930Sstevel@tonic-gate 						rdelim = NOCHAR;
6940Sstevel@tonic-gate 					} else {
6950Sstevel@tonic-gate 						ldelim = c1;
6960Sstevel@tonic-gate 						rdelim = c2;
6970Sstevel@tonic-gate 					}
6980Sstevel@tonic-gate 				}
6990Sstevel@tonic-gate 				dflg = 0;
7000Sstevel@tonic-gate 			}
7010Sstevel@tonic-gate 		}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		if (c != '\n') {
7040Sstevel@tonic-gate 			while (C1 != '\n') {
7050Sstevel@tonic-gate 				if (c == '.') {
7060Sstevel@tonic-gate 					last = 1;
7070Sstevel@tonic-gate 				} else {
7080Sstevel@tonic-gate 					last = 0;
7090Sstevel@tonic-gate 				}
7100Sstevel@tonic-gate 			}
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate static void
backsl(void)7180Sstevel@tonic-gate backsl(void)	/* skip over a complete backslash construction */
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate 	int bdelim;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate sw:	switch (C) {
7230Sstevel@tonic-gate 	case '"':
7240Sstevel@tonic-gate 		SKIP;
7250Sstevel@tonic-gate 		return;
7260Sstevel@tonic-gate 	case 's':
7270Sstevel@tonic-gate 		if (C == '\\') {
7280Sstevel@tonic-gate 			backsl();
7290Sstevel@tonic-gate 		} else {
7300Sstevel@tonic-gate 			while ((C >= '0') && (c <= '9'))
7310Sstevel@tonic-gate 				;
7320Sstevel@tonic-gate 			(void) ungetc(c, infile);
7330Sstevel@tonic-gate 			c = '0';
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 		lindx--;
7360Sstevel@tonic-gate 		return;
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	case 'f':
7390Sstevel@tonic-gate 	case 'n':
7400Sstevel@tonic-gate 	case '*':
7410Sstevel@tonic-gate 		if (C != '(')
7420Sstevel@tonic-gate 			return;
7430Sstevel@tonic-gate 		/* FALLTHROUGH */
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	case '(':
7460Sstevel@tonic-gate 		if (C != '\n') {
7470Sstevel@tonic-gate 			(void) C;
7480Sstevel@tonic-gate 		}
7490Sstevel@tonic-gate 		return;
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	case '$':
7520Sstevel@tonic-gate 		(void) C;	/* discard argument number */
7530Sstevel@tonic-gate 		return;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	case 'b':
7560Sstevel@tonic-gate 	case 'x':
7570Sstevel@tonic-gate 	case 'v':
7580Sstevel@tonic-gate 	case 'h':
7590Sstevel@tonic-gate 	case 'w':
7600Sstevel@tonic-gate 	case 'o':
7610Sstevel@tonic-gate 	case 'l':
7620Sstevel@tonic-gate 	case 'L':
7630Sstevel@tonic-gate 		if ((bdelim = C) == '\n')
7640Sstevel@tonic-gate 			return;
7650Sstevel@tonic-gate 		while ((C != '\n') && (c != bdelim))
7660Sstevel@tonic-gate 			if (c == '\\')
7670Sstevel@tonic-gate 				backsl();
7680Sstevel@tonic-gate 		return;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	case '\\':
7710Sstevel@tonic-gate 		if (inmacro)
7720Sstevel@tonic-gate 			goto sw;
7730Sstevel@tonic-gate 	default:
7740Sstevel@tonic-gate 		return;
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate static char *
copys(char * s)7820Sstevel@tonic-gate copys(char *s)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	char *t, *t0;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	if ((t0 = t = calloc((unsigned)(strlen(s) + 1), sizeof (*t))) == NULL)
7870Sstevel@tonic-gate 		fatal_msg(gettext("Cannot allocate memory"));
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	while (*t++ = *s++)
7900Sstevel@tonic-gate 		;
7910Sstevel@tonic-gate 	return (t0);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate static void
sce(void)7950Sstevel@tonic-gate sce(void)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	char *ap;
7980Sstevel@tonic-gate 	int n, i;
7990Sstevel@tonic-gate 	char a[10];
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	for (ap = a; C != '\n'; ap++) {
8020Sstevel@tonic-gate 		*ap = c;
8030Sstevel@tonic-gate 		if (ap == &a[9]) {
8040Sstevel@tonic-gate 			SKIP;
8050Sstevel@tonic-gate 			ap = a;
8060Sstevel@tonic-gate 			break;
8070Sstevel@tonic-gate 		}
8080Sstevel@tonic-gate 	}
8090Sstevel@tonic-gate 	if (ap != a) {
8100Sstevel@tonic-gate 		n = atoi(a);
8110Sstevel@tonic-gate 	} else {
8120Sstevel@tonic-gate 		n = 1;
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 	for (i = 0; i < n; ) {
8150Sstevel@tonic-gate 		if (C == '.') {
8160Sstevel@tonic-gate 			if (C == 'c') {
8170Sstevel@tonic-gate 				if (C == 'e') {
8180Sstevel@tonic-gate 					while (C == ' ')
8190Sstevel@tonic-gate 						;
8200Sstevel@tonic-gate 					if (c == '0') {
8210Sstevel@tonic-gate 						break;
8220Sstevel@tonic-gate 					} else {
8230Sstevel@tonic-gate 						SKIP;
8240Sstevel@tonic-gate 					}
8250Sstevel@tonic-gate 				} else {
8260Sstevel@tonic-gate 					SKIP;
8270Sstevel@tonic-gate 				}
8280Sstevel@tonic-gate 			} else {
8290Sstevel@tonic-gate 				SKIP;
8300Sstevel@tonic-gate 			}
8310Sstevel@tonic-gate 		} else {
8320Sstevel@tonic-gate 			SKIP;
8330Sstevel@tonic-gate 			i++;
8340Sstevel@tonic-gate 		}
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate }
837