xref: /onnv-gate/usr/src/lib/libpp/common/ppcontrol.c (revision 10898:1883b621b3ea)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1986-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Glenn Fowler
234887Schin  * AT&T Research
244887Schin  *
254887Schin  * preprocessor control directive support
264887Schin  */
274887Schin 
284887Schin #include "pplib.h"
294887Schin 
304887Schin #include <regex.h>
314887Schin 
324887Schin #define TOKOP_DUP	(1<<0)
334887Schin #define TOKOP_STRING	(1<<1)
344887Schin #define TOKOP_UNSET	(1<<2)
354887Schin 
364887Schin struct edit
374887Schin {
384887Schin 	struct edit*	next;
394887Schin 	regex_t		re;
404887Schin };
414887Schin 
424887Schin struct map
434887Schin {
444887Schin 	struct map*	next;
454887Schin 	regex_t		re;
464887Schin 	struct edit*	edit;
474887Schin };
484887Schin 
494887Schin #define RESTORE		(COLLECTING|CONDITIONAL|DEFINITION|DIRECTIVE|DISABLE|EOF2NL|HEADER|NOSPACE|NOVERTICAL|PASSEOF|STRIP)
504887Schin 
514887Schin /*
524887Schin  * common predicate assertion operations
534887Schin  * op is DEFINE or UNDEF
544887Schin  */
554887Schin 
564887Schin static void
assert(int op,char * pred,char * args)574887Schin assert(int op, char* pred, char* args)
584887Schin {
594887Schin 	register struct pplist*		a;
604887Schin 	register struct ppsymbol*	sym;
614887Schin 	register struct pplist*		p;
624887Schin 	register struct pplist*		q;
634887Schin 
644887Schin 	if (!args) switch (op)
654887Schin 	{
664887Schin 	case DEFINE:
674887Schin 		goto mark;
684887Schin 	case UNDEF:
694887Schin 		a = 0;
704887Schin 		goto unmark;
714887Schin 	}
724887Schin 	if (a = (struct pplist*)hashget(pp.prdtab, pred))
734887Schin 	{
744887Schin 		p = 0;
754887Schin 		q = a;
764887Schin 		while (q)
774887Schin 		{
784887Schin 			if (streq(q->value, args))
794887Schin 			{
804887Schin 				if (op == DEFINE) return;
814887Schin 				q = q->next;
824887Schin 				if (p) p->next = q;
834887Schin 				else a = q;
844887Schin 			}
854887Schin 			else
864887Schin 			{
874887Schin 				p = q;
884887Schin 				q = q->next;
894887Schin 			}
904887Schin 		}
914887Schin 		if (op == UNDEF)
924887Schin 		{
934887Schin 		unmark:
944887Schin 			hashput(pp.prdtab, pred, a);
954887Schin 			if (sym = ppsymref(pp.symtab, pred))
964887Schin 				sym->flags &= ~SYM_PREDICATE;
974887Schin 			return;
984887Schin 		}
994887Schin 	}
1004887Schin 	if (op == DEFINE)
1014887Schin 	{
1024887Schin 		p = newof(0, struct pplist, 1, 0);
1034887Schin 		p->next = a;
1044887Schin 		p->value = strdup(args);
1054887Schin 		hashput(pp.prdtab, NiL, p);
1064887Schin 	mark:
1074887Schin 		if ((pp.state & COMPILE) && pp.truncate) return;
1084887Schin 		if (sym = ppsymset(pp.symtab, pred))
1094887Schin 			sym->flags |= SYM_PREDICATE;
1104887Schin 	}
1114887Schin }
1124887Schin 
1134887Schin /*
1144887Schin  * tokenize string ppop()
1154887Schin  *
1164887Schin  *	op	PP_* op
1174887Schin  *	name	option name
1184887Schin  *	s	string of option values
1194887Schin  *	n	option sense
1204887Schin  *	flags	TOKOP_* flags
1214887Schin  */
1224887Schin 
1234887Schin static void
tokop(int op,char * name,register char * s,register int n,int flags)1244887Schin tokop(int op, char* name, register char* s, register int n, int flags)
1254887Schin {
1264887Schin 	register int	c;
1274887Schin 	register char*	t;
1284887Schin 
1294887Schin 	if (!(flags & TOKOP_UNSET) && !n) error(2, "%s: option cannot be unset", name);
1304887Schin 	else if (!s) ppop(op, s, n);
1314887Schin 	else if (flags & TOKOP_STRING)
1324887Schin 	{
1334887Schin 		PUSH_LINE(s);
1344887Schin 		for (;;)
1354887Schin 		{
1364887Schin 			pp.state &= ~NOSPACE;
1374887Schin 			c = pplex();
1384887Schin 			pp.state |= NOSPACE;
1394887Schin 			if (!c) break;
1404887Schin 			if (c != ' ')
1414887Schin 				ppop(op, (flags & TOKOP_DUP) ? strdup(pp.token) : pp.token, n);
1424887Schin 		}
1434887Schin 		POP_LINE();
1444887Schin 	}
1454887Schin 	else do
1464887Schin 	{
1474887Schin 		while (*s == ' ') s++;
1484887Schin 		for (t = s; *t && *t != ' '; t++);
1494887Schin 		if (*t) *t++ = 0;
1504887Schin 		else t = 0;
1514887Schin 		if (*s) ppop(op, (flags & TOKOP_DUP) ? strdup(s) : s, n);
1524887Schin 	} while (s = t);
1534887Schin }
1544887Schin 
1554887Schin /*
1564887Schin  * return symbol pointer for next token macro (re)definition
1574887Schin  */
1584887Schin 
1594887Schin static struct ppsymbol*
macsym(int tok)1604887Schin macsym(int tok)
1614887Schin {
1624887Schin 	register struct ppsymbol*	sym;
1634887Schin 
1644887Schin 	if (tok != T_ID)
1654887Schin 	{
1664887Schin 		error(2, "%s: invalid macro name", pptokstr(pp.token, 0));
1674887Schin 		return 0;
1684887Schin 	}
1694887Schin 	sym = pprefmac(pp.token, REF_CREATE);
1704887Schin 	if ((sym->flags & SYM_FINAL) && (pp.mode & HOSTED)) return 0;
1714887Schin 	if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
1724887Schin 	{
1734887Schin 		if (!(pp.option & ALLPOSSIBLE))
1744887Schin 			error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
1754887Schin 		return 0;
1764887Schin 	}
1774887Schin 	if (!sym->macro) sym->macro = newof(0, struct ppmacro, 1, 0);
1784887Schin 	return sym;
1794887Schin }
1804887Schin 
1814887Schin /*
1824887Schin  * get one space canonical pplex() line, sans '\n', and place in p
1834887Schin  * x is max+1 pos in p
1844887Schin  * 0 returned if line too large
1854887Schin  * otherwise end of p ('\0') returned
1864887Schin  */
1874887Schin 
1884887Schin static char*
getline(register char * p,char * x,int disable)1894887Schin getline(register char* p, char* x, int disable)
1904887Schin {
1914887Schin 	register int	c;
1924887Schin 	register char*	s;
1934887Schin 	char*		b;
1944887Schin 	long		restore;
1954887Schin 
1964887Schin 	restore = pp.state & (NOSPACE|STRIP);
1974887Schin 	pp.state &= ~(NEWLINE|NOSPACE|STRIP);
1984887Schin 	pp.state |= EOF2NL;
1994887Schin 	b = p;
2004887Schin 	while ((c = pplex()) != '\n')
2014887Schin 	{
2024887Schin 		if (disable)
2034887Schin 		{
2044887Schin 			if (c == ' ')
2054887Schin 				/*ignore*/;
2064887Schin 			else if (disable == 1)
2074887Schin 				disable = (c == T_ID && streq(pp.token, pp.pass)) ? 2 : 0;
2084887Schin 			else
2094887Schin 			{
2104887Schin 				disable = 0;
2114887Schin 				if (c == ':')
2124887Schin 					pp.state |= DISABLE;
2134887Schin 			}
2144887Schin 		}
2154887Schin 		s = pp.token;
2164887Schin 		while (*p = *s++)
2174887Schin 			if (++p >= x)
2184887Schin 			{
2194887Schin 				p = 0;
2204887Schin 				goto done;
2214887Schin 			}
2224887Schin 	}
2234887Schin 	if (p > b && *(p - 1) == ' ')
2244887Schin 		p--;
2254887Schin 	if (p >= x)
2264887Schin 		p = 0;
2274887Schin 	else
2284887Schin 		*p = 0;
2294887Schin  done:
2304887Schin 	pp.state &= ~(NOSPACE|STRIP);
2314887Schin 	pp.state |= restore;
2324887Schin 	return p;
2334887Schin }
2344887Schin 
2354887Schin /*
2364887Schin  * regex error handler
2374887Schin  */
2384887Schin 
2394887Schin void
regfatal(regex_t * p,int level,int code)2404887Schin regfatal(regex_t* p, int level, int code)
2414887Schin {
2424887Schin 	char	buf[128];
2434887Schin 
2444887Schin 	regerror(code, p, buf, sizeof(buf));
2454887Schin 	regfree(p);
2464887Schin 	error(level, "regular expression: %s", buf);
2474887Schin }
2484887Schin 
2494887Schin /*
2504887Schin  * process a single directive line
2514887Schin  */
2524887Schin 
2534887Schin int
ppcontrol(void)2544887Schin ppcontrol(void)
2554887Schin {
2564887Schin 	register char*			p;
2574887Schin 	register int			c;
2584887Schin 	register int			n;
2594887Schin 	register char*			s;
2604887Schin 	register struct ppmacro*	mac;
2614887Schin 	register struct ppsymbol*	sym;
2624887Schin 	struct edit*			edit;
2634887Schin 	struct map*			map;
2644887Schin 	struct ppfile*			fp;
2654887Schin 	int				o;
2664887Schin 	int				directive;
2674887Schin 	long				restore;
2684887Schin 	struct pptuple*			rp;
2694887Schin 	struct pptuple*			tp;
2704887Schin 	char*				v;
2714887Schin 	int				emitted;
2724887Schin 
2734887Schin 	union
2744887Schin 	{
2754887Schin 		struct map*		best;
2764887Schin 		struct ppinstk*		inp;
2774887Schin 		struct pplist*		list;
2784887Schin 		char*			string;
2794887Schin 		struct ppsymbol*	symbol;
2804887Schin 		int			type;
2814887Schin 		PPLINESYNC		linesync;
2824887Schin 	}				var;
2834887Schin 
2844887Schin 	static char			__va_args__[] = "__VA_ARGS__";
2854887Schin 	static int			i0;
2864887Schin 	static int			i1;
2874887Schin 	static int			i2;
2884887Schin 	static int			i3;
2894887Schin 	static int			i4;
2904887Schin 
2914887Schin 	static long			n1;
2924887Schin 	static long			n2;
2934887Schin 	static long			n3;
2944887Schin 
2954887Schin 	static char*			p0;
2964887Schin 	static char*			p1;
2974887Schin 	static char*			p2;
2984887Schin 	static char*			p3;
2994887Schin 	static char*			p4;
3004887Schin 	static char*			p5;
3014887Schin 	static char*			p6;
3024887Schin 
3034887Schin 	static struct ppmacro		old;
3044887Schin 	static char*			formargs[MAXFORMALS];
3054887Schin #if MACKEYARGS
3064887Schin 	static char*			formvals[MAXFORMALS];
3074887Schin #endif
3084887Schin 
3094887Schin 	emitted = 0;
3104887Schin 	if (pp.state & SKIPCONTROL) pp.level--;
3114887Schin 	restore = (pp.state & RESTORE)|NEWLINE;
3124887Schin 	if (pp.state & PASSTHROUGH) restore |= DISABLE;
3134887Schin 	else restore &= ~DISABLE;
3144887Schin 	pp.state &= ~(NEWLINE|RESTORE|SKIPCONTROL);
3154887Schin 	pp.state |= DIRECTIVE|DISABLE|EOF2NL|NOSPACE|NOVERTICAL;
3164887Schin #if COMPATIBLE
3174887Schin 	if ((pp.state & (COMPATIBILITY|STRICT)) == COMPATIBILITY || (pp.mode & HOSTED)) pp.state &= ~NOVERTICAL;
3184887Schin #else
3194887Schin 	if (pp.mode & HOSTED) pp.state &= ~NOVERTICAL;
3204887Schin #endif
3214887Schin 	switch (c = pplex())
3224887Schin 	{
3234887Schin 	case T_DECIMAL:
3244887Schin 	case T_OCTAL:
3254887Schin 		if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
3264887Schin 			error(1, "# <line> [ \"<file>\" [ <type> ] ]: non-standard directive");
3274887Schin 		directive = INCLUDE;
3284887Schin 		goto linesync;
3294887Schin 	case T_ID:
3304887Schin 		switch (directive = (int)hashref(pp.dirtab, pp.token))
3314887Schin 		{
3324887Schin 		case ELIF:
3334887Schin 		else_if:
3344887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3354887Schin 				goto eatdirective;
3364887Schin 			if (pp.control <= pp.in->control)
3374887Schin 			{
3384887Schin 				error(2, "no matching #%s for #%s", dirname(IF), dirname(ELIF));
3394887Schin 				goto eatdirective;
3404887Schin 			}
3414887Schin 			if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
3424887Schin 			if (*pp.control & HADELSE)
3434887Schin 			{
3444887Schin 				error(2, "invalid #%s after #%s", dirname(ELIF), dirname(ELSE));
3454887Schin 				*pp.control |= SKIP;
3464887Schin 				goto eatdirective;
3474887Schin 			}
3484887Schin 			if (*pp.control & KEPT)
3494887Schin 			{
3504887Schin 				*pp.control |= SKIP;
3514887Schin 				goto eatdirective;
3524887Schin 			}
3534887Schin 			if (directive == IFDEF || directive == IFNDEF)
3544887Schin 			{
3554887Schin 				*pp.control &= ~SKIP;
3564887Schin 				goto else_ifdef;
3574887Schin 			}
3584887Schin 		conditional:
3594887Schin 			if (ppexpr(&i1))
3604887Schin 			{
3614887Schin 				*pp.control &= ~SKIP;
3624887Schin 				*pp.control |= KEPT;
3634887Schin 			}
3644887Schin 			else *pp.control |= SKIP;
3654887Schin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
3664887Schin 			goto eatdirective;
3674887Schin 		case ELSE:
3684887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3694887Schin 				goto eatdirective;
3704887Schin 			if ((pp.option & ELSEIF) && (c = pplex()) == T_ID && ((n = (int)hashref(pp.dirtab, pp.token)) == IF || n == IFDEF || n == IFNDEF))
3714887Schin 			{
3724887Schin 				error(1, "#%s %s is non-standard -- use #%s", dirname(directive), dirname(n), dirname(ELIF));
3734887Schin 				directive = n;
3744887Schin 				goto else_if;
3754887Schin 			}
3764887Schin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ELSE));
3774887Schin 			else
3784887Schin 			{
3794887Schin 				if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
3804887Schin 				if (!(*pp.control & KEPT))
3814887Schin 				{
3824887Schin 					*pp.control &= ~SKIP;
3834887Schin 					*pp.control |= HADELSE|KEPT;
3844887Schin 				}
3854887Schin 				else
3864887Schin 				{
3874887Schin 					if (*pp.control & HADELSE) error(2, "more than one #%s for #%s", dirname(ELSE), dirname(IF));
3884887Schin 					*pp.control |= HADELSE|SKIP;
3894887Schin 				}
3904887Schin 			}
3914887Schin 			goto enddirective;
3924887Schin 		case ENDIF:
3934887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
3944887Schin 				goto eatdirective;
3954887Schin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ENDIF));
3964887Schin 			else if (--pp.control == pp.in->control && pp.in->symbol)
3974887Schin 			{
3984887Schin 				if (pp.in->flags & IN_endguard) pp.in->flags |= IN_noguard;
3994887Schin 				else
4004887Schin 				{
4014887Schin 					pp.in->flags &= ~IN_tokens;
4024887Schin 					pp.in->flags |= IN_endguard;
4034887Schin 				}
4044887Schin 			}
4054887Schin 			goto enddirective;
4064887Schin 		case IF:
4074887Schin 		case IFDEF:
4084887Schin 		case IFNDEF:
4094887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
4104887Schin 				goto eatdirective;
4114887Schin 			pushcontrol();
4124887Schin 			SETIFBLOCK(pp.control);
4134887Schin 			if (*pp.control & SKIP)
4144887Schin 			{
4154887Schin 				*pp.control |= KEPT;
4164887Schin 				goto eatdirective;
4174887Schin 			}
4184887Schin 			if (directive == IF) goto conditional;
4194887Schin 		else_ifdef:
4204887Schin 			if ((c = pplex()) == T_ID)
4214887Schin 			{
4224887Schin 				sym = pprefmac(pp.token, REF_IF);
4234887Schin 				if (directive == IFNDEF && pp.control == pp.in->control + 1)
4244887Schin 				{
4254887Schin 					if (pp.in->flags & (IN_defguard|IN_endguard))
4264887Schin 						pp.in->flags |= IN_noguard;
4274887Schin 					else
4284887Schin 					{
4294887Schin 						pp.in->flags |= IN_defguard;
4304887Schin 						if (!(pp.in->flags & IN_tokens))
4314887Schin 							pp.in->symbol = sym ? sym : pprefmac(pp.token, REF_CREATE);
4324887Schin 					}
4334887Schin 				}
4344887Schin 			}
4354887Schin 			else
4364887Schin 			{
4374887Schin 				sym = 0;
4384887Schin 				if (!(pp.mode & HOSTED))
4394887Schin 					error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
4404887Schin 			}
4414887Schin 			*pp.control |= ((sym != 0) == (directive == IFDEF)) ? KEPT : SKIP;
4424887Schin 			goto enddirective;
4434887Schin 		case INCLUDE:
4444887Schin 			if (*pp.control & SKIP)
4454887Schin 			{
4464887Schin 				pp.state |= HEADER;
4474887Schin 				c = pplex();
4484887Schin 				pp.state &= ~HEADER;
4494887Schin 				goto eatdirective;
4504887Schin 			}
4514887Schin 			pp.state &= ~DISABLE;
4524887Schin 			pp.state |= HEADER|STRIP;
453*10898Sroland.mainz@nrubsig.org 			pp.in->flags |= IN_noguard;
4544887Schin 			switch (c = pplex())
4554887Schin 			{
4564887Schin 			case T_STRING:
4574887Schin 				p = pp.token;
4584887Schin 				do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING);
4594887Schin 				*pp.token = 0;
4604887Schin 				pp.token = p;
4614887Schin 				/*FALLTHROUGH*/
4624887Schin 			case T_HEADER:
4634887Schin 			header:
4644887Schin 				if (!*pp.token)
4654887Schin 				{
4664887Schin 					error(2, "#%s: null file name", dirname(INCLUDE));
4674887Schin 					break;
4684887Schin 				}
4694887Schin 				if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX)))
4704887Schin 					error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token);
4714887Schin 				n = ppsearch(pp.token, c, SEARCH_INCLUDE);
4724887Schin 				break;
4734887Schin 			case '<':
4744887Schin 				/*
4754887Schin 				 * HEADEREXPAND|HEADEREXPANDALL gets us here
4764887Schin 				 */
4774887Schin 
4784887Schin 				if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0)))
4794887Schin 					error(3, "out of space");
4804887Schin 				pp.state &= ~NOSPACE;
4814887Schin 				while ((c = pplex()) && c != '>')
4824887Schin 				{
4834887Schin 					v = p + 1;
4844887Schin 					STRCOPY(p, pp.token, s);
4854887Schin 					if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO)
4864887Schin 						p--;
4874887Schin 				}
4884887Schin 				pp.state |= NOSPACE;
4894887Schin 				*p++ = 0;
4904887Schin 				memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf);
4914887Schin 				c = T_HEADER;
4924887Schin 				goto header;
4934887Schin 			default:
4944887Schin 				error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE));
4954887Schin 				goto eatdirective;
4964887Schin 			}
4974887Schin 			goto enddirective;
4984887Schin 		case 0:
4994887Schin 			{
5004887Schin 				regmatch_t	match[10];
5014887Schin 
5024887Schin 				/*UNDENT*/
5034887Schin 	p = pp.valbuf;
5044887Schin 	*p++ = '#';
5054887Schin 	STRCOPY(p, pp.token, s);
5064887Schin 	p0 = p;
5074887Schin 	pp.mode |= EXPOSE;
5084887Schin 	pp.state |= HEADER;
5094887Schin 	p6 = getline(p, &pp.valbuf[MAXTOKEN], 0);
5104887Schin 	pp.state &= ~HEADER;
5114887Schin 	pp.mode &= ~EXPOSE;
5124887Schin 	if (!p6)
5134887Schin 	{
5144887Schin 		*p0 = 0;
5154887Schin 		error(2, "%s: directive too long", pp.valbuf);
5164887Schin 		c = 0;
5174887Schin 		goto eatdirective;
5184887Schin 	}
5194887Schin 	p1 = p2 = p3 = p4 = 0;
5204887Schin 	p5 = *p ? p + 1 : 0;
5214887Schin  checkmap:
5224887Schin 	i0 = *p0;
5234887Schin 	p = pp.valbuf;
5244887Schin 	var.best = 0;
5254887Schin 	n = 0;
5264887Schin 	for (map = (struct map*)pp.maps; map; map = map->next)
5274887Schin 		if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0)))
5284887Schin 		{
5294887Schin 			if ((c = match[0].rm_eo - match[0].rm_so) > n)
5304887Schin 			{
5314887Schin 				n = c;
5324887Schin 				var.best = map;
5334887Schin 			}
5344887Schin 		}
5354887Schin 		else if (i1 != REG_NOMATCH)
5364887Schin 			regfatal(&map->re, 3, i1);
5374887Schin 	c = '\n';
5384887Schin 	if (map = var.best)
5394887Schin 	{
5404887Schin 		if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX)))
5414887Schin 		{
5424887Schin 			*p0 = 0;
5434887Schin 			if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA)))
5444887Schin 				error(1, "%s: non-standard directive", p);
5454887Schin 			*p0 = i0;
5464887Schin 		}
5474887Schin 		if (!(*pp.control & SKIP))
5484887Schin 		{
5494887Schin 			n = 0;
5504887Schin 			for (edit = map->edit; edit; edit = edit->next)
5514887Schin 				if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0)))
5524887Schin 				{
5534887Schin 					n++;
5544887Schin 					if (i0 = regsubexec(&edit->re, p, elementsof(match), match))
5554887Schin 						regfatal(&edit->re, 3, i0);
5564887Schin 					p = edit->re.re_sub->re_buf;
5574887Schin 					if (edit->re.re_sub->re_flags & REG_SUB_STOP)
5584887Schin 						break;
5594887Schin 				}
5604887Schin 				else if (i0 != REG_NOMATCH)
5614887Schin 					regfatal(&edit->re, 3, i0);
5624887Schin 			if (n && *p)
5634887Schin 			{
5644887Schin 				p1 = s = oldof(0, char, 0, strlen(p) + 32);
5654887Schin 				while (*s = *p++) s++;
5664887Schin 				debug((-4, "map: %s", p1));
5674887Schin 				*s++ = '\n';
5684887Schin 				*s = 0;
5694887Schin 				error_info.line++;
5704887Schin 				PUSH_RESCAN(p1);
5714887Schin 				error_info.line--;
5724887Schin 				directive = LINE;
5734887Schin 			}
5744887Schin 		}
5754887Schin 		goto donedirective;
5764887Schin 	}
5774887Schin 	if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX))))
5784887Schin 	{
5794887Schin 		*p0 = 0;
5804887Schin 		error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0));
5814887Schin 		*p0 = i0;
5824887Schin 	}
5834887Schin  pass:
5844887Schin 	if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT)))
5854887Schin 	{
5864887Schin 		*p0 = 0;
5874887Schin 		if (p2) *p2 = 0;
5884887Schin 		if (p4)
5894887Schin 		{
5904887Schin 			if (p4 == p5)
5914887Schin 			{
5924887Schin 				p5 = strcpy(pp.tmpbuf, p5);
5934887Schin 				if (p = strchr(p5, MARK))
5944887Schin 				{
5954887Schin 					s = p;
5964887Schin 					while (*p)
5974887Schin 						if ((*s++ = *p++) == MARK && *p == MARK) p++;
5984887Schin 					*s = 0;
5994887Schin 				}
6004887Schin 			}
6014887Schin 			*p4 = 0;
6024887Schin 		}
6034887Schin 		if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1))
6044887Schin 		{
6054887Schin 			s = p;
6064887Schin 			while (p < p6) switch (*s++ = *p++)
6074887Schin 			{
6084887Schin 			case 0:
6094887Schin 				s = p;
6104887Schin 				break;
6114887Schin 			case MARK:
6124887Schin 				p++;
6134887Schin 				break;
6144887Schin 			}
6154887Schin 			*s = 0;
6164887Schin 		}
6174887Schin 		(*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0);
6184887Schin 		emitted = 1;
6194887Schin 	}
6204887Schin 	goto donedirective;
6214887Schin 
6224887Schin 				/*INDENT*/
6234887Schin 			}
6244887Schin 		}
6254887Schin 		if (*pp.control & SKIP) goto eatdirective;
6264887Schin 		switch (directive)
6274887Schin 		{
6284887Schin #if MACDEF
6294887Schin 		case ENDMAC:
6304887Schin 			c = pplex();
6314887Schin 			error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC));
6324887Schin 			goto enddirective;
6334887Schin #endif
6344887Schin #if MACDEF
6354887Schin 		case MACDEF:
6364887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
6374887Schin 				error(1, "#%s: non-standard directive", pp.token);
6384887Schin 			/*FALLTHROUGH*/
6394887Schin #endif
6404887Schin 		case DEFINE:
6414887Schin 			n2 = error_info.line;
6424887Schin 			if ((c = pplex()) == '#' && directive == DEFINE)
6434887Schin 				goto assertion;
6444887Schin 			if (c == '<')
6454887Schin 			{
6464887Schin 				n = 1;
6474887Schin 				c = pplex();
6484887Schin 			}
6494887Schin 			else
6504887Schin 				n = 0;
6514887Schin 			if (!(sym = macsym(c)))
6524887Schin 				goto eatdirective;
6534887Schin 			if (pp.truncate)
6544887Schin 				ppfsm(FSM_MACRO, pp.token);
6554887Schin 			mac = sym->macro;
6564887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value)
6574887Schin 				goto eatdirective;
6584887Schin 			if (n)
6594887Schin 				goto tuple;
6604887Schin 			old = *mac;
6614887Schin 			i0 = sym->flags;
6624887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
6634887Schin #if MACDEF
6644887Schin 			if (directive == MACDEF)
6654887Schin 				sym->flags |= SYM_MULTILINE;
6664887Schin #endif
6674887Schin 			mac->arity = 0;
6684887Schin 			mac->formals = 0;
6694887Schin 			mac->value = 0;
6704887Schin 			pp.state &= ~NOSPACE;
6714887Schin 			pp.state |= DEFINITION|NOEXPAND;
6724887Schin 			switch (c = pplex())
6734887Schin 			{
6744887Schin 			case '(':
6754887Schin 				sym->flags |= SYM_FUNCTION;
6764887Schin 				pp.state |= NOSPACE;
6774887Schin #if MACKEYARGS
6784887Schin 				if (pp.option & KEYARGS)
6794887Schin 				{
6804887Schin 					n = 2 * MAXTOKEN;
6814887Schin 					p = mac->formals = oldof(0, char, 0, n);
6824887Schin 					if ((c = pplex()) == T_ID) for (;;)
6834887Schin 					{
6844887Schin 						if (mac->arity < MAXFORMALS)
6854887Schin 						{
6864887Schin 							if (mac->arity) p++;
6874887Schin 							formargs[mac->arity] = p;
6884887Schin 							STRAPP(p, pp.token, s);
6894887Schin 							formvals[mac->arity++] = p1 = p;
6904887Schin 							if (mac->arity == 1) *p++ = ' ';
6914887Schin 							*p++ = ' ';
6924887Schin 							*p = 0;
6934887Schin 						}
6944887Schin 						else error(2, "%s: formal argument %s ignored", sym->name, pp.token);
6954887Schin 						switch (c = pplex())
6964887Schin 						{
6974887Schin 						case '=':
6984887Schin 							c = pplex();
6994887Schin 							break;
7004887Schin 						case ',':
7014887Schin 							break;
7024887Schin 						default:
7034887Schin 							goto endformals;
7044887Schin 						}
7054887Schin 						pp.state &= ~NOSPACE;
7064887Schin 						p0 = 0;
7074887Schin 						for (;;)
7084887Schin 						{
7094887Schin 							switch (c)
7104887Schin 							{
7114887Schin 							case '\n':
7124887Schin 								goto endformals;
7134887Schin 							case '(':
7144887Schin 								p0++;
7154887Schin 								break;
7164887Schin 							case ')':
7174887Schin 								if (!p0--)
7184887Schin 								{
7194887Schin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
7204887Schin 									goto endformals;
7214887Schin 								}
7224887Schin 								break;
7234887Schin 							case ',':
7244887Schin 								if (!p0)
7254887Schin 								{
7264887Schin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
7274887Schin 									goto nextformal;
7284887Schin 								}
7294887Schin 								break;
7304887Schin 							case ' ':
7314887Schin 								if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue;
7324887Schin 								break;
7334887Schin 							}
7344887Schin 							STRCOPY(p, pp.token, s);
7354887Schin 							if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals)
7364887Schin 							{
7374887Schin 								n1 = s - mac->formals;
7384887Schin 								for (n = 0; n < mac->arity; n++)
7394887Schin 								{
7404887Schin 									formargs[n] += n1;
7414887Schin 									formvals[n] += n1;
7424887Schin 								}
7434887Schin 								c = p - mac->formals;
7444887Schin 								mac->formals = s;
7454887Schin 								p = mac->formals + c;
7464887Schin 							}
7474887Schin 							c = pplex();
7484887Schin 						}
7494887Schin 					nextformal:
7504887Schin 						pp.state |= NOSPACE;
7514887Schin 						if ((c = pplex()) != T_ID)
7524887Schin 						{
7534887Schin 							c = ',';
7544887Schin 							break;
7554887Schin 						}
7564887Schin 					}
7574887Schin 				endformals: /*NOP*/;
7584887Schin 				}
7594887Schin 				else
7604887Schin #endif
7614887Schin 				{
7624887Schin 					p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1));
7634887Schin 					c = pplex();
7644887Schin #if COMPATIBLE
7654887Schin 					if ((pp.state & COMPATIBILITY) && c == ',')
7664887Schin 					{
7674887Schin 						if ((pp.state & WARN) && !(pp.mode & HOSTED))
7684887Schin 							error(1, "%s: macro formal argument expected", sym->name);
7694887Schin 						while ((c = pplex()) == ',');
7704887Schin 					}
7714887Schin #endif
7724887Schin 					for (;;)
7734887Schin 					{
7744887Schin 						if (c == T_VARIADIC)
7754887Schin 						{
7764887Schin 							if (sym->flags & SYM_VARIADIC)
7774887Schin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
7784887Schin 							sym->flags |= SYM_VARIADIC;
7794887Schin 							v = __va_args__;
7804887Schin 						}
7814887Schin 						else if (c == T_ID)
7824887Schin 						{
7834887Schin 							v = pp.token;
7844887Schin 							if (sym->flags & SYM_VARIADIC)
7854887Schin 								error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v);
7864887Schin 							else if (streq(v, __va_args__))
7874887Schin 								error(2, "%s: %s: invalid macro formal argument", sym->name, v);
7884887Schin 						}
7894887Schin 						else
7904887Schin 							break;
7914887Schin 						if (mac->arity < MAXFORMALS)
7924887Schin 						{
7934887Schin 							for (n = 0; n < mac->arity; n++)
7944887Schin 								if (streq(formargs[n], v))
7954887Schin 									error(2, "%s: %s: duplicate macro formal argument", sym->name, v);
7964887Schin 							formargs[mac->arity++] = p;
7974887Schin 							STRAPP(p, v, s);
7984887Schin 						}
7994887Schin 						else
8004887Schin 							error(2, "%s: %s: macro formal argument ignored", sym->name, v);
8014887Schin 						if ((c = pplex()) == ',')
8024887Schin 						{
8034887Schin 							c = pplex();
8044887Schin #if COMPATIBLE
8054887Schin 							if ((pp.state & COMPATIBILITY) && c == ',')
8064887Schin 							{
8074887Schin 								if ((pp.state & WARN) && !(pp.mode & HOSTED))
8084887Schin 									error(1, "%s: macro formal argument expected", sym->name);
8094887Schin 								while ((c = pplex()) == ',');
8104887Schin 							}
8114887Schin #endif
8124887Schin 						}
8134887Schin 						else if (c != T_VARIADIC)
8144887Schin 							break;
8154887Schin 						else
8164887Schin 						{
8174887Schin 							if (sym->flags & SYM_VARIADIC)
8184887Schin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
8194887Schin 							sym->flags |= SYM_VARIADIC;
8204887Schin 							c = pplex();
8214887Schin 							break;
8224887Schin 						}
8234887Schin 					}
8244887Schin 					if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals)
8254887Schin 					{
8264887Schin 						n1 = s - mac->formals;
8274887Schin 						for (n = 0; n < mac->arity; n++)
8284887Schin 							formargs[n] += n1;
8294887Schin 						mac->formals = s;
8304887Schin 					}
8314887Schin 				}
8324887Schin 				if (!mac->arity)
8334887Schin 				{
8344887Schin 					free(mac->formals);
8354887Schin 					mac->formals = 0;
8364887Schin 				}
8374887Schin 				switch (c)
8384887Schin 				{
8394887Schin 				case ')':
8404887Schin #if MACKEYARGS
8414887Schin 					pp.state |= NOEXPAND|NOSPACE;
8424887Schin #else
8434887Schin 					pp.state |= NOEXPAND;
8444887Schin #endif
8454887Schin 					c = pplex();
8464887Schin 					break;
8474887Schin 				default:
8484887Schin 					error(2, "%s: invalid macro formal argument list", sym->name);
8494887Schin 					if (mac->formals)
8504887Schin 					{
8514887Schin 						free(mac->formals);
8524887Schin 						mac->formals = 0;
8534887Schin 						mac->arity = 0;
8544887Schin 					}
8554887Schin 					free(mac);
8564887Schin 					sym->macro = 0;
8574887Schin 					goto eatdirective;
8584887Schin 				}
8594887Schin 				pp.state &= ~NOSPACE;
8604887Schin 				break;
8614887Schin 			case ' ':
8624887Schin 			case '\t':
8634887Schin 				c = pplex();
8644887Schin 				break;
8654887Schin 			}
8664887Schin 			n = 2 * MAXTOKEN;
8674887Schin #if MACKEYARGS
8684887Schin 			p1 = p;
8694887Schin #endif
8704887Schin 			p = mac->value = oldof(0, char, 0, n);
8714887Schin 			var.type = 0;
8724887Schin 			n1 = 0;
8734887Schin #if MACDEF
8744887Schin 			i2 = i3 = 0;
8754887Schin 			n3 = pp.state;
8764887Schin #endif
8774887Schin 			if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
8784887Schin 				switch (c)
8794887Schin 				{
8804887Schin 				case '+':
8814887Schin 				case '-':
8824887Schin 				case '&':
8834887Schin 				case '|':
8844887Schin 				case '<':
8854887Schin 				case '>':
8864887Schin 				case ':':
8874887Schin 				case '=':
8884887Schin 					*p++ = ' ';
8894887Schin 					break;
8904887Schin 				}
8914887Schin 			o = 0;
8924887Schin 			for (;;)
8934887Schin 			{
8944887Schin 				switch (c)
8954887Schin 				{
8964887Schin 				case T_ID:
8974887Schin 					for (c = 0; c < mac->arity; c++)
8984887Schin 						if (streq(formargs[c], pp.token))
8994887Schin 						{
9004887Schin #if COMPATIBLE
9014887Schin 							if (!(pp.state & COMPATIBILITY))
9024887Schin #endif
9034887Schin 							if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' ';
9044887Schin 							*p++ = MARK;
9054887Schin #if COMPATIBLE
9064887Schin 							if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C';
9074887Schin 							else
9084887Schin #endif
9094887Schin 							*p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A';
9104887Schin 							*p++ = c + ARGOFFSET;
9118462SApril.Chin@Sun.COM 							if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)) && var.type != TOK_TOKCAT && !(var.type & TOK_ID))
9128462SApril.Chin@Sun.COM 							{
9138462SApril.Chin@Sun.COM 								s = pp.in->nextchr;
9148462SApril.Chin@Sun.COM 								while ((c = *s++) && (c == ' ' || c == '\t'));
9158462SApril.Chin@Sun.COM 								if (c == '\n')
9168462SApril.Chin@Sun.COM 									c = 0;
9178462SApril.Chin@Sun.COM 								else if (c == '*' && *s == ')')
9188462SApril.Chin@Sun.COM 									c = ')';
9198462SApril.Chin@Sun.COM 								else if (c == '=' || ppisidig(c) || c == *s || *s == '=')
9208462SApril.Chin@Sun.COM 									c = 0;
9218462SApril.Chin@Sun.COM 								if (o != '.' && o != T_PTRMEM)
9228462SApril.Chin@Sun.COM 								{
9238462SApril.Chin@Sun.COM 									if ((var.type & TOK_ID) || o == ' ' || ppisseparate(o))
9248462SApril.Chin@Sun.COM 										o = 0;
9258462SApril.Chin@Sun.COM 									if (!((o == 0 || o == '(' || o == ')' || o == '[' || o == ']' || o == ',' || o == '|' || o == ';' || o == '{' || o == '}') && (c == '(' || c == ')' || c == '[' || c == ']' || c == ',' || c == '|' || c == ';' || c == '}' || c == 0)) && !(o == '*' && c == ')'))
9268462SApril.Chin@Sun.COM 										error(1, "%s: %s: formal should be parenthesized in macro value (t=%x o=%#c c=%#c)", sym->name, pp.token, var.type, o, c);
9278462SApril.Chin@Sun.COM 								}
9288462SApril.Chin@Sun.COM 							}
9294887Schin 							var.type = TOK_FORMAL|TOK_ID;
9304887Schin 							c = '>';
9314887Schin 							goto checkvalue;
9324887Schin 						}
9334887Schin 					if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token))
9344887Schin 					{
9354887Schin 					case V_DEFAULT:
9364887Schin 					case V_EMPTY:
9374887Schin 						sym->flags |= SYM_EMPTY;
9384887Schin 						break;
9394887Schin 					}
9404887Schin 					else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden)
9414887Schin 					{
9424887Schin 						for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev);
9434887Schin 						p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token);
9444887Schin 						var.type = TOK_ID;
9454887Schin 						goto checkvalue;
9464887Schin 					}
9474887Schin 					var.type = TOK_ID;
9484887Schin 					break;
9494887Schin 				case '#':
9504887Schin 					var.type = 0;
9514887Schin #if MACDEF
9524887Schin 					if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break;
9534887Schin #else
9544887Schin 					if (!(sym->flags & SYM_FUNCTION)) break;
9554887Schin #endif
9564887Schin 					pp.state |= NOSPACE;
9574887Schin 					c = pplex();
9584887Schin 					if (c == '@')
9594887Schin 					{
9604887Schin 						c = pplex();
9614887Schin 						i4 = 'S';
9624887Schin 					}
9634887Schin 					else i4 = 'Q';
9644887Schin 					pp.state &= ~NOSPACE;
9654887Schin 					if (c != T_ID) c = mac->arity;
9664887Schin 					else for (c = 0; c < mac->arity; c++)
9674887Schin 						if (streq(formargs[c], pp.token))
9684887Schin 							break;
9694887Schin 					if (c >= mac->arity)
9704887Schin 					{
9714887Schin #if MACDEF
9724887Schin 						if (sym->flags & SYM_MULTILINE)
9734887Schin 						{
9744887Schin 							if (n3 & NEWLINE)
9754887Schin 							{
9764887Schin 								pp.state &= ~NOEXPAND;
9774887Schin 								switch ((int)hashref(pp.dirtab, pp.token))
9784887Schin 								{
9794887Schin 								case ENDMAC:
9804887Schin 									if (!i2--) goto gotdefinition;
9814887Schin 									break;
9824887Schin 								case INCLUDE:
9834887Schin 									/* PARSE HEADER constant */
9844887Schin 									break;
9854887Schin 								case MACDEF:
9864887Schin 									i2++;
9874887Schin 									break;
9884887Schin 								}
9894887Schin 								*p++ = '#';
9904887Schin 							}
9914887Schin 						}
9924887Schin 						else
9934887Schin #endif
9944887Schin #if COMPATIBLE
9954887Schin 						if (pp.state & COMPATIBILITY) *p++ = '#';
9964887Schin 						else
9974887Schin #endif
9984887Schin 						error(2, "# must precede a formal parameter");
9994887Schin 					}
10004887Schin 					else
10014887Schin 					{
10024887Schin 						if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' ';
10034887Schin 						*p++ = MARK;
10044887Schin 						*p++ = i4;
10054887Schin 						*p++ = c + ARGOFFSET;
10064887Schin 						goto checkvalue;
10074887Schin 					}
10084887Schin 					break;
10094887Schin 				case T_TOKCAT:
10104887Schin 					if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token);
10114887Schin 					else
10124887Schin 					{
10134887Schin 						if (*(p - 1) == ' ') p--;
10144887Schin 						if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
10154887Schin 					}
10164887Schin 					pp.state |= NOSPACE;
10174887Schin 					c = pplex();
10184887Schin 					pp.state &= ~NOSPACE;
10194887Schin 					if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT));
10204887Schin 					var.type = TOK_TOKCAT;
10214887Schin 					continue;
10224887Schin 				case '(':
10234887Schin 					if (*pp.token == '#')
10244887Schin 					{
10254887Schin 						var.type = TOK_BUILTIN;
10264887Schin 						n1++;
10274887Schin 					}
10284887Schin 					else
10294887Schin 					{
10304887Schin 						var.type = 0;
10314887Schin 						if (n1) n1++;
10324887Schin 					}
10334887Schin 					break;
10344887Schin 				case ')':
10354887Schin 					var.type = 0;
10364887Schin 					if (n1) n1--;
10374887Schin 					break;
10384887Schin 				case T_STRING:
10394887Schin 				case T_CHARCONST:
10404887Schin 					pp.state &= ~NOEXPAND;
10414887Schin 					var.type = 0;
10424887Schin 					if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND;
10434887Schin #if COMPATIBLE
10444887Schin 					/*UNDENT*/
10454887Schin 
10464887Schin 	if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION)))
10474887Schin 	{
10484887Schin 		char*	v;
10494887Schin 
10504887Schin 		s = pp.token;
10514887Schin 		for (;;)
10524887Schin 		{
10534887Schin 			if (!*s) goto checkvalue;
10544887Schin 			if (ppisid(*s))
10554887Schin 			{
10564887Schin 				v = s;
10574887Schin 				while (ppisid(*++s));
10584887Schin 				i1 = *s;
10594887Schin 				*s = 0;
10604887Schin 				for (c = 0; c < mac->arity; c++)
10614887Schin 					if (streq(formargs[c], v))
10624887Schin 					{
10634887Schin 						*p++ = MARK;
10644887Schin 						*p++ = 'C';
10654887Schin 						*p++ = c + ARGOFFSET;
10664887Schin 						if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token)
10674887Schin 						{
10684887Schin 						case '"':
10694887Schin 							error(1, "use the # operator to \"...\" quote macro arguments");
10704887Schin 							break;
10714887Schin 						case '\'':
10724887Schin 							error(1, "macro arguments should be '...' quoted before substitution");
10734887Schin 							break;
10744887Schin 						}
10754887Schin 						goto quotearg;
10764887Schin 					}
10774887Schin 				STRCOPY2(p, v);
10784887Schin 			quotearg:
10794887Schin 				*s = i1;
10804887Schin 			}
10814887Schin 			else *p++ = *s++;
10824887Schin 		}
10834887Schin 	}
10844887Schin 					/*INDENT*/
10854887Schin #endif
10864887Schin 					break;
10874887Schin 				case '\n':
10884887Schin #if MACDEF
10894887Schin 					if (sym->flags & SYM_MULTILINE)
10904887Schin 					{
10914887Schin 						if (pp.state & EOF2NL)
10924887Schin 						{
10934887Schin 							error_info.line++;
10944887Schin 							pp.state |= HIDDEN;
10954887Schin 							pp.hidden++;
10964887Schin 							var.type = 0;
10974887Schin 							if (!i3++)
10984887Schin 								goto checkvalue;
10994887Schin 							break;
11004887Schin 						}
11014887Schin 						pp.state |= EOF2NL;
11024887Schin 						error(2, "%s: missing #%s", sym->name, dirname(ENDMAC));
11034887Schin 					}
11044887Schin #endif
11054887Schin 					goto gotdefinition;
11064887Schin 				case 0:
11074887Schin 					c = '\n';
11084887Schin 					goto gotdefinition;
11094887Schin #if COMPATIBLE
11104887Schin 				case ' ':
11114887Schin 					if (pp.state & COMPATIBILITY) var.type = 0;
11124887Schin 					if (pp.option & PRESERVE) break;
11134887Schin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
11144887Schin 					goto checkvalue;
11154887Schin 				case '\t':
11164887Schin 					if (var.type & TOK_ID)
11174887Schin 					{
11184887Schin 						while ((c = pplex()) == '\t');
11194887Schin 						if (c == T_ID)
11204887Schin 						{
11214887Schin 							if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
11224887Schin 							var.type = TOK_TOKCAT;
11234887Schin 							if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments");
11244887Schin 						}
11254887Schin 						else var.type = 0;
11264887Schin 						continue;
11274887Schin 					}
11284887Schin 					var.type = 0;
11294887Schin 					if (pp.option & PRESERVE) break;
11304887Schin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
11314887Schin 					goto checkvalue;
11324887Schin #endif
11334887Schin 				case MARK:
11344887Schin 					pp.state &= ~NOEXPAND;
11354887Schin 					/*FALLTHROUGH*/
11364887Schin 
11374887Schin 				default:
11384887Schin 					var.type = 0;
11394887Schin 					break;
11404887Schin 				}
11414887Schin 				STRCOPY(p, pp.token, s);
11424887Schin 			checkvalue:
11434887Schin 				o = c;
11444887Schin 				if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value)
11454887Schin 				{
11464887Schin 					c = p - mac->value;
11474887Schin 					mac->value = s;
11484887Schin 					p = mac->value + c;
11494887Schin 				}
11504887Schin #if MACDEF
11514887Schin 				n3 = pp.state;
11524887Schin #endif
11534887Schin 				c = pplex();
11544887Schin 			}
11554887Schin 		gotdefinition:
11564887Schin 			while (p > mac->value && *(p - 1) == ' ') p--;
11574887Schin 			if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
11584887Schin 				switch (o)
11594887Schin 				{
11604887Schin 				case '+':
11614887Schin 				case '-':
11624887Schin 				case '&':
11634887Schin 				case '|':
11644887Schin 				case '<':
11654887Schin 				case '>':
11664887Schin 				case ':':
11674887Schin 				case '=':
11684887Schin 					*p++ = ' ';
11694887Schin 					break;
11704887Schin 				}
11714887Schin 			*p = 0;
11724887Schin #if MACKEYARGS
11734887Schin 			if (!mac->arity) /* ok */;
11744887Schin 			else if (pp.option & KEYARGS)
11754887Schin 			{
11764887Schin 				p0 = mac->formals;
11774887Schin 				mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1);
11784887Schin 				s = (char*)&mac->formkeys[mac->arity];
11794887Schin 				(void)memcpy(s, p0, p1 - p0 + 1);
11804887Schin 				free(p0);
11814887Schin 				for (n = 0; n < mac->arity; n++)
11824887Schin 				{
11834887Schin 					mac->formkeys[n].name = s + (formargs[n] - p0);
11844887Schin 					mac->formkeys[n].value = s + (formvals[n] - p0);
11854887Schin 				}
11864887Schin 			}
11874887Schin 			else
11884887Schin #endif
11894887Schin 			for (n = 1; n < mac->arity; n++)
11904887Schin 				*(formargs[n] - 1) = ',';
11914887Schin 			if (old.value)
11924887Schin 			{
11934887Schin 				if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined;
11944887Schin 				if (!old.formals)
11954887Schin 				{
11964887Schin 					if (mac->formals) goto redefined;
11974887Schin 				}
11984887Schin 				else if (mac->formals)
11994887Schin 				{
12004887Schin #if MACKEYARGS
12014887Schin 					if (pp.option & KEYARGS)
12024887Schin 					{
12034887Schin 						for (n = 0; n < mac->arity; n++)
12044887Schin 							if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value))
12054887Schin 								goto redefined;
12064887Schin 					}
12074887Schin 					else
12084887Schin #endif
12094887Schin 					if (!streq(mac->formals, old.formals)) goto redefined;
12104887Schin 				}
12114887Schin #if MACKEYARGS
12124887Schin 				if (pp.option & KEYARGS)
12134887Schin 				{
12144887Schin 					if (mac->formkeys) free(mac->formkeys);
12154887Schin 					mac->formkeys = old.formkeys;
12164887Schin 				}
12174887Schin 				else
12184887Schin #endif
12194887Schin 				{
12204887Schin 					if (mac->formals) free(mac->formals);
12214887Schin 					mac->formals = old.formals;
12224887Schin 				}
12234887Schin 				free(mac->value);
12244887Schin 				mac->value = old.value;
12254887Schin 				goto benign;
12264887Schin 			redefined:
12274887Schin 				if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL))
12284887Schin 					error(1, "%s redefined", sym->name);
12294887Schin #if MACKEYARGS
12304887Schin 				if ((pp.option & KEYARGS) && mac->formkeys)
12314887Schin 					free(mac->formkeys);
12324887Schin #endif
12334887Schin #if MACKEYARGS
12344887Schin 				if (!(pp.option & KEYARGS))
12354887Schin #endif
12364887Schin 				if (old.formals) free(old.formals);
12374887Schin 				free(old.value);
12384887Schin 			}
12394887Schin 			else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name);
12404887Schin 			mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0);
12414887Schin 			if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT)))
12424887Schin 			{
12434887Schin 				ppsync();
12444887Schin 				ppprintf("#%s %s", dirname(DEFINE), sym->name);
12454887Schin 				if (sym->flags & SYM_FUNCTION)
12464887Schin 				{
12474887Schin 					ppputchar('(');
12484887Schin 					if (mac->formals)
12494887Schin 						ppprintf("%s", mac->formals);
12504887Schin 					ppputchar(')');
12514887Schin 				}
12524887Schin 				if ((p = mac->value) && *p)
12534887Schin 				{
12544887Schin 					ppputchar(' ');
12554887Schin 					i0 = 0;
12564887Schin 					while (n = *p++)
12574887Schin 					{
12584887Schin 						if (n != MARK || (n = *p++) == MARK)
12594887Schin 						{
12604887Schin 							ppputchar(n);
12614887Schin 							i0 = ppisid(n);
12624887Schin 						}
12634887Schin 						else
12644887Schin 						{
12654887Schin 							if (n == 'Q')
12664887Schin 								ppputchar('#');
12674887Schin 							else if (i0)
12684887Schin 							{
12694887Schin 								ppputchar('#');
12704887Schin 								ppputchar('#');
12714887Schin 							}
12724887Schin 							s = formargs[*p++ - ARGOFFSET];
12734887Schin 							while ((n = *s++) && n != ',')
12744887Schin 								ppputchar(n);
12754887Schin 							if (ppisid(*p) || *p == MARK)
12764887Schin 							{
12774887Schin 								ppputchar('#');
12784887Schin 								ppputchar('#');
12794887Schin 							}
12804887Schin 							i0 = 0;
12814887Schin 						}
12824887Schin 						ppcheckout();
12834887Schin 					}
12844887Schin 				}
12854887Schin 				emitted = 1;
12864887Schin 			}
12874887Schin 		benign:
12884887Schin 			if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN;
12894887Schin 			if (pp.option & FINAL) sym->flags |= SYM_FINAL;
12904887Schin 			if (pp.mode & INIT) sym->flags |= SYM_INIT;
12914887Schin 			if (pp.option & INITIAL) sym->flags |= SYM_INITIAL;
12924887Schin 			if (pp.state & NOEXPAND)  sym->flags |= SYM_NOEXPAND;
12934887Schin 			if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED;
12944887Schin 			if (pp.mode & READONLY) sym->flags |= SYM_READONLY;
12954887Schin 			if (pp.macref) (*pp.macref)(sym, error_info.file, n2, mac ? error_info.line - n2 + 1 : REF_UNDEF, mac ? strsum(mac->value, (long)mac->arity) : 0L);
12964887Schin 			break;
12974887Schin 		assertion:
12984887Schin 			c = pplex();
12994887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
13004887Schin 				error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0));
13014887Schin 			if (c != T_ID)
13024887Schin 			{
13034887Schin 				error(2, "%s: invalid predicate name", pptokstr(pp.token, 0));
13044887Schin 				goto eatdirective;
13054887Schin 			}
13064887Schin 			switch ((int)hashref(pp.strtab, pp.token))
13074887Schin 			{
13084887Schin 			case X_DEFINED:
13094887Schin 			case X_EXISTS:
13104887Schin 			case X_STRCMP:
13114887Schin 				error(2, "%s is a builtin predicate", pp.token);
13124887Schin 				goto eatdirective;
13134887Schin 			case X_SIZEOF:
13144887Schin 				error(2, "%s cannot be a predicate", pp.token);
13154887Schin 				goto eatdirective;
13164887Schin 			}
13174887Schin 			strcpy(pp.tmpbuf, pp.token);
13184887Schin 			switch (pppredargs())
13194887Schin 			{
13204887Schin 			case T_ID:
13214887Schin 			case T_STRING:
13224887Schin 				assert(directive, pp.tmpbuf, pp.args);
13234887Schin 				break;
13244887Schin 			case 0:
13254887Schin 				assert(directive, pp.tmpbuf, NiL);
13264887Schin 				break;
13274887Schin 			default:
13284887Schin 				error(2, "invalid predicate argument list");
13294887Schin 				goto eatdirective;
13304887Schin 			}
13314887Schin 			break;
13324887Schin 		tuple:
13334887Schin 			pp.state |= DEFINITION|NOEXPAND|NOSPACE;
13344887Schin 			rp = 0;
13354887Schin 			tp = mac->tuple;
13364887Schin 			if (!tp && !mac->value)
13374887Schin 				ppfsm(FSM_MACRO, sym->name);
13384887Schin 			while ((c = pplex()) && c != '>' && c != '\n')
13394887Schin 			{
13404887Schin 				for (; tp; tp = tp->nomatch)
13414887Schin 					if (streq(tp->token, pp.token))
13424887Schin 						break;
13434887Schin 				if (!tp)
13444887Schin 				{
13454887Schin 					if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token))))
13464887Schin 						error(3, "out of space");
13474887Schin 					strcpy(tp->token, pp.token);
13484887Schin 					if (rp)
13494887Schin 					{
13504887Schin 						tp->nomatch = rp;
13514887Schin 						rp->nomatch = tp;
13524887Schin 					}
13534887Schin 					else
13544887Schin 					{
13554887Schin 						tp->nomatch = mac->tuple;
13564887Schin 						mac->tuple = tp;
13574887Schin 					}
13584887Schin 				}
13594887Schin 				rp = tp;
13604887Schin 				tp = tp->match;
13614887Schin 			}
13624887Schin 			pp.state &= ~NOSPACE;
13634887Schin 			if (!rp || c != '>')
13644887Schin 				error(2, "%s: > omitted in tuple macro definition", sym->name);
13654887Schin 			else
13664887Schin 			{
13674887Schin 				n = 2 * MAXTOKEN;
13684887Schin 				p = v = oldof(0, char, 0, n);
13694887Schin 				while ((c = pplex()) && c != '\n')
13704887Schin 					if (p > v || c != ' ')
13714887Schin 					{
13724887Schin 						STRCOPY(p, pp.token, s);
13734887Schin 						if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v)
13744887Schin 						{
13754887Schin 							c = p - v;
13764887Schin 							v = s;
13774887Schin 							p = v + c;
13784887Schin 						}
13794887Schin 					}
13804887Schin 				while (p > v && *(p - 1) == ' ')
13814887Schin 					p--;
13824887Schin 				n = p - v;
13834887Schin 				tp = newof(0, struct pptuple, 1, n);
13844887Schin 				strcpy(tp->token, v);
13854887Schin 				tp->match = rp->match;
13864887Schin 				rp->match = tp;
13874887Schin 			}
13884887Schin 			goto benign;
13894887Schin 		case WARNING:
13904887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
13914887Schin 				error(1, "#%s: non-standard directive", pp.token);
13924887Schin 			/*FALLTHROUGH*/
13934887Schin 		case ERROR:
13944887Schin 			pp.state &= ~DISABLE;
13954887Schin 			p = pp.tmpbuf;
13964887Schin 			while ((c = pplex()) != '\n')
13974887Schin 				if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN])
13984887Schin 				{
13994887Schin 					STRCOPY(p, pp.token, s);
14004887Schin 					pp.state &= ~NOSPACE;
14014887Schin 				}
14024887Schin 			*p = 0;
14034887Schin 			p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error");
14044887Schin 			n = (directive == WARNING) ? 1 : 3;
14054887Schin 			error(n, "%s", p);
14064887Schin 			break;
14074887Schin 		case LET:
14084887Schin 			n2 = error_info.line;
14094887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
14104887Schin 				error(1, "#%s: non-standard directive", pp.token);
14114887Schin 			if (!(sym = macsym(c = pplex()))) goto eatdirective;
14124887Schin 			if ((c = pplex()) != '=')
14134887Schin 			{
14144887Schin 				error(2, "%s: = expected", sym->name);
14154887Schin 				goto eatdirective;
14164887Schin 			}
14174887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC);
14184887Schin 			mac = sym->macro;
14194887Schin 			mac->arity = 0;
14204887Schin 			if (mac->value)
14214887Schin 			{
14224887Schin 				if (!(sym->flags & SYM_REDEFINE) && !sym->hidden)
14234887Schin 					error(1, "%s: redefined", sym->name);
14244887Schin #if MACKEYARGS
14254887Schin 				if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys);
14264887Schin 				else
14274887Schin #endif
14284887Schin 				free(mac->formals);
14294887Schin 				mac->formals = 0;
14304887Schin 				n = strlen(mac->value) + 1;
14314887Schin 			}
14324887Schin 			else
14334887Schin 			{
14344887Schin 				ppfsm(FSM_MACRO, sym->name);
14354887Schin 				n = 0;
14364887Schin 			}
14374887Schin 			n1 = ppexpr(&i1);
14384887Schin 			if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1);
14394887Schin 			else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1);
14404887Schin 			if (n < ++c)
14414887Schin 			{
14424887Schin 				if (mac->value) free(mac->value);
14434887Schin 				mac->value = oldof(0, char, 0, c);
14444887Schin 			}
14454887Schin 			strcpy(mac->value, pp.tmpbuf);
14464887Schin 			sym->flags |= SYM_REDEFINE;
14474887Schin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
14484887Schin 			goto benign;
14494887Schin 		case LINE:
14504887Schin 			pp.state &= ~DISABLE;
14514887Schin 			if ((c = pplex()) == '#')
14524887Schin 			{
14534887Schin 				c = pplex();
14544887Schin 				directive = INCLUDE;
14554887Schin 			}
14564887Schin 			if (c != T_DECIMAL && c != T_OCTAL)
14574887Schin 			{
14584887Schin 				error(1, "#%s: line number expected", dirname(LINE));
14594887Schin 				goto eatdirective;
14604887Schin 			}
14614887Schin 		linesync:
14624887Schin 			n = error_info.line;
14634887Schin 			error_info.line = strtol(pp.token, NiL, 0);
14644887Schin 			if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED))
14654887Schin 				error(1, "#%s: line number should be > 0", dirname(LINE));
14664887Schin 			pp.state &= ~DISABLE;
14674887Schin 			pp.state |= STRIP;
14684887Schin 			switch (c = pplex())
14694887Schin 			{
14704887Schin 			case T_STRING:
14714887Schin 				s = error_info.file;
1472*10898Sroland.mainz@nrubsig.org 				if (*(p = pp.token))
1473*10898Sroland.mainz@nrubsig.org 					pathcanon(p, 0);
14744887Schin 				fp = ppsetfile(p);
14754887Schin 				error_info.file = fp->name;
14764887Schin 				if (error_info.line == 1)
1477*10898Sroland.mainz@nrubsig.org 					ppmultiple(fp, INC_IGNORE);
14784887Schin 				switch (c = pplex())
14794887Schin 				{
14804887Schin 				case '\n':
14814887Schin 					break;
14824887Schin 				case T_DECIMAL:
14834887Schin 				case T_OCTAL:
14844887Schin 					if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
14854887Schin 						error(1, "#%s: integer file type argument is non-standard", dirname(LINE));
14864887Schin 					break;
14874887Schin 				default:
14884887Schin 					error(1, "#%s: integer file type argument expected", dirname(LINE));
14894887Schin 					break;
14904887Schin 				}
14914887Schin 				if (directive == LINE) pp.in->flags &= ~IN_ignoreline;
14924887Schin 				else if (pp.incref)
14934887Schin 				{
14944887Schin 					if (error_info.file != s)
14954887Schin 					{
14964887Schin 						switch (*pp.token)
14974887Schin 						{
14984887Schin 						case PP_sync_push:
14994887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15004887Schin 							else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
15014887Schin 							break;
15024887Schin 						case PP_sync_pop:
15034887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15044887Schin 							else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP);
15054887Schin 							break;
15064887Schin 						case PP_sync_ignore:
15074887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15084887Schin 							else
15094887Schin 							{
15104887Schin 								(*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE);
15114887Schin 								error_info.file = s;
15124887Schin 							}
15134887Schin 							break;
15144887Schin 						default:
15154887Schin 							if (*s)
15164887Schin 							{
15174887Schin 								if (fp == pp.insert)
15184887Schin 									pp.insert = 0;
15194887Schin 								else if (error_info.line == 1 && !pp.insert)
15204887Schin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
15214887Schin 								else
15224887Schin 								{
15234887Schin 									if (!pp.insert) pp.insert = ppgetfile(s);
15244887Schin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
15254887Schin 								}
15264887Schin 							}
15274887Schin 							break;
15284887Schin 						}
15294887Schin 					}
15304887Schin 				}
15314887Schin 				break;
15324887Schin 			case '\n':
15334887Schin 				break;
15344887Schin 			default:
15354887Schin 				error(1, "#%s: \"file-name\" expected", dirname(LINE));
15364887Schin 				break;
15374887Schin 			}
15384887Schin 			if (directive == LINE && (pp.in->flags & IN_ignoreline))
15394887Schin 				error_info.line = n + 1;
15404887Schin 			else
15414887Schin 			{
15424887Schin 				pp.hidden = 0;
15434887Schin 				pp.state &= ~HIDDEN;
15444887Schin 				if (pp.linesync)
15454887Schin 				{
15464887Schin #if CATSTRINGS
15474887Schin 					if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
15484887Schin 					else
15494887Schin #endif
15504887Schin 					{
15514887Schin 						s = pp.lineid;
15524887Schin 						n = pp.flags;
15534887Schin 						if (directive == LINE)
15544887Schin 						{
15554887Schin 							pp.flags &= ~PP_linetype;
15564887Schin 							if (pp.macref) pp.lineid = dirname(LINE);
15574887Schin 						}
15584887Schin 						(*pp.linesync)(error_info.line, error_info.file);
15594887Schin 						pp.flags = n;
15604887Schin 						pp.lineid = s;
15614887Schin 					}
15624887Schin 				}
15634887Schin 			}
15644887Schin 			directive = LINE;
15654887Schin 			break;
15664887Schin 		case PRAGMA:
15674887Schin 			/*
15684887Schin 			 * #pragma [STDC] [pass:] [no]option [arg ...]
15694887Schin 			 *
15704887Schin 			 * pragma args are not expanded by default
15714887Schin 			 *
15724887Schin 			 * if STDC is present then it is silently passed on
15734887Schin 			 *
15744887Schin 			 * if pass is pp.pass then the option is used
15754887Schin 			 * and verified but is not passed on
15764887Schin 			 *
15774887Schin 			 * if pass is omitted then the option is passed on
15784887Schin 			 *
15794887Schin 			 * otherwise if pass is non-null and not pp.pass then
15804887Schin 			 * the option is passed on but not used
15814887Schin 			 *
15824887Schin 			 * if the line does not match this form then
15834887Schin 			 * it is passed on unchanged
15844887Schin 			 *
15854887Schin 			 *	#directive   pass:  option  [...]
15864887Schin 			 *	^         ^  ^   ^  ^     ^  ^   ^
15874887Schin 			 *	pp.valbuf p0 p1  p2 p3    p4 p5  p6
15884887Schin 			 *
15894887Schin 			 * p?	0 if component omitted
15904887Schin 			 * i0	0 if ``no''option
15914887Schin 			 */
15924887Schin 
15934887Schin 			p = pp.valbuf;
15944887Schin 			*p++ = '#';
15954887Schin 			STRCOPY(p, pp.token, s);
15964887Schin 			p0 = p;
15974887Schin 			if (pp.option & PRAGMAEXPAND)
15984887Schin 				pp.state &= ~DISABLE;
15994887Schin 			if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND))))
16004887Schin 			{
16014887Schin 				*p0 = 0;
16024887Schin 				error(2, "%s: directive too long", pp.valbuf);
16034887Schin 				c = 0;
16044887Schin 				goto eatdirective;
16054887Schin 			}
16064887Schin 			p1 = ++p;
16074887Schin 			while (ppisid(*p))
16084887Schin 				p++;
16094887Schin 			if (p == p1)
16104887Schin 			{
16114887Schin 				p5 = p;
16124887Schin 				p4 = 0;
16134887Schin 				p3 = 0;
16144887Schin 				p2 = 0;
16154887Schin 				p1 = 0;
16164887Schin 			}
16174887Schin 			else if (*p != ':')
16184887Schin 			{
16194887Schin 				p5 = *p ? p + (*p == ' ') : 0;
16204887Schin 				p4 = p;
16214887Schin 				p3 = p1;
16224887Schin 				p2 = 0;
16234887Schin 				p1 = 0;
16244887Schin 			}
16254887Schin 			else
16264887Schin 			{
16274887Schin 				p2 = p++;
16284887Schin 				p3 = p;
16294887Schin 				while (ppisid(*p))
16304887Schin 					p++;
16314887Schin 				if (p == p3)
16324887Schin 				{
16334887Schin 					p4 = p1;
16344887Schin 					p3 = 0;
16354887Schin 					p2 = 0;
16364887Schin 					p1 = 0;
16374887Schin 				}
16384887Schin 				else
16394887Schin 					p4 = p;
16404887Schin 				p5 = *p4 ? p4 + (*p4 == ' ') : 0;
16414887Schin 			}
16424887Schin 			if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4))
16434887Schin 				goto pass;
16448462SApril.Chin@Sun.COM 			if ((pp.state & WARN) && (pp.mode & (HOSTED|RELAX|PEDANTIC)) == PEDANTIC)
16454887Schin 				error(1, "#%s: non-standard directive", dirname(PRAGMA));
16464887Schin 			i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o';
16474887Schin 			if (!p3)
16484887Schin 				goto checkmap;
16494887Schin 			if (p1)
16504887Schin 			{
16514887Schin 				*p2 = 0;
16524887Schin 				n = streq(p1, pp.pass);
16534887Schin 				*p2 = ':';
16544887Schin 				if (!n)
16554887Schin 					goto checkmap;
16564887Schin 			}
16574887Schin 			else
16584887Schin 				n = 0;
16594887Schin 			i2 = *p4;
16604887Schin 			*p4 = 0;
16614887Schin 			if (((i1 = (int)hashref(pp.strtab, p3 + (i0 ? 0 : 2))) < 1 || i1 > X_last_option) && (i0 || (i1 = (int)hashref(pp.strtab, p3)) > X_last_option))
16624887Schin 				i1 = 0;
16634887Schin 			if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX)))
16644887Schin 			{
16654887Schin 				if (pp.optflags[i1] & OPT_GLOBAL)
16664887Schin 					goto donedirective;
16674887Schin 				if (n || (pp.mode & WARN))
16684887Schin 				{
16694887Schin 					n = 0;
16704887Schin 					error(1, "#%s: non-standard directive ignored", dirname(PRAGMA));
16714887Schin 				}
16724887Schin 				i1 = 0;
16734887Schin 			}
16744887Schin 			if (!n)
16754887Schin 			{
16764887Schin 				if (!(pp.optflags[i1] & OPT_GLOBAL))
16774887Schin 				{
16784887Schin 					*p4 = i2;
16794887Schin 					goto checkmap;
16804887Schin 				}
16814887Schin 				if (!(pp.optflags[i1] & OPT_PASS))
16824887Schin 					n = 1;
16834887Schin 			}
16844887Schin 			else if (!i1)
16854887Schin 				error(2, "%s: unknown option", p1);
16864887Schin 			else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
16874887Schin 				error(1, "%s: non-standard option", p1);
16884887Schin 			p = p5;
16894887Schin 			switch (i1)
16904887Schin 			{
16914887Schin 			case X_ALLMULTIPLE:
16924887Schin 				ppop(PP_MULTIPLE, i0);
16934887Schin 				break;
16944887Schin 			case X_ALLPOSSIBLE:
16954887Schin 				setoption(ALLPOSSIBLE, i0);
16964887Schin 				break;
16974887Schin 			case X_BUILTIN:
16984887Schin 				setmode(BUILTIN, i0);
16994887Schin 				break;
17004887Schin 			case X_CATLITERAL:
17014887Schin 				setmode(CATLITERAL, i0);
17024887Schin 				if (pp.mode & CATLITERAL)
17034887Schin 					setoption(STRINGSPLIT, 0);
17044887Schin 				break;
17054887Schin 			case X_CDIR:
17064887Schin 				tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
17074887Schin 				break;
17084887Schin 			case X_CHECKPOINT:
17094887Schin #if CHECKPOINT
17104887Schin 				ppload(p);
17114887Schin #else
17124887Schin 				error(3, "%s: preprocessor not compiled with checkpoint enabled", p3);
17134887Schin #endif
17144887Schin 				break;
17154887Schin 			case X_CHOP:
17164887Schin 				tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
17174887Schin 				break;
17184887Schin 			case X_COMPATIBILITY:
17194887Schin 				ppop(PP_COMPATIBILITY, i0);
17204887Schin 				break;
17214887Schin 			case X_DEBUG:
17224887Schin 				error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0;
17234887Schin 				break;
17244887Schin 			case X_ELSEIF:
17254887Schin 				setoption(ELSEIF, i0);
17264887Schin 				break;
17274887Schin 			case X_EXTERNALIZE:
17284887Schin 				setmode(EXTERNALIZE, i0);
17294887Schin 				break;
17304887Schin 			case X_FINAL:
17314887Schin 				setoption(FINAL, i0);
17324887Schin 				break;
17334887Schin 			case X_HEADEREXPAND:
17344887Schin 				setoption(HEADEREXPAND, i0);
17354887Schin 				break;
17364887Schin 			case X_HEADEREXPANDALL:
17374887Schin 				setoption(HEADEREXPANDALL, i0);
17384887Schin 				break;
17394887Schin 			case X_HIDE:
17404887Schin 			case X_NOTE:
17414887Schin 				PUSH_LINE(p);
17424887Schin 				/* UNDENT...*/
17434887Schin 	while (c = pplex())
17444887Schin 	{
17454887Schin 		if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token);
17464887Schin 		else if (sym = ppsymset(pp.symtab, pp.token))
17474887Schin 		{
17484887Schin 			if (i1 == X_NOTE)
17494887Schin 			{
17504887Schin 				sym->flags &= ~SYM_NOTICED;
17514887Schin 				ppfsm(FSM_MACRO, sym->name);
17524887Schin 			}
17534887Schin 			else if (i0)
17544887Schin 			{
17554887Schin 				if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0)))
17564887Schin 					error(3, "out of space");
17574887Schin 				if (!sym->macro)
17584887Schin 					ppfsm(FSM_MACRO, sym->name);
17594887Schin 				if (!sym->hidden->level++)
17604887Schin 				{
17614887Schin 					pp.hiding++;
17624887Schin 					if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
17634887Schin 					{
17644887Schin 						sym->hidden->macro = sym->macro;
17654887Schin 						sym->macro = 0;
17664887Schin 						sym->hidden->flags = sym->flags;
17674887Schin 						sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
17684887Schin 					}
17694887Schin 				}
17704887Schin 			}
17714887Schin 			else if (sym->hidden)
17724887Schin 			{
17734887Schin 				if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
17744887Schin 				{
17754887Schin 					if (mac->formals) free(mac->formals);
17764887Schin 					free(mac->value);
17774887Schin 					free(mac);
17784887Schin 					sym->macro = 0;
17794887Schin 					sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
17804887Schin 				}
17814887Schin 				if (!--sym->hidden->level)
17824887Schin 				{
17834887Schin 					pp.hiding--;
17844887Schin 					if (sym->hidden->macro)
17854887Schin 					{
17864887Schin 						sym->macro = sym->hidden->macro;
17874887Schin 						sym->flags = sym->hidden->flags;
17884887Schin 					}
17894887Schin 					free(sym->hidden);
17904887Schin 					sym->hidden = 0;
17914887Schin 				}
17924887Schin 			}
17934887Schin 		}
17944887Schin 	}
17954887Schin 				/*...INDENT*/
17964887Schin 				POP_LINE();
17974887Schin 				break;
17984887Schin 			case X_HOSTDIR:
17994887Schin 				tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
18004887Schin 				break;
18014887Schin 			case X_HOSTED:
18024887Schin 				setmode(HOSTED, i0);
18034887Schin 				break;
18044887Schin 			case X_HOSTEDTRANSITION:
18054887Schin 				setmode(HOSTEDTRANSITION, i0);
18064887Schin 				break;
18074887Schin 			case X_ID:
18084887Schin 				tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
18094887Schin 				break;
18104887Schin 			case X_IGNORE:
18114887Schin 				tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
18124887Schin 				break;
18134887Schin 			case X_INCLUDE:
18144887Schin 				tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP);
18154887Schin 				break;
18164887Schin 			case X_INITIAL:
18174887Schin 				setoption(INITIAL, i0);
18184887Schin 				break;
18194887Schin 			case X_KEYARGS:
18204887Schin 				ppop(PP_KEYARGS, i0);
18214887Schin 				break;
18224887Schin 			case X_LINE:
18234887Schin 				if (pp.linesync) pp.olinesync = pp.linesync;
18244887Schin 				pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0;
18254887Schin 				break;
18264887Schin 			case X_LINEBASE:
18274887Schin 				ppop(PP_LINEBASE, i0);
18284887Schin 				break;
18294887Schin 			case X_LINEFILE:
18304887Schin 				ppop(PP_LINEFILE, i0);
18314887Schin 				break;
18324887Schin 			case X_LINEID:
18334887Schin 				ppop(PP_LINEID, i0 ? p : (char*)0);
18344887Schin 				break;
18354887Schin 			case X_LINETYPE:
18364887Schin 				ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0);
18374887Schin 				break;
18384887Schin 			case X_MACREF:
18394887Schin 				if (!p)
18404887Schin 				{
18414887Schin 					if (i0 && !pp.macref)
18424887Schin 					{
18434887Schin 						ppop(PP_LINETYPE, 1);
18444887Schin 						ppop(PP_MACREF, ppmacref);
18454887Schin 					}
18464887Schin 					else error(2, "%s: option cannot be unset", p3);
18474887Schin 				}
18484887Schin 				else if (s = strchr(p, ' '))
18494887Schin 				{
18504887Schin 					if (pp.macref && (s = strchr(p, ' ')))
18514887Schin 					{
18524887Schin 						*s++ = 0;
18534887Schin 						c = strtol(s, NiL, 0);
18544887Schin 						var.type = pp.truncate;
18554887Schin 						pp.truncate = PPTOKSIZ;
18564887Schin 						(*pp.macref)(pprefmac(p, REF_CREATE), error_info.file, error_info.line - (c == REF_NORMAL ? 2 : 1), c, (s = strchr(s, ' ')) ? strtol(s, NiL, 0) : 0L);
18574887Schin 						pp.truncate = var.type;
18584887Schin 					}
18594887Schin 					error_info.line -= 2;
18604887Schin 				}
18614887Schin 				break;
18624887Schin 			case X_MAP:
18634887Schin 				/*UNDENT*/
18644887Schin 	/*
18654887Schin 	 * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ]
18664887Schin 	 */
18674887Schin 
18684887Schin 	if (!i0)
18694887Schin 	{
18704887Schin 		error(2, "%s: option cannot be unset", p3);
18714887Schin 		goto donedirective;
18724887Schin 	}
18734887Schin 	if (!p5)
18744887Schin 	{
18754887Schin 		error(2, "%s: address argument expected", p3);
18764887Schin 		goto donedirective;
18774887Schin 	}
18784887Schin 	PUSH_LINE(p5);
18794887Schin 	while ((c = pplex()) == T_ID)
18804887Schin 	{
18814887Schin 		sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token);
18824887Schin 		if (c = (int)hashget(pp.dirtab, s))
18834887Schin 		{
18844887Schin 			hashput(pp.dirtab, 0, 0);
18854887Schin 			hashput(pp.dirtab, pp.tmpbuf, c);
18864887Schin 		}
18874887Schin 		if (c = (int)hashget(pp.strtab, s))
18884887Schin 		{
18894887Schin 			hashput(pp.strtab, 0, 0);
18904887Schin 			hashput(pp.strtab, pp.tmpbuf, c);
18914887Schin 		}
18924887Schin 	}
18934887Schin 	if (c != T_STRING || !*(s = pp.token))
18944887Schin 	{
18954887Schin 		if (c)
18964887Schin 			error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0));
18974887Schin 		goto eatmap;
18984887Schin 	}
18994887Schin 	map = newof(0, struct map, 1, 0);
19004887Schin 
19014887Schin 	/*
19024887Schin 	 * /from/
19034887Schin 	 */
19044887Schin 
19054887Schin 	if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL))
19064887Schin 		regfatal(&map->re, 3, i0);
19074887Schin 	if (*(s += map->re.re_npat))
19084887Schin 	{
19094887Schin 		error(2, "%s: invalid characters after pattern: %s ", p3, s);
19104887Schin 		goto eatmap;
19114887Schin 	}
19124887Schin 
19134887Schin 	/*
19144887Schin 	 * /old/new/[flags]
19154887Schin 	 */
19164887Schin 
19174887Schin 	edit = 0;
19184887Schin 	while ((c = pplex()) == T_STRING)
19194887Schin 	{
19204887Schin 		if (!*(s = pp.token))
19214887Schin 		{
19224887Schin 			error(2, "%s: substitution argument expected", p3);
19234887Schin 			goto eatmap;
19244887Schin 		}
19254887Schin 		if (edit)
19264887Schin 			edit = edit->next = newof(0, struct edit, 1, 0);
19274887Schin 		else
19284887Schin 			edit = map->edit = newof(0, struct edit, 1, 0);
19294887Schin 		if (!(i0 = regcomp(&edit->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL)) && !(i0 = regsubcomp(&edit->re, s += edit->re.re_npat, NiL, 0, 0)))
19304887Schin 			s += edit->re.re_npat;
19314887Schin 		if (i0)
19324887Schin 			regfatal(&edit->re, 3, i0);
19334887Schin 		if (*s)
19344887Schin 		{
19354887Schin 			error(2, "%s: invalid characters after substitution: %s ", p3, s);
19364887Schin 			goto eatmap;
19374887Schin 		}
19384887Schin 	}
19394887Schin 	if (c)
19404887Schin 	{
19414887Schin 		error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0));
19424887Schin 		goto eatmap;
19434887Schin 	}
19444887Schin 	map->next = (struct map*)pp.maps;
19454887Schin 	pp.maps = (char*)map;
19464887Schin  eatmap:
19474887Schin 	POP_LINE();
19484887Schin 				/*INDENT*/
19494887Schin 				break;
19504887Schin 			case X_MAPINCLUDE:
19514887Schin 				ppmapinclude(NiL, p5);
19524887Schin 				break;
19534887Schin 			case X_MODERN:
19544887Schin 				setoption(MODERN, i0);
19554887Schin 				break;
19564887Schin 			case X_MULTIPLE:
19574887Schin 				n = 1;
1958*10898Sroland.mainz@nrubsig.org 				if (pp.in->type == IN_FILE || pp.in->type == IN_RESCAN)
1959*10898Sroland.mainz@nrubsig.org 					ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_IGNORE);
19604887Schin 				break;
19614887Schin 			case X_NATIVE:
19624887Schin 				setoption(NATIVE, i0);
19634887Schin 				break;
19644887Schin 			case X_OPSPACE:
19654887Schin 				ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0);
19664887Schin 				break;
19674887Schin 			case X_PASSTHROUGH:
19684887Schin 				ppop(PP_PASSTHROUGH, i0);
19694887Schin 				break;
19704887Schin 			case X_PEDANTIC:
19714887Schin 				ppop(PP_PEDANTIC, i0);
19724887Schin 				break;
19734887Schin 			case X_PLUSCOMMENT:
19744887Schin 				ppop(PP_PLUSCOMMENT, i0);
19754887Schin 				break;
19764887Schin 			case X_PLUSPLUS:
19774887Schin 				ppop(PP_PLUSPLUS, i0);
19784887Schin 				break;
19794887Schin 			case X_PLUSSPLICE:
19804887Schin 				setoption(PLUSSPLICE, i0);
19814887Schin 				break;
19824887Schin 			case X_PRAGMAEXPAND:
19834887Schin 				setoption(PRAGMAEXPAND, i0);
19844887Schin 				break;
19854887Schin 			case X_PRAGMAFLAGS:
19864887Schin 				tokop(PP_PRAGMAFLAGS, p3, p, i0, 0);
19874887Schin 				break;
19884887Schin 			case X_PREDEFINED:
19894887Schin 				setoption(PREDEFINED, i0);
19904887Schin 				break;
19914887Schin 			case X_PREFIX:
19924887Schin 				setoption(PREFIX, i0);
19934887Schin 				break;
19944887Schin 			case X_PRESERVE:
19954887Schin 				setoption(PRESERVE, i0);
19964887Schin 				if (pp.option & PRESERVE)
19974887Schin 				{
19984887Schin 					setmode(CATLITERAL, 0);
19994887Schin 					ppop(PP_COMPATIBILITY, 1);
20004887Schin 					ppop(PP_TRANSITION, 0);
20014887Schin 					ppop(PP_PLUSCOMMENT, 1);
20024887Schin 					ppop(PP_SPACEOUT, 1);
20034887Schin 					setoption(STRINGSPAN, 1);
20044887Schin 					setoption(STRINGSPLIT, 0);
20054887Schin 					ppop(PP_HOSTDIR, "-", 1);
20064887Schin 				}
20074887Schin 				break;
20084887Schin 			case X_PROTOTYPED:
20094887Schin 				/*
20104887Schin 				 * this option doesn't bump the token count
20114887Schin 				 */
20124887Schin 
20134887Schin 				n = 1;
20144887Schin 				directive = ENDIF;
20154887Schin #if PROTOTYPE
20164887Schin 				setoption(PROTOTYPED, i0);
20174887Schin #else
20184887Schin 				error(1, "preprocessor not compiled with prototype conversion enabled");
20194887Schin #endif
20204887Schin 				break;
20214887Schin 			case X_PROTO:
20224887Schin 				setoption(NOPROTO, !i0);
20234887Schin 				break;
20244887Schin 			case X_QUOTE:
20254887Schin 				tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
20264887Schin 				break;
20274887Schin 			case X_READONLY:
20284887Schin 				setmode(READONLY, i0);
20294887Schin 				break;
20304887Schin 			case X_REGUARD:
20314887Schin 				setoption(REGUARD, i0);
20324887Schin 				break;
20334887Schin 			case X_RESERVED:
20344887Schin 				tokop(PP_RESERVED, p3, p, i0, 0);
20354887Schin 				break;
20364887Schin 			case X_SPACEOUT:
20374887Schin 				if (!(pp.state & (COMPATIBILITY|COMPILE)))
20384887Schin 					ppop(PP_SPACEOUT, i0);
20394887Schin 				break;
20404887Schin 			case X_SPLICECAT:
20414887Schin 				setoption(SPLICECAT, i0);
20424887Schin 				break;
20434887Schin 			case X_SPLICESPACE:
20444887Schin 				setoption(SPLICESPACE, i0);
20454887Schin 				break;
20464887Schin 			case X_STANDARD:
20474887Schin 				tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
20484887Schin 				break;
20494887Schin 			case X_STRICT:
20504887Schin 				ppop(PP_STRICT, i0);
20514887Schin 				break;
20524887Schin 			case X_STRINGSPAN:
20534887Schin 				setoption(STRINGSPAN, i0);
20544887Schin 				break;
20554887Schin 			case X_STRINGSPLIT:
20564887Schin 				setoption(STRINGSPLIT, i0);
20574887Schin 				if (pp.option & STRINGSPLIT)
20584887Schin 					setmode(CATLITERAL, 0);
20594887Schin 				break;
20604887Schin 			case X_SYSTEM_HEADER:
20614887Schin 				if (i0)
20624887Schin 				{
20634887Schin 					pp.mode |= HOSTED;
20644887Schin 					pp.flags |= PP_hosted;
20654887Schin 					pp.in->flags |= IN_hosted;
20664887Schin 				}
20674887Schin 				else
20684887Schin 				{
20694887Schin 					pp.mode &= ~HOSTED;
20704887Schin 					pp.flags &= ~PP_hosted;
20714887Schin 					pp.in->flags &= ~PP_hosted;
20724887Schin 				}
20734887Schin 				break;
20744887Schin 			case X_TEST:
20754887Schin 				ppop(PP_TEST, p);
20764887Schin 				break;
20774887Schin 			case X_TEXT:
20784887Schin 				if (!(pp.option & KEEPNOTEXT))
20794887Schin 					setstate(NOTEXT, !i0);
20804887Schin 				break;
20814887Schin 			case X_TRANSITION:
20824887Schin 				ppop(PP_TRANSITION, i0);
20834887Schin 				if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0);
20844887Schin 				break;
20854887Schin 			case X_TRUNCATE:
20864887Schin 				ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0);
20874887Schin 				break;
20884887Schin 			case X_VENDOR:
20894887Schin 				tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
20904887Schin 				break;
20914887Schin 			case X_VERSION:
20924887Schin 				if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT))
20934887Schin 				{
20944887Schin 					sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version);
20954887Schin 					(*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n);
20964887Schin 					if (pp.linesync && !n)
20974887Schin 						(*pp.linesync)(error_info.line, error_info.file);
20984887Schin 					emitted = 1;
20994887Schin 				}
21004887Schin 				break;
21014887Schin 			case X_WARN:
21024887Schin 				ppop(PP_WARN, i0);
21034887Schin 				break;
21044887Schin 			case X_ZEOF:
21054887Schin 				setoption(ZEOF, i0);
21064887Schin 				break;
21074887Schin #if DEBUG
21084887Schin 			case 0:
21094887Schin 			case X_INCLUDED:
21104887Schin 			case X_NOTICED:
21114887Schin 			case X_OPTION:
21124887Schin 			case X_STATEMENT:
21134887Schin 				break;
21144887Schin 			default:
21154887Schin 				error(PANIC, "%s: option recognized but not implemented", pp.valbuf);
21164887Schin 				break;
21174887Schin #endif
21184887Schin 			}
21194887Schin 			*p4 = i2;
21204887Schin 			if (!n)
21214887Schin 				goto checkmap;
21224887Schin 			goto donedirective;
21234887Schin 		case RENAME:
21244887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
21254887Schin 				error(1, "#%s: non-standard directive", pp.token);
21264887Schin 			if ((c = pplex()) != T_ID)
21274887Schin 			{
21284887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21294887Schin 				goto eatdirective;
21304887Schin 			}
21314887Schin 			if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro)
21324887Schin 				goto eatdirective;
21334887Schin 			if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
21344887Schin 			{
21354887Schin 				if (!(pp.option & ALLPOSSIBLE))
21364887Schin 					error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
21374887Schin 				goto eatdirective;
21384887Schin 			}
21394887Schin 			if ((c = pplex()) != T_ID)
21404887Schin 			{
21414887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21424887Schin 				goto eatdirective;
21434887Schin 			}
21444887Schin 			var.symbol = pprefmac(pp.token, REF_CREATE);
21454887Schin 			if (mac = var.symbol->macro)
21464887Schin 			{
21474887Schin 				if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY))
21484887Schin 				{
21494887Schin 					if (!(pp.option & ALLPOSSIBLE))
21504887Schin 						error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active");
21514887Schin 					goto eatdirective;
21524887Schin 				}
21534887Schin 				if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL))
21544887Schin 					error(1, "%s redefined", var.symbol->name);
21554887Schin 				if (mac->formals) free(mac->formals);
21564887Schin 				free(mac->value);
21574887Schin 				free(mac);
21584887Schin 			}
21594887Schin 			ppfsm(FSM_MACRO, var.symbol->name);
21604887Schin 			var.symbol->flags = sym->flags;
21614887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
21624887Schin 			var.symbol->macro = sym->macro;
21634887Schin 			sym->macro = 0;
21644887Schin 			break;
21654887Schin 		case UNDEF:
21664887Schin 			if ((c = pplex()) != T_ID)
21674887Schin 			{
21684887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
21694887Schin 				goto eatdirective;
21704887Schin 			}
21714887Schin 			if (sym = pprefmac(pp.token, REF_DELETE))
21724887Schin 			{
21734887Schin 				if (mac = sym->macro)
21744887Schin 				{
21754887Schin 					if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
21764887Schin 					{
21774887Schin 						if (!(pp.option & ALLPOSSIBLE))
21784887Schin 							error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
21794887Schin 						goto eatdirective;
21804887Schin 					}
21814887Schin 					if (mac->formals) free(mac->formals);
21824887Schin 					free(mac->value);
21834887Schin 					free(mac);
21844887Schin 					mac = sym->macro = 0;
21854887Schin 				}
21864887Schin 				if ((pp.option & (DEFINITIONS|PREDEFINITIONS|REGUARD)) && !sym->hidden && !(sym->flags & SYM_MULTILINE) && ((pp.option & PREDEFINITIONS) || !(pp.mode & INIT)) && ((pp.option & (DEFINITIONS|PREDEFINITIONS)) || !(pp.state & NOTEXT)))
21874887Schin 				{
21884887Schin 					ppsync();
21894887Schin 					ppprintf("#%s %s", dirname(UNDEF), sym->name);
21904887Schin 					emitted = 1;
21914887Schin 				}
21924887Schin 				sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
21934887Schin 				n2 = error_info.line;
21944887Schin 				goto benign;
21954887Schin 			}
21964887Schin 			else pprefmac(pp.token, REF_UNDEF);
21974887Schin 			break;
21984887Schin #if DEBUG
21994887Schin 		default:
22004887Schin 			error(PANIC, "#%s: directive recognized but not implemented", pp.token);
22014887Schin 			goto eatdirective;
22024887Schin #endif
22034887Schin 		}
22044887Schin 		break;
22054887Schin 	case '\n':
22064887Schin 		break;
22074887Schin 	default:
22084887Schin 		error(1, "%s: invalid directive name", pptokstr(pp.token, 0));
22094887Schin 		goto eatdirective;
22104887Schin 	}
22114887Schin  enddirective:
22124887Schin #if COMPATIBLE
22134887Schin 	if (c != '\n' && !(pp.state & COMPATIBILITY))
22144887Schin #else
22154887Schin 	if (c != '\n')
22164887Schin #endif
22174887Schin 	{
22184887Schin 		pp.state |= DISABLE|NOSPACE;
22194887Schin 		if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC)
22204887Schin 			error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0));
22214887Schin 	}
22224887Schin  eatdirective:
22234887Schin 	if (c != '\n')
22244887Schin 	{
22254887Schin 		pp.state |= DISABLE;
22264887Schin 		while (pplex() != '\n');
22274887Schin 	}
22284887Schin  donedirective:
22294887Schin #if _HUH_2002_05_09
22304887Schin 	if (!(pp.state & EOF2NL))
22314887Schin 		error(2, "%s in directive", pptokchr(0));
22324887Schin #endif
22334887Schin 	pp.state &= ~RESTORE;
22344887Schin 	pp.mode &= ~RELAX;
22354887Schin 	if (!(*pp.control & SKIP))
22364887Schin 	{
22374887Schin 		pp.state |= restore;
22384887Schin 		switch (directive)
22394887Schin 		{
22404887Schin 		case LINE:
22414887Schin 			return 0;
22424887Schin 		case INCLUDE:
22434887Schin 			if (pp.include)
22444887Schin 			{
22454887Schin 				error_info.line++;
22464887Schin 				PUSH_FILE(pp.include, n);
22474887Schin 				if (!pp.vendor && (pp.found->type & TYPE_VENDOR))
22484887Schin 					pp.vendor = 1;
22494887Schin 				pp.include = 0;
22504887Schin 				return 0;
22514887Schin 			}
22524887Schin 			if (pp.incref)
22534887Schin 				(*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE);
22544887Schin 			else if (pp.linesync && pp.macref)
22554887Schin 			{
22564887Schin 				pp.flags |= PP_lineignore;
22574887Schin 				(*pp.linesync)(error_info.line, ppgetfile(pp.path)->name);
22584887Schin 			}
22594887Schin 			/*FALLTHROUGH*/
22604887Schin 		default:
22614887Schin 			pp.in->flags |= IN_tokens;
22624887Schin 			/*FALLTHROUGH*/
22634887Schin 		case ENDIF:
22644887Schin 			error_info.line++;
22654887Schin 			if (emitted)
22664887Schin 			{
22674887Schin 				ppputchar('\n');
22684887Schin 				ppcheckout();
22694887Schin 			}
22704887Schin 			else
22714887Schin 			{
22724887Schin 				pp.state |= HIDDEN;
22734887Schin 				pp.hidden++;
22744887Schin 			}
22754887Schin 			return 0;
22764887Schin 		}
22774887Schin 	}
22784887Schin 	pp.state |= restore|HIDDEN|SKIPCONTROL;
22794887Schin 	pp.hidden++;
22804887Schin 	pp.level++;
22814887Schin 	error_info.line++;
22824887Schin 	return 0;
22834887Schin }
22844887Schin 
22854887Schin /*
22864887Schin  * grow the pp nesting control stack
22874887Schin  */
22884887Schin 
22894887Schin void
ppnest(void)22904887Schin ppnest(void)
22914887Schin {
22924887Schin 	register struct ppinstk*	ip;
22934887Schin 	int				oz;
22944887Schin 	int				nz;
22954887Schin 	long				adjust;
22964887Schin 	long*				op;
22974887Schin 	long*				np;
22984887Schin 
22994887Schin 	oz = pp.constack;
23004887Schin 	op = pp.maxcon - oz + 1;
23014887Schin 	nz = oz * 2;
23024887Schin 	np = newof(op, long, nz, 0);
23034887Schin 	if (adjust = (np - op))
23044887Schin 	{
23054887Schin 		ip = pp.in;
23064887Schin 		do
23074887Schin 		{
23084887Schin 			if (ip->control)
23094887Schin 				ip->control += adjust;
23104887Schin 		} while (ip = ip->prev);
23114887Schin 	}
23124887Schin 	pp.control = np + oz;
23134887Schin 	pp.constack = nz;
23144887Schin 	pp.maxcon = np + nz - 1;
23154887Schin }
2316