xref: /onnv-gate/usr/src/cmd/sgs/m4/common/m4.c (revision 12955:1e73c8f5a88b)
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
56951Sab196087  * Common Development and Distribution License (the "License").
66951Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21291Smike_s 
22291Smike_s /*
23*12955Srich.burridge@oracle.com  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24291Smike_s  */
25291Smike_s 
260Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include	<signal.h>
300Sstevel@tonic-gate #include	<unistd.h>
310Sstevel@tonic-gate #include	<fcntl.h>
320Sstevel@tonic-gate #include	"m4.h"
330Sstevel@tonic-gate 
346951Sab196087 #if defined(__lint)
356951Sab196087 extern int yydebug;
366951Sab196087 #endif
376951Sab196087 
380Sstevel@tonic-gate #define	match(c, s)	(c == *s && (!s[1] || inpmatch(s+1)))
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static char	tmp_name[] = "/tmp/m4aXXXXX";
410Sstevel@tonic-gate static wchar_t	prev_char;
420Sstevel@tonic-gate static int mb_cur_max;
430Sstevel@tonic-gate 
440Sstevel@tonic-gate static void getflags(int *, char ***, int *);
450Sstevel@tonic-gate static void initalloc(void);
460Sstevel@tonic-gate static void expand(wchar_t **, int);
470Sstevel@tonic-gate static void lnsync(FILE *);
480Sstevel@tonic-gate static void fpath(FILE *);
490Sstevel@tonic-gate static void puttok(wchar_t *);
500Sstevel@tonic-gate static void error3(void);
510Sstevel@tonic-gate static wchar_t itochr(int);
526951Sab196087 /*LINTED: E_STATIC_UNUSED*/
530Sstevel@tonic-gate static wchar_t *chkbltin(wchar_t *);
540Sstevel@tonic-gate static wchar_t *inpmatch(wchar_t *);
550Sstevel@tonic-gate static void chkspace(char **, int *, char ***);
560Sstevel@tonic-gate static void catchsig(int);
570Sstevel@tonic-gate static FILE *m4open(char ***, char *, int *);
580Sstevel@tonic-gate static void showwrap(void);
590Sstevel@tonic-gate static void sputchr(wchar_t, FILE *);
600Sstevel@tonic-gate static void putchr(wchar_t);
610Sstevel@tonic-gate static void *xcalloc(size_t, size_t);
620Sstevel@tonic-gate static wint_t myfgetwc(FILE *, int);
630Sstevel@tonic-gate static wint_t myfputwc(wchar_t, FILE *);
640Sstevel@tonic-gate static int myfeof(int);
650Sstevel@tonic-gate 
66291Smike_s int
main(int argc,char ** argv)67291Smike_s main(int argc, char **argv)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	wchar_t t;
700Sstevel@tonic-gate 	int i, opt_end = 0;
710Sstevel@tonic-gate 	int sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0};
720Sstevel@tonic-gate 
736951Sab196087 #if defined(__lint)
746951Sab196087 	yydebug = 0;
756951Sab196087 #endif
766951Sab196087 
770Sstevel@tonic-gate 	for (i = 0; sigs[i]; ++i) {
780Sstevel@tonic-gate 		if (signal(sigs[i], SIG_IGN) != SIG_IGN)
790Sstevel@tonic-gate 			(void) signal(sigs[i], catchsig);
800Sstevel@tonic-gate 	}
810Sstevel@tonic-gate 	tempfile = mktemp(tmp_name);
820Sstevel@tonic-gate 	(void) close(creat(tempfile, 0));
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
870Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
880Sstevel@tonic-gate #endif
890Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	if ((mb_cur_max = MB_CUR_MAX) > 1)
920Sstevel@tonic-gate 		wide = 1;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	procnam = argv[0];
950Sstevel@tonic-gate 	getflags(&argc, &argv, &opt_end);
960Sstevel@tonic-gate 	initalloc();
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	setfname("-");
990Sstevel@tonic-gate 	if (argc > 1) {
1000Sstevel@tonic-gate 		--argc;
1010Sstevel@tonic-gate 		++argv;
1020Sstevel@tonic-gate 		if (strcmp(argv[0], "-")) {
1030Sstevel@tonic-gate 			ifile[ifx] = m4open(&argv, "r", &argc);
1040Sstevel@tonic-gate 			setfname(argv[0]);
1050Sstevel@tonic-gate 		}
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	for (;;) {
1090Sstevel@tonic-gate 		token[0] = t = getchr();
1100Sstevel@tonic-gate 		token[1] = EOS;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 		if (t == WEOF) {
1130Sstevel@tonic-gate 			if (ifx > 0) {
1140Sstevel@tonic-gate 				(void) fclose(ifile[ifx]);
1150Sstevel@tonic-gate 				ipflr = ipstk[--ifx];
1160Sstevel@tonic-gate 				continue;
1170Sstevel@tonic-gate 			}
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 			getflags(&argc, &argv, &opt_end);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 			if (argc <= 1)
1220Sstevel@tonic-gate 				/*
1230Sstevel@tonic-gate 				 * If dowrap() has been called, the m4wrap
1240Sstevel@tonic-gate 				 * macro has been processed, and a linked
1250Sstevel@tonic-gate 				 * list of m4wrap strings has been created.
1260Sstevel@tonic-gate 				 * The list starts at wrapstart.
1270Sstevel@tonic-gate 				 */
1280Sstevel@tonic-gate 				if (wrapstart) {
1290Sstevel@tonic-gate 					/*
1300Sstevel@tonic-gate 					 * Now that EOF has been processed,
1310Sstevel@tonic-gate 					 * display the m4wrap strings.
1320Sstevel@tonic-gate 					 */
1330Sstevel@tonic-gate 					showwrap();
1340Sstevel@tonic-gate 					continue;
1350Sstevel@tonic-gate 				} else
1360Sstevel@tonic-gate 					break;
1370Sstevel@tonic-gate 			--argc;
1380Sstevel@tonic-gate 			++argv;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 			if (ifile[ifx] != stdin)
1410Sstevel@tonic-gate 				(void) fclose(ifile[ifx]);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 			if (strcmp(argv[0], "-"))
1440Sstevel@tonic-gate 				ifile[ifx] = m4open(&argv, "r", &argc);
1450Sstevel@tonic-gate 			else
1460Sstevel@tonic-gate 				ifile[ifx] = stdin;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 			setfname(argv[0]);
1490Sstevel@tonic-gate 			continue;
1500Sstevel@tonic-gate 		}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 		if (is_alpha(t) || t == '_') {
1530Sstevel@tonic-gate 			wchar_t	*tp = token+1;
1540Sstevel@tonic-gate 			int tlim = toksize;
1550Sstevel@tonic-gate 			struct nlist	*macadd;  /* temp variable */
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 			while ((*tp = getchr()) != WEOF &&
1586951Sab196087 			    (is_alnum(*tp) || *tp == '_')) {
1590Sstevel@tonic-gate 				tp++;
1600Sstevel@tonic-gate 				if (--tlim <= 0)
1610Sstevel@tonic-gate 					error2(gettext(
1626951Sab196087 					    "more than %d chars in word"),
1636951Sab196087 					    toksize);
1640Sstevel@tonic-gate 			}
1650Sstevel@tonic-gate 			putbak(*tp);
1660Sstevel@tonic-gate 			*tp = EOS;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 			macadd = lookup(token);
1690Sstevel@tonic-gate 			*Ap = (wchar_t *)macadd;
1700Sstevel@tonic-gate 			if (macadd->def) {
1710Sstevel@tonic-gate 				if ((wchar_t *)(++Ap) >= astklm) {
1720Sstevel@tonic-gate 					--Ap;
1730Sstevel@tonic-gate 					error2(gettext(
1746951Sab196087 					    "more than %d items on "
1756951Sab196087 					    "argument stack"),
1766951Sab196087 					    stksize);
1770Sstevel@tonic-gate 				}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 				if (Cp++ == NULL)
1800Sstevel@tonic-gate 					Cp = callst;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 				Cp->argp = Ap;
1830Sstevel@tonic-gate 				*Ap++ = op;
1840Sstevel@tonic-gate 				puttok(token);
1850Sstevel@tonic-gate 				stkchr(EOS);
1860Sstevel@tonic-gate 				t = getchr();
1870Sstevel@tonic-gate 				putbak(t);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 				if (t != '(')
1900Sstevel@tonic-gate 					pbstr(L"()");
1910Sstevel@tonic-gate 				else	/* try to fix arg count */
1920Sstevel@tonic-gate 					*Ap++ = op;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 				Cp->plev = 0;
1950Sstevel@tonic-gate 			} else {
1960Sstevel@tonic-gate 				puttok(token);
1970Sstevel@tonic-gate 			}
1980Sstevel@tonic-gate 		} else if (match(t, lquote)) {
199291Smike_s 			int	qlev = 1;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 			for (;;) {
2020Sstevel@tonic-gate 				token[0] = t = getchr();
2030Sstevel@tonic-gate 				token[1] = EOS;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 				if (match(t, rquote)) {
2060Sstevel@tonic-gate 					if (--qlev > 0)
2070Sstevel@tonic-gate 						puttok(token);
2080Sstevel@tonic-gate 					else
2090Sstevel@tonic-gate 						break;
2100Sstevel@tonic-gate 				} else if (match(t, lquote)) {
2110Sstevel@tonic-gate 					++qlev;
2120Sstevel@tonic-gate 					puttok(token);
2130Sstevel@tonic-gate 				} else {
2140Sstevel@tonic-gate 					if (t == WEOF)
2150Sstevel@tonic-gate 						error(gettext(
2160Sstevel@tonic-gate 						"EOF in quote"));
2170Sstevel@tonic-gate 					putchr(t);
2180Sstevel@tonic-gate 				}
2190Sstevel@tonic-gate 			}
2200Sstevel@tonic-gate 		} else if (match(t, lcom) &&
2216951Sab196087 		    ((lcom[0] != L'#' || lcom[1] != L'\0') ||
2226951Sab196087 		    prev_char != '$')) {
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 			/*
2250Sstevel@tonic-gate 			 * Don't expand commented macro (between lcom and
2260Sstevel@tonic-gate 			 * rcom).
2270Sstevel@tonic-gate 			 * What we know so far is that we have found the
2280Sstevel@tonic-gate 			 * left comment char (lcom).
2290Sstevel@tonic-gate 			 * Make sure we haven't found '#' (lcom) immediately
2300Sstevel@tonic-gate 			 * preceded by '$' because we want to expand "$#".
2310Sstevel@tonic-gate 			 */
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 			puttok(token);
2340Sstevel@tonic-gate 			for (;;) {
2350Sstevel@tonic-gate 				token[0] = t = getchr();
2360Sstevel@tonic-gate 				token[1] = EOS;
2370Sstevel@tonic-gate 				if (match(t, rcom)) {
2380Sstevel@tonic-gate 					puttok(token);
2390Sstevel@tonic-gate 					break;
2400Sstevel@tonic-gate 				} else {
2410Sstevel@tonic-gate 					if (t == WEOF)
2420Sstevel@tonic-gate 						error(gettext(
2430Sstevel@tonic-gate 						"EOF in comment"));
2440Sstevel@tonic-gate 					putchr(t);
2450Sstevel@tonic-gate 				}
2460Sstevel@tonic-gate 			}
2470Sstevel@tonic-gate 		} else if (Cp == NULL) {
2480Sstevel@tonic-gate 			putchr(t);
2490Sstevel@tonic-gate 		} else if (t == '(') {
2500Sstevel@tonic-gate 			if (Cp->plev)
2510Sstevel@tonic-gate 				stkchr(t);
2520Sstevel@tonic-gate 			else {
2530Sstevel@tonic-gate 				/* skip white before arg */
2540Sstevel@tonic-gate 				while ((t = getchr()) != WEOF && is_space(t))
2550Sstevel@tonic-gate 					;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 				putbak(t);
2580Sstevel@tonic-gate 			}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 			++Cp->plev;
2610Sstevel@tonic-gate 		} else if (t == ')') {
2620Sstevel@tonic-gate 			--Cp->plev;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 			if (Cp->plev == 0) {
2650Sstevel@tonic-gate 				stkchr(EOS);
2660Sstevel@tonic-gate 				expand(Cp->argp, Ap-Cp->argp-1);
2670Sstevel@tonic-gate 				op = *Cp->argp;
2680Sstevel@tonic-gate 				Ap = Cp->argp-1;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 				if (--Cp < callst)
2710Sstevel@tonic-gate 					Cp = NULL;
2720Sstevel@tonic-gate 			} else
2730Sstevel@tonic-gate 				stkchr(t);
2740Sstevel@tonic-gate 		} else if (t == ',' && Cp->plev <= 1) {
2750Sstevel@tonic-gate 			stkchr(EOS);
2760Sstevel@tonic-gate 			*Ap = op;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 			if ((wchar_t *)(++Ap) >= astklm) {
2790Sstevel@tonic-gate 				--Ap;
2800Sstevel@tonic-gate 				error2(gettext(
2816951Sab196087 				    "more than %d items on argument stack"),
2826951Sab196087 				    stksize);
2830Sstevel@tonic-gate 			}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 			while ((t = getchr()) != WEOF && is_space(t))
2860Sstevel@tonic-gate 				;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 			putbak(t);
2890Sstevel@tonic-gate 		} else {
2900Sstevel@tonic-gate 			stkchr(t);
2910Sstevel@tonic-gate 		}
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (Cp != NULL)
2950Sstevel@tonic-gate 		error(gettext(
2960Sstevel@tonic-gate 		"EOF in argument list"));
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	delexit(exitstat, 1);
2990Sstevel@tonic-gate 	return (0);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate static wchar_t *
inpmatch(wchar_t * s)3030Sstevel@tonic-gate inpmatch(wchar_t *s)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	wchar_t	*tp = token+1;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	while (*s) {
3080Sstevel@tonic-gate 		*tp = getchr();
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		if (*tp++ != *s++) {
3110Sstevel@tonic-gate 			*tp = EOS;
3120Sstevel@tonic-gate 			pbstr(token+1);
3130Sstevel@tonic-gate 			return (0);
3140Sstevel@tonic-gate 		}
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	*tp = EOS;
3180Sstevel@tonic-gate 	return (token);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate static void
getflags(int * xargc,char *** xargv,int * option_end)3220Sstevel@tonic-gate getflags(int *xargc, char ***xargv, int *option_end)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	char	*arg;
3250Sstevel@tonic-gate 	char *t;
3260Sstevel@tonic-gate 	wchar_t *s[3];
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	while (*xargc > 1) {
3290Sstevel@tonic-gate 		arg = (*xargv)[1]; /* point arg to current argument */
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 		/*
3320Sstevel@tonic-gate 		 * This argument is not an option if it equals "-" or if
3330Sstevel@tonic-gate 		 * "--" has already been parsed.
3340Sstevel@tonic-gate 		 */
3350Sstevel@tonic-gate 		if (arg[0] != '-' || arg[1] == EOS || *option_end)
3360Sstevel@tonic-gate 			break;
3370Sstevel@tonic-gate 		if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') {
3380Sstevel@tonic-gate 			*option_end = 1;
3390Sstevel@tonic-gate 		} else {
3400Sstevel@tonic-gate 			switch (arg[1]) {
3410Sstevel@tonic-gate 			case 'B':
3420Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3430Sstevel@tonic-gate 				bufsize = atoi(&arg[2]);
344*12955Srich.burridge@oracle.com 				if (bufsize <= 0) {
345*12955Srich.burridge@oracle.com 					bufsize = DEF_BUFSIZE;
346*12955Srich.burridge@oracle.com 				}
3470Sstevel@tonic-gate 				break;
3480Sstevel@tonic-gate 			case 'D':
3490Sstevel@tonic-gate 				initalloc();
3500Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3510Sstevel@tonic-gate 				for (t = &arg[2]; *t; t++) {
3520Sstevel@tonic-gate 					if (*t == '=') {
3530Sstevel@tonic-gate 						*t++ = EOS;
3540Sstevel@tonic-gate 						break;
3550Sstevel@tonic-gate 					}
3560Sstevel@tonic-gate 				}
3570Sstevel@tonic-gate 				s[1] = str2wstr(&arg[2], 1);
3580Sstevel@tonic-gate 				s[2] = str2wstr(t, 1);
3590Sstevel@tonic-gate 				dodef(&s[0], 2);
3600Sstevel@tonic-gate 				free(s[1]);
3610Sstevel@tonic-gate 				free(s[2]);
3620Sstevel@tonic-gate 				break;
3630Sstevel@tonic-gate 			case 'H':
3640Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3650Sstevel@tonic-gate 				hshsize = atoi(&arg[2]);
366*12955Srich.burridge@oracle.com 				if (hshsize <= 0) {
367*12955Srich.burridge@oracle.com 					hshsize = DEF_HSHSIZE;
368*12955Srich.burridge@oracle.com 				}
3690Sstevel@tonic-gate 				break;
3700Sstevel@tonic-gate 			case 'S':
3710Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3720Sstevel@tonic-gate 				stksize = atoi(&arg[2]);
373*12955Srich.burridge@oracle.com 				if (stksize <= 0) {
374*12955Srich.burridge@oracle.com 					stksize = DEF_STKSIZE;
375*12955Srich.burridge@oracle.com 				}
3760Sstevel@tonic-gate 				break;
3770Sstevel@tonic-gate 			case 'T':
3780Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3790Sstevel@tonic-gate 				toksize = atoi(&arg[2]);
380*12955Srich.burridge@oracle.com 				if (toksize <= 0) {
381*12955Srich.burridge@oracle.com 					toksize = DEF_TOKSIZE;
382*12955Srich.burridge@oracle.com 				}
3830Sstevel@tonic-gate 				break;
3840Sstevel@tonic-gate 			case 'U':
3850Sstevel@tonic-gate 				initalloc();
3860Sstevel@tonic-gate 				chkspace(&arg, xargc, xargv);
3870Sstevel@tonic-gate 				s[1] = str2wstr(&arg[2], 1);
3880Sstevel@tonic-gate 				doundef(&s[0], 1);
3890Sstevel@tonic-gate 				free(s[1]);
3900Sstevel@tonic-gate 				break;
3910Sstevel@tonic-gate 			case 'e':
3920Sstevel@tonic-gate 				setbuf(stdout, NULL);
3930Sstevel@tonic-gate 				(void) signal(SIGINT, SIG_IGN);
3940Sstevel@tonic-gate 				break;
3950Sstevel@tonic-gate 			case 's':
3960Sstevel@tonic-gate 				/* turn on line sync */
3970Sstevel@tonic-gate 				sflag = 1;
3980Sstevel@tonic-gate 				break;
3990Sstevel@tonic-gate 			default:
4000Sstevel@tonic-gate 				(void) fprintf(stderr,
4010Sstevel@tonic-gate 				    gettext("%s: bad option: %s\n"),
4020Sstevel@tonic-gate 				    procnam, arg);
4030Sstevel@tonic-gate 				delexit(NOT_OK, 0);
4040Sstevel@tonic-gate 			}
4050Sstevel@tonic-gate 		} /* end else not "--" */
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 		(*xargv)++;
4080Sstevel@tonic-gate 		--(*xargc);
4090Sstevel@tonic-gate 	} /* end while options to process */
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * Function: chkspace
4140Sstevel@tonic-gate  *
4150Sstevel@tonic-gate  * If there is a space between the option and its argument,
4160Sstevel@tonic-gate  * adjust argptr so that &arg[2] will point to beginning of the option argument.
4170Sstevel@tonic-gate  * This will ensure that processing in getflags() will work, because &arg[2]
4180Sstevel@tonic-gate  * will point to the beginning of the option argument whether or not we have
4190Sstevel@tonic-gate  * a space between the option and its argument.  If there is a space between
4200Sstevel@tonic-gate  * the option and its argument, also adjust xargv and xargc because we are
4210Sstevel@tonic-gate  * processing the next argument.
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate static void
chkspace(char ** argptr,int * xargc,char *** xargv)4240Sstevel@tonic-gate chkspace(char **argptr, int *xargc, char ***xargv)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	if ((*argptr)[2] == EOS) {
4270Sstevel@tonic-gate 		/* there is a space between the option and its argument */
4280Sstevel@tonic-gate 		(*xargv)++; /* look at the next argument */
4290Sstevel@tonic-gate 		--(*xargc);
4300Sstevel@tonic-gate 		/*
4310Sstevel@tonic-gate 		 * Adjust argptr if the option is followed by an
4320Sstevel@tonic-gate 		 * option argument.
4330Sstevel@tonic-gate 		 */
4340Sstevel@tonic-gate 		if (*xargc > 1) {
4350Sstevel@tonic-gate 			*argptr = (*xargv)[1];
4360Sstevel@tonic-gate 			/* point &arg[2] to beginning of option argument */
4370Sstevel@tonic-gate 			*argptr -= 2;
4380Sstevel@tonic-gate 		}
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate static void
initalloc(void)443291Smike_s initalloc(void)
4440Sstevel@tonic-gate {
445291Smike_s 	static int done = 0;
446291Smike_s 	int	t;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (done++)
4490Sstevel@tonic-gate 		return;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	hshtab = xcalloc(hshsize, sizeof (struct nlist *));
4520Sstevel@tonic-gate 	callst = xcalloc(stksize/3+1, sizeof (struct call));
4530Sstevel@tonic-gate 	Ap = argstk = xcalloc(stksize+3, sizeof (wchar_t *));
4540Sstevel@tonic-gate 	ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1, sizeof (wchar_t));
4550Sstevel@tonic-gate 	op = obuf = xcalloc(bufsize+1, sizeof (wchar_t));
4560Sstevel@tonic-gate 	token = xcalloc(toksize+1, sizeof (wchar_t));
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	astklm = (wchar_t *)(&argstk[stksize]);
4590Sstevel@tonic-gate 	ibuflm = &ibuf[bufsize];
4600Sstevel@tonic-gate 	obuflm = &obuf[bufsize];
4610Sstevel@tonic-gate 	toklm = &token[toksize];
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	for (t = 0; barray[t].bname; ++t) {
4640Sstevel@tonic-gate 		wchar_t	p[2] = {0, EOS};
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		p[0] = builtin(t);
4670Sstevel@tonic-gate 		install(barray[t].bname, p, NOPUSH);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 	install(L"unix", nullstr, NOPUSH);
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate void
install(wchar_t * nam,wchar_t * val,int mode)4730Sstevel@tonic-gate install(wchar_t *nam, wchar_t *val, int mode)
4740Sstevel@tonic-gate {
475291Smike_s 	struct nlist *np;
4760Sstevel@tonic-gate 	wchar_t	*cp;
4770Sstevel@tonic-gate 	int		l;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (mode == PUSH)
4800Sstevel@tonic-gate 		(void) lookup(nam);	/* lookup sets hshval */
4810Sstevel@tonic-gate 	else
4820Sstevel@tonic-gate 		while (undef(nam))	/* undef calls lookup */
4830Sstevel@tonic-gate 			;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	np = xcalloc(1, sizeof (*np));
4860Sstevel@tonic-gate 	np->name = wstrdup(nam);
4870Sstevel@tonic-gate 	np->next = hshtab[hshval];
4880Sstevel@tonic-gate 	hshtab[hshval] = np;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	cp = xcalloc((l = wcslen(val))+1, sizeof (*val));
4910Sstevel@tonic-gate 	np->def = cp;
4920Sstevel@tonic-gate 	cp = &cp[l];
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	while (*val)
4950Sstevel@tonic-gate 		*--cp = *val++;
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate struct nlist *
lookup(wchar_t * str)4990Sstevel@tonic-gate lookup(wchar_t *str)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	wchar_t	*s1;
502291Smike_s 	struct nlist	*np;
5030Sstevel@tonic-gate 	static struct nlist	nodef;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	s1 = str;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	for (hshval = 0; *s1; )
5080Sstevel@tonic-gate 		hshval += *s1++;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	hshval %= hshsize;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	for (np = hshtab[hshval]; np != NULL; np = np->next) {
5130Sstevel@tonic-gate 		if (*str == *np->name && wcscmp(str, np->name) == 0)
5140Sstevel@tonic-gate 			return (np);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate 	return (&nodef);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate static void
expand(wchar_t ** a1,int c)5200Sstevel@tonic-gate expand(wchar_t **a1, int c)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	wchar_t	*dp;
523291Smike_s 	struct nlist	*sp;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	sp = (struct nlist *)a1[-1];
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if (sp->tflag || trace) {
5286951Sab196087 #if !defined(__lint)	/* lint doesn't grok "%ws" */
5290Sstevel@tonic-gate 		int	i;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		(void) fprintf(stderr,
5320Sstevel@tonic-gate 		    "Trace(%d): %ws", Cp-callst, a1[0]);
5336951Sab196087 #endif
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		if (c > 0) {
5366951Sab196087 #if !defined(__lint)	/* lint doesn't grok "%ws" */
5370Sstevel@tonic-gate 			(void) fprintf(stderr, "(%ws", chkbltin(a1[1]));
5380Sstevel@tonic-gate 			for (i = 2; i <= c; ++i)
5390Sstevel@tonic-gate 				(void) fprintf(stderr, ",%ws", chkbltin(a1[i]));
5406951Sab196087 #endif
5410Sstevel@tonic-gate 			(void) fprintf(stderr, ")");
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	dp = sp->def;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	for (; *dp; ++dp) {
5490Sstevel@tonic-gate 		if (is_builtin(*dp)) {
5500Sstevel@tonic-gate 			(*barray[builtin_idx(*dp)].bfunc)(a1, c);
5510Sstevel@tonic-gate 		} else if (dp[1] == '$') {
5520Sstevel@tonic-gate 			if (is_digit(*dp)) {
553291Smike_s 				int	n;
5540Sstevel@tonic-gate 				if ((n = *dp-'0') <= c)
5550Sstevel@tonic-gate 					pbstr(a1[n]);
5560Sstevel@tonic-gate 				++dp;
5570Sstevel@tonic-gate 			} else if (*dp == '#') {
5580Sstevel@tonic-gate 				pbnum((long)c);
5590Sstevel@tonic-gate 				++dp;
5600Sstevel@tonic-gate 			} else if (*dp == '*' || *dp == '@') {
561291Smike_s 				int i = c;
5620Sstevel@tonic-gate 				wchar_t **a = a1;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 				if (i > 0)
5650Sstevel@tonic-gate 					for (;;) {
5660Sstevel@tonic-gate 						if (*dp == '@')
5670Sstevel@tonic-gate 							pbstr(rquote);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 						pbstr(a[i--]);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 						if (*dp == '@')
5720Sstevel@tonic-gate 							pbstr(lquote);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 						if (i <= 0)
5750Sstevel@tonic-gate 						break;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 						pbstr(L",");
5780Sstevel@tonic-gate 					}
5790Sstevel@tonic-gate 				++dp;
5800Sstevel@tonic-gate 			} else
5810Sstevel@tonic-gate 				putbak(*dp);
5820Sstevel@tonic-gate 		} else
5830Sstevel@tonic-gate 			putbak(*dp);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate void
setfname(char * s)5880Sstevel@tonic-gate setfname(char *s)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	if (fname[ifx])
5910Sstevel@tonic-gate 		free(fname[ifx]);
5920Sstevel@tonic-gate 	if ((fname[ifx] = strdup(s)) == NULL)
5930Sstevel@tonic-gate 		error(gettext("out of storage"));
5940Sstevel@tonic-gate 	fline[ifx] = 1;
5950Sstevel@tonic-gate 	nflag = 1;
5960Sstevel@tonic-gate 	lnsync(stdout);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate static void
lnsync(FILE * iop)6000Sstevel@tonic-gate lnsync(FILE *iop)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate 	static int cline = 0;
6030Sstevel@tonic-gate 	static int cfile = 0;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	if (!sflag || iop != stdout)
6060Sstevel@tonic-gate 		return;
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (nflag || ifx != cfile) {
6090Sstevel@tonic-gate 		nflag = 0;
6100Sstevel@tonic-gate 		cfile = ifx;
6110Sstevel@tonic-gate 		(void) fprintf(iop, "#line %d \"", cline = fline[ifx]);
6120Sstevel@tonic-gate 		fpath(iop);
6130Sstevel@tonic-gate 		(void) fprintf(iop, "\"\n");
6140Sstevel@tonic-gate 	} else if (++cline != fline[ifx])
6150Sstevel@tonic-gate 		(void) fprintf(iop, "#line %d\n", cline = fline[ifx]);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate static void
fpath(FILE * iop)6190Sstevel@tonic-gate fpath(FILE *iop)
6200Sstevel@tonic-gate {
621291Smike_s 	int	i;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	if (fname[0] == NULL)
6240Sstevel@tonic-gate 		return;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	(void) fprintf(iop, "%s", fname[0]);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	for (i = 1; i <= ifx; ++i)
6290Sstevel@tonic-gate 		(void) fprintf(iop, ":%s", fname[i]);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate /* ARGSUSED */
6330Sstevel@tonic-gate static void
catchsig(int i)6340Sstevel@tonic-gate catchsig(int i)
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate 	(void) signal(SIGHUP, SIG_IGN);
6370Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);
6380Sstevel@tonic-gate 	delexit(NOT_OK, 0);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate void
delexit(int code,int flushio)6420Sstevel@tonic-gate delexit(int code, int flushio)
6430Sstevel@tonic-gate {
644291Smike_s 	int i;
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	cf = stdout;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate /*
6490Sstevel@tonic-gate  *	if (ofx != 0) {
6500Sstevel@tonic-gate  *		ofx = 0;
6510Sstevel@tonic-gate  *		code = NOT_OK;
6520Sstevel@tonic-gate  *	}
6530Sstevel@tonic-gate  */
6540Sstevel@tonic-gate 	ofx = 0;	/* ensure that everything comes out */
6550Sstevel@tonic-gate 	for (i = 1; i < 10; i++)
6560Sstevel@tonic-gate 		undiv(i, code);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	tempfile[7] = 'a';
6590Sstevel@tonic-gate 	(void) unlink(tempfile);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/* flush standard I/O buffers, ie: call exit() not _exit() */
6620Sstevel@tonic-gate 	if (flushio)
6630Sstevel@tonic-gate 		exit(code);
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	_exit(code);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate static void
puttok(wchar_t * tp)6690Sstevel@tonic-gate puttok(wchar_t *tp)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	if (Cp) {
6720Sstevel@tonic-gate 		while (*tp)
6730Sstevel@tonic-gate 			stkchr(*tp++);
6740Sstevel@tonic-gate 	} else if (cf) {
6750Sstevel@tonic-gate 		while (*tp) {
6760Sstevel@tonic-gate 			sputchr(*tp++, cf);
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate void
pbstr(wchar_t * str)6820Sstevel@tonic-gate pbstr(wchar_t *str)
6830Sstevel@tonic-gate {
6840Sstevel@tonic-gate 	wchar_t *p;
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	for (p = str + wcslen(str); --p >= str; )
6870Sstevel@tonic-gate 		putbak(*p);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate void
undiv(int i,int code)6910Sstevel@tonic-gate undiv(int i, int code)
6920Sstevel@tonic-gate {
693291Smike_s 	FILE *fp;
6940Sstevel@tonic-gate 	wint_t c;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	if (i < 1 || i > 9 || i == ofx || !ofile[i])
6970Sstevel@tonic-gate 		return;
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	(void) fclose(ofile[i]);
7000Sstevel@tonic-gate 	tempfile[7] = 'a'+i;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	if (code == OK && cf) {
7030Sstevel@tonic-gate 		fp = xfopen(tempfile, "r");
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 		if (wide) {
7060Sstevel@tonic-gate 			while ((c = myfgetwc(fp, -1)) != WEOF)
7070Sstevel@tonic-gate 				sputchr((wchar_t)c, cf);
7080Sstevel@tonic-gate 		} else {
7090Sstevel@tonic-gate 			while ((c = (wint_t)getc(fp)) != WEOF)
7100Sstevel@tonic-gate 				sputchr((wchar_t)c, cf);
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 		(void) fclose(fp);
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	(void) unlink(tempfile);
7170Sstevel@tonic-gate 	ofile[i] = NULL;
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate void
pbnum(long num)7210Sstevel@tonic-gate pbnum(long num)
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate 	pbnbr(num, 10, 1);
7240Sstevel@tonic-gate }
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate void
pbnbr(long nbr,int base,int len)7270Sstevel@tonic-gate pbnbr(long nbr, int base, int len)
7280Sstevel@tonic-gate {
729291Smike_s 	int	neg = 0;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	if (base <= 0)
7320Sstevel@tonic-gate 		return;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if (nbr < 0)
7350Sstevel@tonic-gate 		neg = 1;
7360Sstevel@tonic-gate 	else
7370Sstevel@tonic-gate 		nbr = -nbr;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	while (nbr < 0) {
740291Smike_s 		int	i;
7410Sstevel@tonic-gate 		if (base > 1) {
7420Sstevel@tonic-gate 			i = nbr%base;
7430Sstevel@tonic-gate 			nbr /= base;
7440Sstevel@tonic-gate #if (-3 % 2) != -1
7450Sstevel@tonic-gate 			while (i > 0) {
7460Sstevel@tonic-gate 				i -= base;
7470Sstevel@tonic-gate 				++nbr;
7480Sstevel@tonic-gate 			}
7490Sstevel@tonic-gate #endif
7500Sstevel@tonic-gate 			i = -i;
7510Sstevel@tonic-gate 		} else {
7520Sstevel@tonic-gate 			i = 1;
7530Sstevel@tonic-gate 			++nbr;
7540Sstevel@tonic-gate 		}
7550Sstevel@tonic-gate 		putbak(itochr(i));
7560Sstevel@tonic-gate 		--len;
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	while (--len >= 0)
7600Sstevel@tonic-gate 		putbak('0');
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if (neg)
7630Sstevel@tonic-gate 		putbak('-');
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate static wchar_t
itochr(int i)7670Sstevel@tonic-gate itochr(int i)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	if (i > 9)
7700Sstevel@tonic-gate 		return ((wchar_t)(i-10+'A'));
7710Sstevel@tonic-gate 	else
7720Sstevel@tonic-gate 		return ((wchar_t)(i+'0'));
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate long
ctol(wchar_t * str)7760Sstevel@tonic-gate ctol(wchar_t *str)
7770Sstevel@tonic-gate {
778291Smike_s 	int sign;
7790Sstevel@tonic-gate 	long num;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	while (is_space(*str))
7820Sstevel@tonic-gate 		++str;
7830Sstevel@tonic-gate 	num = 0;
7840Sstevel@tonic-gate 	if (*str == '-') {
7850Sstevel@tonic-gate 		sign = -1;
7860Sstevel@tonic-gate 		++str;
7870Sstevel@tonic-gate 	} else
7880Sstevel@tonic-gate 		sign = 1;
7890Sstevel@tonic-gate 	while (is_digit(*str))
7900Sstevel@tonic-gate 		num = num*10 + *str++ - '0';
7910Sstevel@tonic-gate 	return (sign * num);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate int
min(int a,int b)7950Sstevel@tonic-gate min(int a, int b)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	if (a > b)
7980Sstevel@tonic-gate 		return (b);
7990Sstevel@tonic-gate 	return (a);
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate FILE *
xfopen(char * name,char * mode)8030Sstevel@tonic-gate xfopen(char *name, char *mode)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate 	FILE	*fp;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	if ((fp = fopen(name, mode)) == NULL)
8080Sstevel@tonic-gate 		error(gettext("can't open file"));
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	return (fp);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate /*
8140Sstevel@tonic-gate  * m4open
8150Sstevel@tonic-gate  *
8160Sstevel@tonic-gate  * Continue processing files when unable to open the given file argument.
8170Sstevel@tonic-gate  */
8180Sstevel@tonic-gate FILE *
m4open(char *** argvec,char * mode,int * argcnt)8190Sstevel@tonic-gate m4open(char ***argvec, char *mode, int *argcnt)
8200Sstevel@tonic-gate {
8210Sstevel@tonic-gate 	FILE	*fp;
8220Sstevel@tonic-gate 	char *arg;
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	while (*argcnt > 0) {
8250Sstevel@tonic-gate 		arg = (*argvec)[0]; /* point arg to current file name */
8260Sstevel@tonic-gate 		if (arg[0] == '-' && arg[1] == EOS)
8270Sstevel@tonic-gate 			return (stdin);
8280Sstevel@tonic-gate 		else {
8290Sstevel@tonic-gate 			if ((fp = fopen(arg, mode)) == NULL) {
8300Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
8310Sstevel@tonic-gate 				"m4: cannot open %s: "), arg);
8320Sstevel@tonic-gate 				perror("");
8330Sstevel@tonic-gate 				if (*argcnt == 1) {
8340Sstevel@tonic-gate 					/* last arg therefore exit */
8350Sstevel@tonic-gate 					error3();
8360Sstevel@tonic-gate 				} else {
8370Sstevel@tonic-gate 					exitstat = 1;
8380Sstevel@tonic-gate 					(*argvec)++; /* try next arg */
8390Sstevel@tonic-gate 					(*argcnt)--;
8400Sstevel@tonic-gate 				}
8410Sstevel@tonic-gate 			} else
8420Sstevel@tonic-gate 				break;
8430Sstevel@tonic-gate 		}
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 	return (fp);
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate void *
xmalloc(size_t size)8490Sstevel@tonic-gate xmalloc(size_t size)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	void *ptr;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	if ((ptr = malloc(size)) == NULL)
8540Sstevel@tonic-gate 		error(gettext("out of storage"));
8550Sstevel@tonic-gate 	return (ptr);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate static void *
xcalloc(size_t nbr,size_t size)8590Sstevel@tonic-gate xcalloc(size_t nbr, size_t size)
8600Sstevel@tonic-gate {
861291Smike_s 	void	*ptr;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	ptr = xmalloc(nbr * size);
8640Sstevel@tonic-gate 	(void) memset(ptr, '\0', nbr * size);
8650Sstevel@tonic-gate 	return (ptr);
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate 
868291Smike_s /* PRINTFLIKE1 */
8690Sstevel@tonic-gate void
error2(char * str,int num)8700Sstevel@tonic-gate error2(char *str, int num)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	char buf[500];
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), str, num);
8750Sstevel@tonic-gate 	error(buf);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate void
error(char * str)8790Sstevel@tonic-gate error(char *str)
8800Sstevel@tonic-gate {
8810Sstevel@tonic-gate 	(void) fprintf(stderr, "\n%s:", procnam);
8820Sstevel@tonic-gate 	fpath(stderr);
8830Sstevel@tonic-gate 	(void) fprintf(stderr, ":%d %s\n", fline[ifx], str);
8840Sstevel@tonic-gate 	error3();
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate static void
error3()8880Sstevel@tonic-gate error3()
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	if (Cp) {
891291Smike_s 		struct call	*mptr;
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 		/* fix limit */
8940Sstevel@tonic-gate 		*op = EOS;
8950Sstevel@tonic-gate 		(Cp+1)->argp = Ap+1;
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		for (mptr = callst; mptr <= Cp; ++mptr) {
8980Sstevel@tonic-gate 			wchar_t	**aptr, **lim;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 			aptr = mptr->argp;
9010Sstevel@tonic-gate 			lim = (mptr+1)->argp-1;
9020Sstevel@tonic-gate 			if (mptr == callst)
9030Sstevel@tonic-gate 				(void) fputws(*aptr, stderr);
9040Sstevel@tonic-gate 			++aptr;
9050Sstevel@tonic-gate 			(void) fputs("(", stderr);
9060Sstevel@tonic-gate 			if (aptr < lim)
9070Sstevel@tonic-gate 				for (;;) {
9080Sstevel@tonic-gate 					(void) fputws(*aptr++, stderr);
9090Sstevel@tonic-gate 					if (aptr >= lim)
9100Sstevel@tonic-gate 						break;
9110Sstevel@tonic-gate 					(void) fputs(",", stderr);
9120Sstevel@tonic-gate 				}
9130Sstevel@tonic-gate 		}
9140Sstevel@tonic-gate 		while (--mptr >= callst)
9150Sstevel@tonic-gate 			(void) fputs(")", stderr);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 		(void) fputs("\n", stderr);
9180Sstevel@tonic-gate 	}
9190Sstevel@tonic-gate 	delexit(NOT_OK, 1);
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate static wchar_t *
chkbltin(wchar_t * s)9230Sstevel@tonic-gate chkbltin(wchar_t *s)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate 	static wchar_t buf[24];
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	if (is_builtin(*s)) {
9280Sstevel@tonic-gate 		(void) swprintf(buf, sizeof (buf)/sizeof (wchar_t), L"<%ls>",
9290Sstevel@tonic-gate 		    barray[builtin_idx(*s)].bname);
9300Sstevel@tonic-gate 		return (buf);
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 	return (s);
9330Sstevel@tonic-gate }
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate wchar_t
getchr()9360Sstevel@tonic-gate getchr()
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate 	static wchar_t C;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	prev_char = C;
9410Sstevel@tonic-gate 	if (ip > ipflr)
9420Sstevel@tonic-gate 		return (*--ip);
9430Sstevel@tonic-gate 	if (wide) {
9440Sstevel@tonic-gate 		C = (wchar_t)(myfeof(ifx) ? WEOF : myfgetwc(NULL, ifx));
9450Sstevel@tonic-gate 	} else {
9460Sstevel@tonic-gate 		C = (wchar_t)(feof(ifile[ifx]) ?
9470Sstevel@tonic-gate 		    WEOF : (wint_t)getc(ifile[ifx]));
9480Sstevel@tonic-gate 	}
9490Sstevel@tonic-gate 	if (C == '\n')
9500Sstevel@tonic-gate 		fline[ifx]++;
9510Sstevel@tonic-gate 	return (C);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate /*
9550Sstevel@tonic-gate  * showwrap
9560Sstevel@tonic-gate  *
9570Sstevel@tonic-gate  * Loop through the list of m4wrap strings.  Call pbstr() so that the
9580Sstevel@tonic-gate  * string will be displayed, then delete the list entry and free the memory
9590Sstevel@tonic-gate  * allocated for it.
9600Sstevel@tonic-gate  */
9610Sstevel@tonic-gate static void
showwrap()9620Sstevel@tonic-gate showwrap()
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	struct Wrap *prev;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	while (wrapstart) {
9670Sstevel@tonic-gate 		pbstr(wrapstart->wrapstr);
9680Sstevel@tonic-gate 		free(wrapstart->wrapstr);
9690Sstevel@tonic-gate 		prev = wrapstart;
9700Sstevel@tonic-gate 		wrapstart = wrapstart->nxt;
9710Sstevel@tonic-gate 		free(prev);
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate static void
sputchr(wchar_t c,FILE * f)9760Sstevel@tonic-gate sputchr(wchar_t c, FILE *f)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate 	wint_t ret;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	if (is_builtin(c))
9810Sstevel@tonic-gate 		return;
9820Sstevel@tonic-gate 	if (wide)
9830Sstevel@tonic-gate 		ret = myfputwc(c, f);
9840Sstevel@tonic-gate 	else
9850Sstevel@tonic-gate 		ret = (wint_t)putc((int)c, f);
9860Sstevel@tonic-gate 	if (ret == WEOF)
9870Sstevel@tonic-gate 		error(gettext("output error"));
9880Sstevel@tonic-gate 	if (ret == '\n')
9890Sstevel@tonic-gate 		lnsync(f);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate static void
putchr(wchar_t c)9930Sstevel@tonic-gate putchr(wchar_t c)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate 	wint_t ret;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	if (Cp)
9980Sstevel@tonic-gate 		stkchr(c);
9990Sstevel@tonic-gate 	else if (cf) {
10000Sstevel@tonic-gate 		if (sflag)
10010Sstevel@tonic-gate 			sputchr(c, cf);
10020Sstevel@tonic-gate 		else {
10030Sstevel@tonic-gate 			if (is_builtin(c))
10040Sstevel@tonic-gate 				return;
10050Sstevel@tonic-gate 			if (wide)
10060Sstevel@tonic-gate 				ret = myfputwc(c, cf);
10070Sstevel@tonic-gate 			else
10080Sstevel@tonic-gate 				ret = (wint_t)putc((int)c, cf);
10090Sstevel@tonic-gate 			if (ret == WEOF) {
10100Sstevel@tonic-gate 				error(gettext("output error"));
10110Sstevel@tonic-gate 			}
10120Sstevel@tonic-gate 		}
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate wchar_t *
wstrdup(wchar_t * p)10170Sstevel@tonic-gate wstrdup(wchar_t *p)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate 	size_t len = wcslen(p);
10200Sstevel@tonic-gate 	wchar_t *ret;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	ret = xmalloc((len + 1) * sizeof (wchar_t));
10230Sstevel@tonic-gate 	(void) wcscpy(ret, p);
10240Sstevel@tonic-gate 	return (ret);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate int
wstoi(wchar_t * p)10280Sstevel@tonic-gate wstoi(wchar_t *p)
10290Sstevel@tonic-gate {
10300Sstevel@tonic-gate 	return ((int)wcstol(p, NULL, 10));
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate char *
wstr2str(wchar_t * from,int alloc)10340Sstevel@tonic-gate wstr2str(wchar_t *from, int alloc)
10350Sstevel@tonic-gate {
10360Sstevel@tonic-gate 	static char *retbuf;
10370Sstevel@tonic-gate 	static size_t bsiz;
10380Sstevel@tonic-gate 	char *p, *ret;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	if (alloc) {
10410Sstevel@tonic-gate 		ret = p = xmalloc(wcslen(from) * mb_cur_max + 1);
10420Sstevel@tonic-gate 	} else {
10430Sstevel@tonic-gate 		while (bsiz < (wcslen(from) * mb_cur_max + 1)) {
10440Sstevel@tonic-gate 			if ((p = realloc(retbuf, bsiz + 256)) == NULL)
10450Sstevel@tonic-gate 				error(gettext("out of storage"));
10460Sstevel@tonic-gate 			bsiz += 256;
10470Sstevel@tonic-gate 			retbuf = p;
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 		ret = p = retbuf;
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	if (wide) {
10530Sstevel@tonic-gate 		while (*from) {
10540Sstevel@tonic-gate 			int len;
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 			if (*from & INVALID_CHAR) {
10570Sstevel@tonic-gate 				*p = (char)(*from & ~INVALID_CHAR);
10580Sstevel@tonic-gate 				len = 1;
10590Sstevel@tonic-gate 			} else {
10600Sstevel@tonic-gate 				if ((len = wctomb(p, *from)) == -1) {
10610Sstevel@tonic-gate 					*p = (char)*from;
10620Sstevel@tonic-gate 					len = 1;
10630Sstevel@tonic-gate 				}
10640Sstevel@tonic-gate 			}
10650Sstevel@tonic-gate 			p += len;
10660Sstevel@tonic-gate 			from++;
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 	} else {
10690Sstevel@tonic-gate 		while (*from)
10700Sstevel@tonic-gate 			*p++ = (char)*from++;
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 	*p = '\0';
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	return (ret);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate wchar_t *
str2wstr(char * from,int alloc)10780Sstevel@tonic-gate str2wstr(char *from, int alloc)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	static wchar_t *retbuf;
10810Sstevel@tonic-gate 	static size_t bsiz;
10820Sstevel@tonic-gate 	wchar_t *p, *ret;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	if (alloc) {
10850Sstevel@tonic-gate 		ret = p = xmalloc((strlen(from) + 1) * sizeof (wchar_t));
10860Sstevel@tonic-gate 	} else {
10870Sstevel@tonic-gate 		while (bsiz < (strlen(from) + 1)) {
10880Sstevel@tonic-gate 			if ((p = realloc(retbuf,
10890Sstevel@tonic-gate 			    (bsiz + 256) * sizeof (wchar_t))) == NULL) {
10900Sstevel@tonic-gate 				error(gettext("out of storage"));
10910Sstevel@tonic-gate 			}
10920Sstevel@tonic-gate 			bsiz += 256;
10930Sstevel@tonic-gate 			retbuf = p;
10940Sstevel@tonic-gate 		}
10950Sstevel@tonic-gate 		ret = p = retbuf;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (wide) {
10990Sstevel@tonic-gate 		while (*from) {
11000Sstevel@tonic-gate 			int len;
11010Sstevel@tonic-gate 			wchar_t wc;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 			if ((len = mbtowc(&wc, from, mb_cur_max)) <= 0) {
11040Sstevel@tonic-gate 				wc = *from | INVALID_CHAR;
11050Sstevel@tonic-gate 				len = 1;
11060Sstevel@tonic-gate 			}
11070Sstevel@tonic-gate 			*p++ = wc;
11080Sstevel@tonic-gate 			from += len;
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 	} else {
11110Sstevel@tonic-gate 		while (*from)
11120Sstevel@tonic-gate 			*p++ = (unsigned char) *from++;
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 	*p = 0;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	return (ret);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate static wint_t
myfgetwc(FILE * fp,int idx)11200Sstevel@tonic-gate myfgetwc(FILE *fp, int idx)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	int i, c, len, nb;
11230Sstevel@tonic-gate 	wchar_t wc;
11240Sstevel@tonic-gate 	unsigned char *buf;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	if (fp == NULL)
11270Sstevel@tonic-gate 		fp = ifile[idx];
11280Sstevel@tonic-gate 	else
11290Sstevel@tonic-gate 		idx = 10; /* extra slot */
11300Sstevel@tonic-gate 	buf = ibuffer[idx].buffer;
11310Sstevel@tonic-gate 	nb = ibuffer[idx].nbytes;
11320Sstevel@tonic-gate 	len = 0;
11330Sstevel@tonic-gate 	for (i = 1; i <= mb_cur_max; i++) {
11340Sstevel@tonic-gate 		if (nb < i) {
11350Sstevel@tonic-gate 			c = getc(fp);
11360Sstevel@tonic-gate 			if (c == EOF) {
11370Sstevel@tonic-gate 				if (nb == 0)
11380Sstevel@tonic-gate 					return (WEOF);
11390Sstevel@tonic-gate 				else
11400Sstevel@tonic-gate 					break;
11410Sstevel@tonic-gate 			}
11420Sstevel@tonic-gate 			buf[nb++] = (unsigned char)c;
11430Sstevel@tonic-gate 		}
11440Sstevel@tonic-gate 		if ((len = mbtowc(&wc, (char *)buf, i)) >= 0)
11450Sstevel@tonic-gate 			break;
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 	if (len <= 0) {
11480Sstevel@tonic-gate 		wc = buf[0] | INVALID_CHAR;
11490Sstevel@tonic-gate 		len = 1;
11500Sstevel@tonic-gate 	}
11510Sstevel@tonic-gate 	nb -= len;
11520Sstevel@tonic-gate 	if (nb > 0) {
11530Sstevel@tonic-gate 		for (i = 0; i < nb; i++)
11540Sstevel@tonic-gate 			buf[i] = buf[i + len];
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 	ibuffer[idx].nbytes = nb;
11570Sstevel@tonic-gate 	return (wc);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate static wint_t
myfputwc(wchar_t wc,FILE * fp)11610Sstevel@tonic-gate myfputwc(wchar_t wc, FILE *fp)
11620Sstevel@tonic-gate {
11630Sstevel@tonic-gate 	if (wc & INVALID_CHAR) {
11640Sstevel@tonic-gate 		wc &= ~INVALID_CHAR;
11650Sstevel@tonic-gate 		return (fputc((int)wc, fp));
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 	return (fputwc(wc, fp));
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate static int
myfeof(int idx)11710Sstevel@tonic-gate myfeof(int idx)
11720Sstevel@tonic-gate {
11730Sstevel@tonic-gate 	return (ibuffer[idx].nbytes == 0 && feof(ifile[idx]));
11740Sstevel@tonic-gate }
1175