1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * Glenn Fowler
23*4887Schin  * AT&T Research
24*4887Schin  *
25*4887Schin  * preprocessor control directive support
26*4887Schin  */
27*4887Schin 
28*4887Schin #include "pplib.h"
29*4887Schin 
30*4887Schin #include <regex.h>
31*4887Schin 
32*4887Schin #define TOKOP_DUP	(1<<0)
33*4887Schin #define TOKOP_STRING	(1<<1)
34*4887Schin #define TOKOP_UNSET	(1<<2)
35*4887Schin 
36*4887Schin struct edit
37*4887Schin {
38*4887Schin 	struct edit*	next;
39*4887Schin 	regex_t		re;
40*4887Schin };
41*4887Schin 
42*4887Schin struct map
43*4887Schin {
44*4887Schin 	struct map*	next;
45*4887Schin 	regex_t		re;
46*4887Schin 	struct edit*	edit;
47*4887Schin };
48*4887Schin 
49*4887Schin #define RESTORE		(COLLECTING|CONDITIONAL|DEFINITION|DIRECTIVE|DISABLE|EOF2NL|HEADER|NOSPACE|NOVERTICAL|PASSEOF|STRIP)
50*4887Schin 
51*4887Schin /*
52*4887Schin  * common predicate assertion operations
53*4887Schin  * op is DEFINE or UNDEF
54*4887Schin  */
55*4887Schin 
56*4887Schin static void
57*4887Schin assert(int op, char* pred, char* args)
58*4887Schin {
59*4887Schin 	register struct pplist*		a;
60*4887Schin 	register struct ppsymbol*	sym;
61*4887Schin 	register struct pplist*		p;
62*4887Schin 	register struct pplist*		q;
63*4887Schin 
64*4887Schin 	if (!args) switch (op)
65*4887Schin 	{
66*4887Schin 	case DEFINE:
67*4887Schin 		goto mark;
68*4887Schin 	case UNDEF:
69*4887Schin 		a = 0;
70*4887Schin 		goto unmark;
71*4887Schin 	}
72*4887Schin 	if (a = (struct pplist*)hashget(pp.prdtab, pred))
73*4887Schin 	{
74*4887Schin 		p = 0;
75*4887Schin 		q = a;
76*4887Schin 		while (q)
77*4887Schin 		{
78*4887Schin 			if (streq(q->value, args))
79*4887Schin 			{
80*4887Schin 				if (op == DEFINE) return;
81*4887Schin 				q = q->next;
82*4887Schin 				if (p) p->next = q;
83*4887Schin 				else a = q;
84*4887Schin 			}
85*4887Schin 			else
86*4887Schin 			{
87*4887Schin 				p = q;
88*4887Schin 				q = q->next;
89*4887Schin 			}
90*4887Schin 		}
91*4887Schin 		if (op == UNDEF)
92*4887Schin 		{
93*4887Schin 		unmark:
94*4887Schin 			hashput(pp.prdtab, pred, a);
95*4887Schin 			if (sym = ppsymref(pp.symtab, pred))
96*4887Schin 				sym->flags &= ~SYM_PREDICATE;
97*4887Schin 			return;
98*4887Schin 		}
99*4887Schin 	}
100*4887Schin 	if (op == DEFINE)
101*4887Schin 	{
102*4887Schin 		p = newof(0, struct pplist, 1, 0);
103*4887Schin 		p->next = a;
104*4887Schin 		p->value = strdup(args);
105*4887Schin 		hashput(pp.prdtab, NiL, p);
106*4887Schin 	mark:
107*4887Schin 		if ((pp.state & COMPILE) && pp.truncate) return;
108*4887Schin 		if (sym = ppsymset(pp.symtab, pred))
109*4887Schin 			sym->flags |= SYM_PREDICATE;
110*4887Schin 	}
111*4887Schin }
112*4887Schin 
113*4887Schin /*
114*4887Schin  * tokenize string ppop()
115*4887Schin  *
116*4887Schin  *	op	PP_* op
117*4887Schin  *	name	option name
118*4887Schin  *	s	string of option values
119*4887Schin  *	n	option sense
120*4887Schin  *	flags	TOKOP_* flags
121*4887Schin  */
122*4887Schin 
123*4887Schin static void
124*4887Schin tokop(int op, char* name, register char* s, register int n, int flags)
125*4887Schin {
126*4887Schin 	register int	c;
127*4887Schin 	register char*	t;
128*4887Schin 
129*4887Schin 	if (!(flags & TOKOP_UNSET) && !n) error(2, "%s: option cannot be unset", name);
130*4887Schin 	else if (!s) ppop(op, s, n);
131*4887Schin 	else if (flags & TOKOP_STRING)
132*4887Schin 	{
133*4887Schin 		PUSH_LINE(s);
134*4887Schin 		for (;;)
135*4887Schin 		{
136*4887Schin 			pp.state &= ~NOSPACE;
137*4887Schin 			c = pplex();
138*4887Schin 			pp.state |= NOSPACE;
139*4887Schin 			if (!c) break;
140*4887Schin 			if (c != ' ')
141*4887Schin 				ppop(op, (flags & TOKOP_DUP) ? strdup(pp.token) : pp.token, n);
142*4887Schin 		}
143*4887Schin 		POP_LINE();
144*4887Schin 	}
145*4887Schin 	else do
146*4887Schin 	{
147*4887Schin 		while (*s == ' ') s++;
148*4887Schin 		for (t = s; *t && *t != ' '; t++);
149*4887Schin 		if (*t) *t++ = 0;
150*4887Schin 		else t = 0;
151*4887Schin 		if (*s) ppop(op, (flags & TOKOP_DUP) ? strdup(s) : s, n);
152*4887Schin 	} while (s = t);
153*4887Schin }
154*4887Schin 
155*4887Schin /*
156*4887Schin  * return symbol pointer for next token macro (re)definition
157*4887Schin  */
158*4887Schin 
159*4887Schin static struct ppsymbol*
160*4887Schin macsym(int tok)
161*4887Schin {
162*4887Schin 	register struct ppsymbol*	sym;
163*4887Schin 
164*4887Schin 	if (tok != T_ID)
165*4887Schin 	{
166*4887Schin 		error(2, "%s: invalid macro name", pptokstr(pp.token, 0));
167*4887Schin 		return 0;
168*4887Schin 	}
169*4887Schin 	sym = pprefmac(pp.token, REF_CREATE);
170*4887Schin 	if ((sym->flags & SYM_FINAL) && (pp.mode & HOSTED)) return 0;
171*4887Schin 	if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
172*4887Schin 	{
173*4887Schin 		if (!(pp.option & ALLPOSSIBLE))
174*4887Schin 			error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
175*4887Schin 		return 0;
176*4887Schin 	}
177*4887Schin 	if (!sym->macro) sym->macro = newof(0, struct ppmacro, 1, 0);
178*4887Schin 	return sym;
179*4887Schin }
180*4887Schin 
181*4887Schin /*
182*4887Schin  * get one space canonical pplex() line, sans '\n', and place in p
183*4887Schin  * x is max+1 pos in p
184*4887Schin  * 0 returned if line too large
185*4887Schin  * otherwise end of p ('\0') returned
186*4887Schin  */
187*4887Schin 
188*4887Schin static char*
189*4887Schin getline(register char* p, char* x, int disable)
190*4887Schin {
191*4887Schin 	register int	c;
192*4887Schin 	register char*	s;
193*4887Schin 	char*		b;
194*4887Schin 	long		restore;
195*4887Schin 
196*4887Schin 	restore = pp.state & (NOSPACE|STRIP);
197*4887Schin 	pp.state &= ~(NEWLINE|NOSPACE|STRIP);
198*4887Schin 	pp.state |= EOF2NL;
199*4887Schin 	b = p;
200*4887Schin 	while ((c = pplex()) != '\n')
201*4887Schin 	{
202*4887Schin 		if (disable)
203*4887Schin 		{
204*4887Schin 			if (c == ' ')
205*4887Schin 				/*ignore*/;
206*4887Schin 			else if (disable == 1)
207*4887Schin 				disable = (c == T_ID && streq(pp.token, pp.pass)) ? 2 : 0;
208*4887Schin 			else
209*4887Schin 			{
210*4887Schin 				disable = 0;
211*4887Schin 				if (c == ':')
212*4887Schin 					pp.state |= DISABLE;
213*4887Schin 			}
214*4887Schin 		}
215*4887Schin 		s = pp.token;
216*4887Schin 		while (*p = *s++)
217*4887Schin 			if (++p >= x)
218*4887Schin 			{
219*4887Schin 				p = 0;
220*4887Schin 				goto done;
221*4887Schin 			}
222*4887Schin 	}
223*4887Schin 	if (p > b && *(p - 1) == ' ')
224*4887Schin 		p--;
225*4887Schin 	if (p >= x)
226*4887Schin 		p = 0;
227*4887Schin 	else
228*4887Schin 		*p = 0;
229*4887Schin  done:
230*4887Schin 	pp.state &= ~(NOSPACE|STRIP);
231*4887Schin 	pp.state |= restore;
232*4887Schin 	return p;
233*4887Schin }
234*4887Schin 
235*4887Schin /*
236*4887Schin  * regex error handler
237*4887Schin  */
238*4887Schin 
239*4887Schin void
240*4887Schin regfatal(regex_t* p, int level, int code)
241*4887Schin {
242*4887Schin 	char	buf[128];
243*4887Schin 
244*4887Schin 	regerror(code, p, buf, sizeof(buf));
245*4887Schin 	regfree(p);
246*4887Schin 	error(level, "regular expression: %s", buf);
247*4887Schin }
248*4887Schin 
249*4887Schin /*
250*4887Schin  * process a single directive line
251*4887Schin  */
252*4887Schin 
253*4887Schin int
254*4887Schin ppcontrol(void)
255*4887Schin {
256*4887Schin 	register char*			p;
257*4887Schin 	register int			c;
258*4887Schin 	register int			n;
259*4887Schin 	register char*			s;
260*4887Schin 	register struct ppmacro*	mac;
261*4887Schin 	register struct ppsymbol*	sym;
262*4887Schin 	struct edit*			edit;
263*4887Schin 	struct map*			map;
264*4887Schin 	struct ppfile*			fp;
265*4887Schin 	int				o;
266*4887Schin 	int				directive;
267*4887Schin 	long				restore;
268*4887Schin 	struct pptuple*			rp;
269*4887Schin 	struct pptuple*			tp;
270*4887Schin 	char*				v;
271*4887Schin 	int				emitted;
272*4887Schin 
273*4887Schin 	union
274*4887Schin 	{
275*4887Schin 		struct map*		best;
276*4887Schin 		struct ppinstk*		inp;
277*4887Schin 		struct pplist*		list;
278*4887Schin 		char*			string;
279*4887Schin 		struct ppsymbol*	symbol;
280*4887Schin 		int			type;
281*4887Schin 		PPLINESYNC		linesync;
282*4887Schin 	}				var;
283*4887Schin 
284*4887Schin 	static char			__va_args__[] = "__VA_ARGS__";
285*4887Schin 	static int			i0;
286*4887Schin 	static int			i1;
287*4887Schin 	static int			i2;
288*4887Schin 	static int			i3;
289*4887Schin 	static int			i4;
290*4887Schin 
291*4887Schin 	static long			n1;
292*4887Schin 	static long			n2;
293*4887Schin 	static long			n3;
294*4887Schin 
295*4887Schin 	static char*			p0;
296*4887Schin 	static char*			p1;
297*4887Schin 	static char*			p2;
298*4887Schin 	static char*			p3;
299*4887Schin 	static char*			p4;
300*4887Schin 	static char*			p5;
301*4887Schin 	static char*			p6;
302*4887Schin 
303*4887Schin 	static struct ppmacro		old;
304*4887Schin 	static char*			formargs[MAXFORMALS];
305*4887Schin #if MACKEYARGS
306*4887Schin 	static char*			formvals[MAXFORMALS];
307*4887Schin #endif
308*4887Schin 
309*4887Schin 	emitted = 0;
310*4887Schin 	if (pp.state & SKIPCONTROL) pp.level--;
311*4887Schin 	restore = (pp.state & RESTORE)|NEWLINE;
312*4887Schin 	if (pp.state & PASSTHROUGH) restore |= DISABLE;
313*4887Schin 	else restore &= ~DISABLE;
314*4887Schin 	pp.state &= ~(NEWLINE|RESTORE|SKIPCONTROL);
315*4887Schin 	pp.state |= DIRECTIVE|DISABLE|EOF2NL|NOSPACE|NOVERTICAL;
316*4887Schin #if COMPATIBLE
317*4887Schin 	if ((pp.state & (COMPATIBILITY|STRICT)) == COMPATIBILITY || (pp.mode & HOSTED)) pp.state &= ~NOVERTICAL;
318*4887Schin #else
319*4887Schin 	if (pp.mode & HOSTED) pp.state &= ~NOVERTICAL;
320*4887Schin #endif
321*4887Schin 	switch (c = pplex())
322*4887Schin 	{
323*4887Schin 	case T_DECIMAL:
324*4887Schin 	case T_OCTAL:
325*4887Schin 		if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
326*4887Schin 			error(1, "# <line> [ \"<file>\" [ <type> ] ]: non-standard directive");
327*4887Schin 		directive = INCLUDE;
328*4887Schin 		goto linesync;
329*4887Schin 	case T_ID:
330*4887Schin 		switch (directive = (int)hashref(pp.dirtab, pp.token))
331*4887Schin 		{
332*4887Schin 		case ELIF:
333*4887Schin 		else_if:
334*4887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
335*4887Schin 				goto eatdirective;
336*4887Schin 			if (pp.control <= pp.in->control)
337*4887Schin 			{
338*4887Schin 				error(2, "no matching #%s for #%s", dirname(IF), dirname(ELIF));
339*4887Schin 				goto eatdirective;
340*4887Schin 			}
341*4887Schin 			if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
342*4887Schin 			if (*pp.control & HADELSE)
343*4887Schin 			{
344*4887Schin 				error(2, "invalid #%s after #%s", dirname(ELIF), dirname(ELSE));
345*4887Schin 				*pp.control |= SKIP;
346*4887Schin 				goto eatdirective;
347*4887Schin 			}
348*4887Schin 			if (*pp.control & KEPT)
349*4887Schin 			{
350*4887Schin 				*pp.control |= SKIP;
351*4887Schin 				goto eatdirective;
352*4887Schin 			}
353*4887Schin 			if (directive == IFDEF || directive == IFNDEF)
354*4887Schin 			{
355*4887Schin 				*pp.control &= ~SKIP;
356*4887Schin 				goto else_ifdef;
357*4887Schin 			}
358*4887Schin 		conditional:
359*4887Schin 			if (ppexpr(&i1))
360*4887Schin 			{
361*4887Schin 				*pp.control &= ~SKIP;
362*4887Schin 				*pp.control |= KEPT;
363*4887Schin 			}
364*4887Schin 			else *pp.control |= SKIP;
365*4887Schin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
366*4887Schin 			goto eatdirective;
367*4887Schin 		case ELSE:
368*4887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
369*4887Schin 				goto eatdirective;
370*4887Schin 			if ((pp.option & ELSEIF) && (c = pplex()) == T_ID && ((n = (int)hashref(pp.dirtab, pp.token)) == IF || n == IFDEF || n == IFNDEF))
371*4887Schin 			{
372*4887Schin 				error(1, "#%s %s is non-standard -- use #%s", dirname(directive), dirname(n), dirname(ELIF));
373*4887Schin 				directive = n;
374*4887Schin 				goto else_if;
375*4887Schin 			}
376*4887Schin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ELSE));
377*4887Schin 			else
378*4887Schin 			{
379*4887Schin 				if (pp.control == (pp.in->control + 1)) pp.in->flags |= IN_noguard;
380*4887Schin 				if (!(*pp.control & KEPT))
381*4887Schin 				{
382*4887Schin 					*pp.control &= ~SKIP;
383*4887Schin 					*pp.control |= HADELSE|KEPT;
384*4887Schin 				}
385*4887Schin 				else
386*4887Schin 				{
387*4887Schin 					if (*pp.control & HADELSE) error(2, "more than one #%s for #%s", dirname(ELSE), dirname(IF));
388*4887Schin 					*pp.control |= HADELSE|SKIP;
389*4887Schin 				}
390*4887Schin 			}
391*4887Schin 			goto enddirective;
392*4887Schin 		case ENDIF:
393*4887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
394*4887Schin 				goto eatdirective;
395*4887Schin 			if (pp.control <= pp.in->control) error(2, "no matching #%s for #%s", dirname(IF), dirname(ENDIF));
396*4887Schin 			else if (--pp.control == pp.in->control && pp.in->symbol)
397*4887Schin 			{
398*4887Schin 				if (pp.in->flags & IN_endguard) pp.in->flags |= IN_noguard;
399*4887Schin 				else
400*4887Schin 				{
401*4887Schin 					pp.in->flags &= ~IN_tokens;
402*4887Schin 					pp.in->flags |= IN_endguard;
403*4887Schin 				}
404*4887Schin 			}
405*4887Schin 			goto enddirective;
406*4887Schin 		case IF:
407*4887Schin 		case IFDEF:
408*4887Schin 		case IFNDEF:
409*4887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev)
410*4887Schin 				goto eatdirective;
411*4887Schin 			pushcontrol();
412*4887Schin 			SETIFBLOCK(pp.control);
413*4887Schin 			if (*pp.control & SKIP)
414*4887Schin 			{
415*4887Schin 				*pp.control |= KEPT;
416*4887Schin 				goto eatdirective;
417*4887Schin 			}
418*4887Schin 			if (directive == IF) goto conditional;
419*4887Schin 		else_ifdef:
420*4887Schin 			if ((c = pplex()) == T_ID)
421*4887Schin 			{
422*4887Schin 				sym = pprefmac(pp.token, REF_IF);
423*4887Schin 				if (directive == IFNDEF && pp.control == pp.in->control + 1)
424*4887Schin 				{
425*4887Schin 					if (pp.in->flags & (IN_defguard|IN_endguard))
426*4887Schin 						pp.in->flags |= IN_noguard;
427*4887Schin 					else
428*4887Schin 					{
429*4887Schin 						pp.in->flags |= IN_defguard;
430*4887Schin 						if (!(pp.in->flags & IN_tokens))
431*4887Schin 							pp.in->symbol = sym ? sym : pprefmac(pp.token, REF_CREATE);
432*4887Schin 					}
433*4887Schin 				}
434*4887Schin 			}
435*4887Schin 			else
436*4887Schin 			{
437*4887Schin 				sym = 0;
438*4887Schin 				if (!(pp.mode & HOSTED))
439*4887Schin 					error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
440*4887Schin 			}
441*4887Schin 			*pp.control |= ((sym != 0) == (directive == IFDEF)) ? KEPT : SKIP;
442*4887Schin 			goto enddirective;
443*4887Schin 		case INCLUDE:
444*4887Schin 			if (*pp.control & SKIP)
445*4887Schin 			{
446*4887Schin 				pp.state |= HEADER;
447*4887Schin 				c = pplex();
448*4887Schin 				pp.state &= ~HEADER;
449*4887Schin 				goto eatdirective;
450*4887Schin 			}
451*4887Schin 			pp.state &= ~DISABLE;
452*4887Schin 			pp.state |= HEADER|STRIP;
453*4887Schin 			switch (c = pplex())
454*4887Schin 			{
455*4887Schin 			case T_STRING:
456*4887Schin 				p = pp.token;
457*4887Schin 				do pp.token = pp.toknxt; while ((c = pplex()) == T_STRING);
458*4887Schin 				*pp.token = 0;
459*4887Schin 				pp.token = p;
460*4887Schin 				/*FALLTHROUGH*/
461*4887Schin 			case T_HEADER:
462*4887Schin 			header:
463*4887Schin 				if (!*pp.token)
464*4887Schin 				{
465*4887Schin 					error(2, "#%s: null file name", dirname(INCLUDE));
466*4887Schin 					break;
467*4887Schin 				}
468*4887Schin 				if (*pp.token == '/' && !(pp.mode & (HOSTED|RELAX)))
469*4887Schin 					error(1, "#%s: reference to %s is not portable", dirname(INCLUDE), pp.token);
470*4887Schin 				n = ppsearch(pp.token, c, SEARCH_INCLUDE);
471*4887Schin 				break;
472*4887Schin 			case '<':
473*4887Schin 				/*
474*4887Schin 				 * HEADEREXPAND|HEADEREXPANDALL gets us here
475*4887Schin 				 */
476*4887Schin 
477*4887Schin 				if (!(p = pp.hdrbuf) && !(p = pp.hdrbuf = newof(0, char, MAXTOKEN, 0)))
478*4887Schin 					error(3, "out of space");
479*4887Schin 				pp.state &= ~NOSPACE;
480*4887Schin 				while ((c = pplex()) && c != '>')
481*4887Schin 				{
482*4887Schin 					v = p + 1;
483*4887Schin 					STRCOPY(p, pp.token, s);
484*4887Schin 					if (p == v && *(p - 1) == ' ' && pp.in->type != IN_MACRO)
485*4887Schin 						p--;
486*4887Schin 				}
487*4887Schin 				pp.state |= NOSPACE;
488*4887Schin 				*p++ = 0;
489*4887Schin 				memcpy(pp.token, pp.hdrbuf, p - pp.hdrbuf);
490*4887Schin 				c = T_HEADER;
491*4887Schin 				goto header;
492*4887Schin 			default:
493*4887Schin 				error(2, "#%s: \"...\" or <...> argument expected", dirname(INCLUDE));
494*4887Schin 				goto eatdirective;
495*4887Schin 			}
496*4887Schin 			goto enddirective;
497*4887Schin 		case 0:
498*4887Schin 			{
499*4887Schin 				regmatch_t	match[10];
500*4887Schin 
501*4887Schin 				/*UNDENT*/
502*4887Schin 	p = pp.valbuf;
503*4887Schin 	*p++ = '#';
504*4887Schin 	STRCOPY(p, pp.token, s);
505*4887Schin 	p0 = p;
506*4887Schin 	pp.mode |= EXPOSE;
507*4887Schin 	pp.state |= HEADER;
508*4887Schin 	p6 = getline(p, &pp.valbuf[MAXTOKEN], 0);
509*4887Schin 	pp.state &= ~HEADER;
510*4887Schin 	pp.mode &= ~EXPOSE;
511*4887Schin 	if (!p6)
512*4887Schin 	{
513*4887Schin 		*p0 = 0;
514*4887Schin 		error(2, "%s: directive too long", pp.valbuf);
515*4887Schin 		c = 0;
516*4887Schin 		goto eatdirective;
517*4887Schin 	}
518*4887Schin 	p1 = p2 = p3 = p4 = 0;
519*4887Schin 	p5 = *p ? p + 1 : 0;
520*4887Schin  checkmap:
521*4887Schin 	i0 = *p0;
522*4887Schin 	p = pp.valbuf;
523*4887Schin 	var.best = 0;
524*4887Schin 	n = 0;
525*4887Schin 	for (map = (struct map*)pp.maps; map; map = map->next)
526*4887Schin 		if (!(i1 = regexec(&map->re, p, elementsof(match), match, 0)))
527*4887Schin 		{
528*4887Schin 			if ((c = match[0].rm_eo - match[0].rm_so) > n)
529*4887Schin 			{
530*4887Schin 				n = c;
531*4887Schin 				var.best = map;
532*4887Schin 			}
533*4887Schin 		}
534*4887Schin 		else if (i1 != REG_NOMATCH)
535*4887Schin 			regfatal(&map->re, 3, i1);
536*4887Schin 	c = '\n';
537*4887Schin 	if (map = var.best)
538*4887Schin 	{
539*4887Schin 		if ((pp.state & (STRICT|WARN)) && !(pp.mode & (HOSTED|RELAX)))
540*4887Schin 		{
541*4887Schin 			*p0 = 0;
542*4887Schin 			if (!(pp.state & WARN) || strcmp(p + 1, dirname(PRAGMA)))
543*4887Schin 				error(1, "%s: non-standard directive", p);
544*4887Schin 			*p0 = i0;
545*4887Schin 		}
546*4887Schin 		if (!(*pp.control & SKIP))
547*4887Schin 		{
548*4887Schin 			n = 0;
549*4887Schin 			for (edit = map->edit; edit; edit = edit->next)
550*4887Schin 				if (!(i0 = regexec(&edit->re, p, elementsof(match), match, 0)))
551*4887Schin 				{
552*4887Schin 					n++;
553*4887Schin 					if (i0 = regsubexec(&edit->re, p, elementsof(match), match))
554*4887Schin 						regfatal(&edit->re, 3, i0);
555*4887Schin 					p = edit->re.re_sub->re_buf;
556*4887Schin 					if (edit->re.re_sub->re_flags & REG_SUB_STOP)
557*4887Schin 						break;
558*4887Schin 				}
559*4887Schin 				else if (i0 != REG_NOMATCH)
560*4887Schin 					regfatal(&edit->re, 3, i0);
561*4887Schin 			if (n && *p)
562*4887Schin 			{
563*4887Schin 				p1 = s = oldof(0, char, 0, strlen(p) + 32);
564*4887Schin 				while (*s = *p++) s++;
565*4887Schin 				debug((-4, "map: %s", p1));
566*4887Schin 				*s++ = '\n';
567*4887Schin 				*s = 0;
568*4887Schin 				error_info.line++;
569*4887Schin 				PUSH_RESCAN(p1);
570*4887Schin 				error_info.line--;
571*4887Schin 				directive = LINE;
572*4887Schin 			}
573*4887Schin 		}
574*4887Schin 		goto donedirective;
575*4887Schin 	}
576*4887Schin 	if (directive != PRAGMA && (!(*pp.control & SKIP) || !(pp.mode & (HOSTED|RELAX))))
577*4887Schin 	{
578*4887Schin 		*p0 = 0;
579*4887Schin 		error(1, "%s: unknown directive", pptokstr(pp.valbuf, 0));
580*4887Schin 		*p0 = i0;
581*4887Schin 	}
582*4887Schin  pass:
583*4887Schin 	if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT) && (directive == PRAGMA || !(pp.mode & INIT)))
584*4887Schin 	{
585*4887Schin 		*p0 = 0;
586*4887Schin 		if (p2) *p2 = 0;
587*4887Schin 		if (p4)
588*4887Schin 		{
589*4887Schin 			if (p4 == p5)
590*4887Schin 			{
591*4887Schin 				p5 = strcpy(pp.tmpbuf, p5);
592*4887Schin 				if (p = strchr(p5, MARK))
593*4887Schin 				{
594*4887Schin 					s = p;
595*4887Schin 					while (*p)
596*4887Schin 						if ((*s++ = *p++) == MARK && *p == MARK) p++;
597*4887Schin 					*s = 0;
598*4887Schin 				}
599*4887Schin 			}
600*4887Schin 			*p4 = 0;
601*4887Schin 		}
602*4887Schin 		if (p = (char*)memchr(pp.valbuf + 1, MARK, p6 - pp.valbuf - 1))
603*4887Schin 		{
604*4887Schin 			s = p;
605*4887Schin 			while (p < p6) switch (*s++ = *p++)
606*4887Schin 			{
607*4887Schin 			case 0:
608*4887Schin 				s = p;
609*4887Schin 				break;
610*4887Schin 			case MARK:
611*4887Schin 				p++;
612*4887Schin 				break;
613*4887Schin 			}
614*4887Schin 			*s = 0;
615*4887Schin 		}
616*4887Schin 		(*pp.pragma)(pp.valbuf + 1, p1, p3, p5, (pp.state & COMPILE) || (pp.mode & INIT) != 0);
617*4887Schin 		emitted = 1;
618*4887Schin 	}
619*4887Schin 	goto donedirective;
620*4887Schin 
621*4887Schin 				/*INDENT*/
622*4887Schin 			}
623*4887Schin 		}
624*4887Schin 		if (*pp.control & SKIP) goto eatdirective;
625*4887Schin 		switch (directive)
626*4887Schin 		{
627*4887Schin #if MACDEF
628*4887Schin 		case ENDMAC:
629*4887Schin 			c = pplex();
630*4887Schin 			error(2, "no matching #%s for #%s", dirname(MACDEF), dirname(ENDMAC));
631*4887Schin 			goto enddirective;
632*4887Schin #endif
633*4887Schin #if MACDEF
634*4887Schin 		case MACDEF:
635*4887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
636*4887Schin 				error(1, "#%s: non-standard directive", pp.token);
637*4887Schin 			/*FALLTHROUGH*/
638*4887Schin #endif
639*4887Schin 		case DEFINE:
640*4887Schin 			n2 = error_info.line;
641*4887Schin 			if ((c = pplex()) == '#' && directive == DEFINE)
642*4887Schin 				goto assertion;
643*4887Schin 			if (c == '<')
644*4887Schin 			{
645*4887Schin 				n = 1;
646*4887Schin 				c = pplex();
647*4887Schin 			}
648*4887Schin 			else
649*4887Schin 				n = 0;
650*4887Schin 			if (!(sym = macsym(c)))
651*4887Schin 				goto eatdirective;
652*4887Schin 			if (pp.truncate)
653*4887Schin 				ppfsm(FSM_MACRO, pp.token);
654*4887Schin 			mac = sym->macro;
655*4887Schin 			if ((pp.option & ALLPOSSIBLE) && !pp.in->prev->prev && mac->value)
656*4887Schin 				goto eatdirective;
657*4887Schin 			if (n)
658*4887Schin 				goto tuple;
659*4887Schin 			old = *mac;
660*4887Schin 			i0 = sym->flags;
661*4887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_EMPTY|SYM_FINAL|SYM_FUNCTION|SYM_INIT|SYM_INITIAL|SYM_MULTILINE|SYM_NOEXPAND|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
662*4887Schin #if MACDEF
663*4887Schin 			if (directive == MACDEF)
664*4887Schin 				sym->flags |= SYM_MULTILINE;
665*4887Schin #endif
666*4887Schin 			mac->arity = 0;
667*4887Schin 			mac->formals = 0;
668*4887Schin 			mac->value = 0;
669*4887Schin 			pp.state &= ~NOSPACE;
670*4887Schin 			pp.state |= DEFINITION|NOEXPAND;
671*4887Schin 			switch (c = pplex())
672*4887Schin 			{
673*4887Schin 			case '(':
674*4887Schin 				sym->flags |= SYM_FUNCTION;
675*4887Schin 				pp.state |= NOSPACE;
676*4887Schin #if MACKEYARGS
677*4887Schin 				if (pp.option & KEYARGS)
678*4887Schin 				{
679*4887Schin 					n = 2 * MAXTOKEN;
680*4887Schin 					p = mac->formals = oldof(0, char, 0, n);
681*4887Schin 					if ((c = pplex()) == T_ID) for (;;)
682*4887Schin 					{
683*4887Schin 						if (mac->arity < MAXFORMALS)
684*4887Schin 						{
685*4887Schin 							if (mac->arity) p++;
686*4887Schin 							formargs[mac->arity] = p;
687*4887Schin 							STRAPP(p, pp.token, s);
688*4887Schin 							formvals[mac->arity++] = p1 = p;
689*4887Schin 							if (mac->arity == 1) *p++ = ' ';
690*4887Schin 							*p++ = ' ';
691*4887Schin 							*p = 0;
692*4887Schin 						}
693*4887Schin 						else error(2, "%s: formal argument %s ignored", sym->name, pp.token);
694*4887Schin 						switch (c = pplex())
695*4887Schin 						{
696*4887Schin 						case '=':
697*4887Schin 							c = pplex();
698*4887Schin 							break;
699*4887Schin 						case ',':
700*4887Schin 							break;
701*4887Schin 						default:
702*4887Schin 							goto endformals;
703*4887Schin 						}
704*4887Schin 						pp.state &= ~NOSPACE;
705*4887Schin 						p0 = 0;
706*4887Schin 						for (;;)
707*4887Schin 						{
708*4887Schin 							switch (c)
709*4887Schin 							{
710*4887Schin 							case '\n':
711*4887Schin 								goto endformals;
712*4887Schin 							case '(':
713*4887Schin 								p0++;
714*4887Schin 								break;
715*4887Schin 							case ')':
716*4887Schin 								if (!p0--)
717*4887Schin 								{
718*4887Schin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
719*4887Schin 									goto endformals;
720*4887Schin 								}
721*4887Schin 								break;
722*4887Schin 							case ',':
723*4887Schin 								if (!p0)
724*4887Schin 								{
725*4887Schin 									if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') *--p = 0;
726*4887Schin 									goto nextformal;
727*4887Schin 								}
728*4887Schin 								break;
729*4887Schin 							case ' ':
730*4887Schin 								if (p > formvals[mac->arity - 1] && *(p - 1) == ' ') continue;
731*4887Schin 								break;
732*4887Schin 							}
733*4887Schin 							STRCOPY(p, pp.token, s);
734*4887Schin 							if (p > &mac->formals[n - MAXTOKEN] && (s = newof(mac->formals, char, n += MAXTOKEN, 0)) != mac->formals)
735*4887Schin 							{
736*4887Schin 								n1 = s - mac->formals;
737*4887Schin 								for (n = 0; n < mac->arity; n++)
738*4887Schin 								{
739*4887Schin 									formargs[n] += n1;
740*4887Schin 									formvals[n] += n1;
741*4887Schin 								}
742*4887Schin 								c = p - mac->formals;
743*4887Schin 								mac->formals = s;
744*4887Schin 								p = mac->formals + c;
745*4887Schin 							}
746*4887Schin 							c = pplex();
747*4887Schin 						}
748*4887Schin 					nextformal:
749*4887Schin 						pp.state |= NOSPACE;
750*4887Schin 						if ((c = pplex()) != T_ID)
751*4887Schin 						{
752*4887Schin 							c = ',';
753*4887Schin 							break;
754*4887Schin 						}
755*4887Schin 					}
756*4887Schin 				endformals: /*NOP*/;
757*4887Schin 				}
758*4887Schin 				else
759*4887Schin #endif
760*4887Schin 				{
761*4887Schin 					p = mac->formals = oldof(0, char, 0, MAXFORMALS * (MAXID + 1));
762*4887Schin 					c = pplex();
763*4887Schin #if COMPATIBLE
764*4887Schin 					if ((pp.state & COMPATIBILITY) && c == ',')
765*4887Schin 					{
766*4887Schin 						if ((pp.state & WARN) && !(pp.mode & HOSTED))
767*4887Schin 							error(1, "%s: macro formal argument expected", sym->name);
768*4887Schin 						while ((c = pplex()) == ',');
769*4887Schin 					}
770*4887Schin #endif
771*4887Schin 					for (;;)
772*4887Schin 					{
773*4887Schin 						if (c == T_VARIADIC)
774*4887Schin 						{
775*4887Schin 							if (sym->flags & SYM_VARIADIC)
776*4887Schin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
777*4887Schin 							sym->flags |= SYM_VARIADIC;
778*4887Schin 							v = __va_args__;
779*4887Schin 						}
780*4887Schin 						else if (c == T_ID)
781*4887Schin 						{
782*4887Schin 							v = pp.token;
783*4887Schin 							if (sym->flags & SYM_VARIADIC)
784*4887Schin 								error(2, "%s: %s: macro formal argument cannot follow ...", sym->name, v);
785*4887Schin 							else if (streq(v, __va_args__))
786*4887Schin 								error(2, "%s: %s: invalid macro formal argument", sym->name, v);
787*4887Schin 						}
788*4887Schin 						else
789*4887Schin 							break;
790*4887Schin 						if (mac->arity < MAXFORMALS)
791*4887Schin 						{
792*4887Schin 							for (n = 0; n < mac->arity; n++)
793*4887Schin 								if (streq(formargs[n], v))
794*4887Schin 									error(2, "%s: %s: duplicate macro formal argument", sym->name, v);
795*4887Schin 							formargs[mac->arity++] = p;
796*4887Schin 							STRAPP(p, v, s);
797*4887Schin 						}
798*4887Schin 						else
799*4887Schin 							error(2, "%s: %s: macro formal argument ignored", sym->name, v);
800*4887Schin 						if ((c = pplex()) == ',')
801*4887Schin 						{
802*4887Schin 							c = pplex();
803*4887Schin #if COMPATIBLE
804*4887Schin 							if ((pp.state & COMPATIBILITY) && c == ',')
805*4887Schin 							{
806*4887Schin 								if ((pp.state & WARN) && !(pp.mode & HOSTED))
807*4887Schin 									error(1, "%s: macro formal argument expected", sym->name);
808*4887Schin 								while ((c = pplex()) == ',');
809*4887Schin 							}
810*4887Schin #endif
811*4887Schin 						}
812*4887Schin 						else if (c != T_VARIADIC)
813*4887Schin 							break;
814*4887Schin 						else
815*4887Schin 						{
816*4887Schin 							if (sym->flags & SYM_VARIADIC)
817*4887Schin 								error(2, "%s: %s: duplicate macro formal argument", sym->name, pp.token);
818*4887Schin 							sym->flags |= SYM_VARIADIC;
819*4887Schin 							c = pplex();
820*4887Schin 							break;
821*4887Schin 						}
822*4887Schin 					}
823*4887Schin 					if (mac->arity && (s = newof(mac->formals, char, p - mac->formals, 0)) != mac->formals)
824*4887Schin 					{
825*4887Schin 						n1 = s - mac->formals;
826*4887Schin 						for (n = 0; n < mac->arity; n++)
827*4887Schin 							formargs[n] += n1;
828*4887Schin 						mac->formals = s;
829*4887Schin 					}
830*4887Schin 				}
831*4887Schin 				if (!mac->arity)
832*4887Schin 				{
833*4887Schin 					free(mac->formals);
834*4887Schin 					mac->formals = 0;
835*4887Schin 				}
836*4887Schin 				switch (c)
837*4887Schin 				{
838*4887Schin 				case ')':
839*4887Schin #if MACKEYARGS
840*4887Schin 					pp.state |= NOEXPAND|NOSPACE;
841*4887Schin #else
842*4887Schin 					pp.state |= NOEXPAND;
843*4887Schin #endif
844*4887Schin 					c = pplex();
845*4887Schin 					break;
846*4887Schin 				default:
847*4887Schin 					error(2, "%s: invalid macro formal argument list", sym->name);
848*4887Schin 					if (mac->formals)
849*4887Schin 					{
850*4887Schin 						free(mac->formals);
851*4887Schin 						mac->formals = 0;
852*4887Schin 						mac->arity = 0;
853*4887Schin 					}
854*4887Schin 					free(mac);
855*4887Schin 					sym->macro = 0;
856*4887Schin 					goto eatdirective;
857*4887Schin 				}
858*4887Schin 				pp.state &= ~NOSPACE;
859*4887Schin 				break;
860*4887Schin 			case ' ':
861*4887Schin 			case '\t':
862*4887Schin 				c = pplex();
863*4887Schin 				break;
864*4887Schin 			}
865*4887Schin 			n = 2 * MAXTOKEN;
866*4887Schin #if MACKEYARGS
867*4887Schin 			p1 = p;
868*4887Schin #endif
869*4887Schin 			p = mac->value = oldof(0, char, 0, n);
870*4887Schin 			var.type = 0;
871*4887Schin 			n1 = 0;
872*4887Schin #if MACDEF
873*4887Schin 			i2 = i3 = 0;
874*4887Schin 			n3 = pp.state;
875*4887Schin #endif
876*4887Schin 			if ((pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
877*4887Schin 				switch (c)
878*4887Schin 				{
879*4887Schin 				case '+':
880*4887Schin 				case '-':
881*4887Schin 				case '&':
882*4887Schin 				case '|':
883*4887Schin 				case '<':
884*4887Schin 				case '>':
885*4887Schin 				case ':':
886*4887Schin 				case '=':
887*4887Schin 					*p++ = ' ';
888*4887Schin 					break;
889*4887Schin 				}
890*4887Schin 			o = 0;
891*4887Schin 			for (;;)
892*4887Schin 			{
893*4887Schin 				switch (c)
894*4887Schin 				{
895*4887Schin 				case T_ID:
896*4887Schin 					for (c = 0; c < mac->arity; c++)
897*4887Schin 						if (streq(formargs[c], pp.token))
898*4887Schin 						{
899*4887Schin #if COMPATIBLE
900*4887Schin 							if (!(pp.state & COMPATIBILITY))
901*4887Schin #endif
902*4887Schin 							if (var.type != TOK_TOKCAT && p > mac->value && *(p - 1) != ' ' && !(pp.option & PRESERVE)) *p++ = ' ';
903*4887Schin 							*p++ = MARK;
904*4887Schin #if COMPATIBLE
905*4887Schin 							if ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) *p++ = 'C';
906*4887Schin 							else
907*4887Schin #endif
908*4887Schin 							*p++ = (n1 || var.type == TOK_TOKCAT) ? 'C' : 'A';
909*4887Schin 							*p++ = c + ARGOFFSET;
910*4887Schin 							var.type = TOK_FORMAL|TOK_ID;
911*4887Schin 							c = '>';
912*4887Schin 							goto checkvalue;
913*4887Schin 						}
914*4887Schin 					if (var.type == TOK_BUILTIN) switch ((int)hashget(pp.strtab, pp.token))
915*4887Schin 					{
916*4887Schin 					case V_DEFAULT:
917*4887Schin 					case V_EMPTY:
918*4887Schin 						sym->flags |= SYM_EMPTY;
919*4887Schin 						break;
920*4887Schin 					}
921*4887Schin 					else if (pp.hiding && (var.symbol = ppsymref(pp.symtab, pp.token)) && var.symbol->hidden)
922*4887Schin 					{
923*4887Schin 						for (var.inp = pp.in; var.inp->type != IN_FILE && var.inp->prev; var.inp = var.inp->prev);
924*4887Schin 						p += sfsprintf(p, MAXTOKEN, "_%d_%s_hIDe", var.inp->hide, pp.token);
925*4887Schin 						var.type = TOK_ID;
926*4887Schin 						goto checkvalue;
927*4887Schin 					}
928*4887Schin 					var.type = TOK_ID;
929*4887Schin 					break;
930*4887Schin 				case '#':
931*4887Schin 					var.type = 0;
932*4887Schin #if MACDEF
933*4887Schin 					if (!(sym->flags & (SYM_FUNCTION|SYM_MULTILINE))) break;
934*4887Schin #else
935*4887Schin 					if (!(sym->flags & SYM_FUNCTION)) break;
936*4887Schin #endif
937*4887Schin 					pp.state |= NOSPACE;
938*4887Schin 					c = pplex();
939*4887Schin 					if (c == '@')
940*4887Schin 					{
941*4887Schin 						c = pplex();
942*4887Schin 						i4 = 'S';
943*4887Schin 					}
944*4887Schin 					else i4 = 'Q';
945*4887Schin 					pp.state &= ~NOSPACE;
946*4887Schin 					if (c != T_ID) c = mac->arity;
947*4887Schin 					else for (c = 0; c < mac->arity; c++)
948*4887Schin 						if (streq(formargs[c], pp.token))
949*4887Schin 							break;
950*4887Schin 					if (c >= mac->arity)
951*4887Schin 					{
952*4887Schin #if MACDEF
953*4887Schin 						if (sym->flags & SYM_MULTILINE)
954*4887Schin 						{
955*4887Schin 							if (n3 & NEWLINE)
956*4887Schin 							{
957*4887Schin 								pp.state &= ~NOEXPAND;
958*4887Schin 								switch ((int)hashref(pp.dirtab, pp.token))
959*4887Schin 								{
960*4887Schin 								case ENDMAC:
961*4887Schin 									if (!i2--) goto gotdefinition;
962*4887Schin 									break;
963*4887Schin 								case INCLUDE:
964*4887Schin 									/* PARSE HEADER constant */
965*4887Schin 									break;
966*4887Schin 								case MACDEF:
967*4887Schin 									i2++;
968*4887Schin 									break;
969*4887Schin 								}
970*4887Schin 								*p++ = '#';
971*4887Schin 							}
972*4887Schin 						}
973*4887Schin 						else
974*4887Schin #endif
975*4887Schin #if COMPATIBLE
976*4887Schin 						if (pp.state & COMPATIBILITY) *p++ = '#';
977*4887Schin 						else
978*4887Schin #endif
979*4887Schin 						error(2, "# must precede a formal parameter");
980*4887Schin 					}
981*4887Schin 					else
982*4887Schin 					{
983*4887Schin 						if (p > mac->value && ppisidig(*(p - 1)) && !(pp.option & PRESERVE)) *p++ = ' ';
984*4887Schin 						*p++ = MARK;
985*4887Schin 						*p++ = i4;
986*4887Schin 						*p++ = c + ARGOFFSET;
987*4887Schin 						goto checkvalue;
988*4887Schin 					}
989*4887Schin 					break;
990*4887Schin 				case T_TOKCAT:
991*4887Schin 					if (p <= mac->value) error(2, "%s lhs operand omitted", pp.token);
992*4887Schin 					else
993*4887Schin 					{
994*4887Schin 						if (*(p - 1) == ' ') p--;
995*4887Schin 						if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
996*4887Schin 					}
997*4887Schin 					pp.state |= NOSPACE;
998*4887Schin 					c = pplex();
999*4887Schin 					pp.state &= ~NOSPACE;
1000*4887Schin 					if (c == '\n') error(2, "%s rhs operand omitted", pptokchr(T_TOKCAT));
1001*4887Schin 					var.type = TOK_TOKCAT;
1002*4887Schin 					continue;
1003*4887Schin 				case '(':
1004*4887Schin 					if (*pp.token == '#')
1005*4887Schin 					{
1006*4887Schin 						var.type = TOK_BUILTIN;
1007*4887Schin 						n1++;
1008*4887Schin 					}
1009*4887Schin 					else
1010*4887Schin 					{
1011*4887Schin 						var.type = 0;
1012*4887Schin 						if (n1) n1++;
1013*4887Schin 					}
1014*4887Schin 					break;
1015*4887Schin 				case ')':
1016*4887Schin 					var.type = 0;
1017*4887Schin 					if (n1) n1--;
1018*4887Schin 					break;
1019*4887Schin 				case T_STRING:
1020*4887Schin 				case T_CHARCONST:
1021*4887Schin 					pp.state &= ~NOEXPAND;
1022*4887Schin 					var.type = 0;
1023*4887Schin 					if (strchr(pp.token, MARK)) pp.state &= ~NOEXPAND;
1024*4887Schin #if COMPATIBLE
1025*4887Schin 					/*UNDENT*/
1026*4887Schin 
1027*4887Schin 	if ((sym->flags & SYM_FUNCTION) && (pp.state & (COMPATIBILITY|TRANSITION)))
1028*4887Schin 	{
1029*4887Schin 		char*	v;
1030*4887Schin 
1031*4887Schin 		s = pp.token;
1032*4887Schin 		for (;;)
1033*4887Schin 		{
1034*4887Schin 			if (!*s) goto checkvalue;
1035*4887Schin 			if (ppisid(*s))
1036*4887Schin 			{
1037*4887Schin 				v = s;
1038*4887Schin 				while (ppisid(*++s));
1039*4887Schin 				i1 = *s;
1040*4887Schin 				*s = 0;
1041*4887Schin 				for (c = 0; c < mac->arity; c++)
1042*4887Schin 					if (streq(formargs[c], v))
1043*4887Schin 					{
1044*4887Schin 						*p++ = MARK;
1045*4887Schin 						*p++ = 'C';
1046*4887Schin 						*p++ = c + ARGOFFSET;
1047*4887Schin 						if (!(pp.mode & HOSTED) && (!(pp.state & COMPATIBILITY) || (pp.state & WARN))) switch (*pp.token)
1048*4887Schin 						{
1049*4887Schin 						case '"':
1050*4887Schin 							error(1, "use the # operator to \"...\" quote macro arguments");
1051*4887Schin 							break;
1052*4887Schin 						case '\'':
1053*4887Schin 							error(1, "macro arguments should be '...' quoted before substitution");
1054*4887Schin 							break;
1055*4887Schin 						}
1056*4887Schin 						goto quotearg;
1057*4887Schin 					}
1058*4887Schin 				STRCOPY2(p, v);
1059*4887Schin 			quotearg:
1060*4887Schin 				*s = i1;
1061*4887Schin 			}
1062*4887Schin 			else *p++ = *s++;
1063*4887Schin 		}
1064*4887Schin 	}
1065*4887Schin 					/*INDENT*/
1066*4887Schin #endif
1067*4887Schin 					break;
1068*4887Schin 				case '\n':
1069*4887Schin #if MACDEF
1070*4887Schin 					if (sym->flags & SYM_MULTILINE)
1071*4887Schin 					{
1072*4887Schin 						if (pp.state & EOF2NL)
1073*4887Schin 						{
1074*4887Schin 							error_info.line++;
1075*4887Schin 							pp.state |= HIDDEN;
1076*4887Schin 							pp.hidden++;
1077*4887Schin 							var.type = 0;
1078*4887Schin 							if (!i3++)
1079*4887Schin 								goto checkvalue;
1080*4887Schin 							break;
1081*4887Schin 						}
1082*4887Schin 						pp.state |= EOF2NL;
1083*4887Schin 						error(2, "%s: missing #%s", sym->name, dirname(ENDMAC));
1084*4887Schin 					}
1085*4887Schin #endif
1086*4887Schin 					goto gotdefinition;
1087*4887Schin 				case 0:
1088*4887Schin 					c = '\n';
1089*4887Schin 					goto gotdefinition;
1090*4887Schin #if COMPATIBLE
1091*4887Schin 				case ' ':
1092*4887Schin 					if (pp.state & COMPATIBILITY) var.type = 0;
1093*4887Schin 					if (pp.option & PRESERVE) break;
1094*4887Schin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1095*4887Schin 					goto checkvalue;
1096*4887Schin 				case '\t':
1097*4887Schin 					if (var.type & TOK_ID)
1098*4887Schin 					{
1099*4887Schin 						while ((c = pplex()) == '\t');
1100*4887Schin 						if (c == T_ID)
1101*4887Schin 						{
1102*4887Schin 							if (var.type == (TOK_FORMAL|TOK_ID)) *(p - 2) = 'C';
1103*4887Schin 							var.type = TOK_TOKCAT;
1104*4887Schin 							if (pp.state & WARN) error(1, "use the ## operator to concatenate macro arguments");
1105*4887Schin 						}
1106*4887Schin 						else var.type = 0;
1107*4887Schin 						continue;
1108*4887Schin 					}
1109*4887Schin 					var.type = 0;
1110*4887Schin 					if (pp.option & PRESERVE) break;
1111*4887Schin 					if (p > mac->value && *(p - 1) != ' ') *p++ = ' ';
1112*4887Schin 					goto checkvalue;
1113*4887Schin #endif
1114*4887Schin 				case MARK:
1115*4887Schin 					pp.state &= ~NOEXPAND;
1116*4887Schin 					/*FALLTHROUGH*/
1117*4887Schin 
1118*4887Schin 				default:
1119*4887Schin 					var.type = 0;
1120*4887Schin 					break;
1121*4887Schin 				}
1122*4887Schin 				STRCOPY(p, pp.token, s);
1123*4887Schin 			checkvalue:
1124*4887Schin 				o = c;
1125*4887Schin 				if (p > &mac->value[n - MAXTOKEN] && (s = newof(mac->value, char, n += MAXTOKEN, 0)) != mac->value)
1126*4887Schin 				{
1127*4887Schin 					c = p - mac->value;
1128*4887Schin 					mac->value = s;
1129*4887Schin 					p = mac->value + c;
1130*4887Schin 				}
1131*4887Schin #if MACDEF
1132*4887Schin 				n3 = pp.state;
1133*4887Schin #endif
1134*4887Schin 				c = pplex();
1135*4887Schin 			}
1136*4887Schin 		gotdefinition:
1137*4887Schin 			while (p > mac->value && *(p - 1) == ' ') p--;
1138*4887Schin 			if (p > mac->value && (pp.option & PLUSPLUS) && (pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
1139*4887Schin 				switch (o)
1140*4887Schin 				{
1141*4887Schin 				case '+':
1142*4887Schin 				case '-':
1143*4887Schin 				case '&':
1144*4887Schin 				case '|':
1145*4887Schin 				case '<':
1146*4887Schin 				case '>':
1147*4887Schin 				case ':':
1148*4887Schin 				case '=':
1149*4887Schin 					*p++ = ' ';
1150*4887Schin 					break;
1151*4887Schin 				}
1152*4887Schin 			*p = 0;
1153*4887Schin #if MACKEYARGS
1154*4887Schin 			if (!mac->arity) /* ok */;
1155*4887Schin 			else if (pp.option & KEYARGS)
1156*4887Schin 			{
1157*4887Schin 				p0 = mac->formals;
1158*4887Schin 				mac->formkeys = newof(0, struct ppkeyarg, n, p1 - p0 + 1);
1159*4887Schin 				s = (char*)&mac->formkeys[mac->arity];
1160*4887Schin 				(void)memcpy(s, p0, p1 - p0 + 1);
1161*4887Schin 				free(p0);
1162*4887Schin 				for (n = 0; n < mac->arity; n++)
1163*4887Schin 				{
1164*4887Schin 					mac->formkeys[n].name = s + (formargs[n] - p0);
1165*4887Schin 					mac->formkeys[n].value = s + (formvals[n] - p0);
1166*4887Schin 				}
1167*4887Schin 			}
1168*4887Schin 			else
1169*4887Schin #endif
1170*4887Schin 			for (n = 1; n < mac->arity; n++)
1171*4887Schin 				*(formargs[n] - 1) = ',';
1172*4887Schin 			if (old.value)
1173*4887Schin 			{
1174*4887Schin 				if ((i0 & SYM_FUNCTION) != (sym->flags & SYM_FUNCTION) || old.arity != mac->arity || !streq(old.value, mac->value)) goto redefined;
1175*4887Schin 				if (!old.formals)
1176*4887Schin 				{
1177*4887Schin 					if (mac->formals) goto redefined;
1178*4887Schin 				}
1179*4887Schin 				else if (mac->formals)
1180*4887Schin 				{
1181*4887Schin #if MACKEYARGS
1182*4887Schin 					if (pp.option & KEYARGS)
1183*4887Schin 					{
1184*4887Schin 						for (n = 0; n < mac->arity; n++)
1185*4887Schin 							if (!streq(mac->formkeys[n].name, old.formkeys[n].name) || !streq(mac->formkeys[n].value, old.formkeys[n].value))
1186*4887Schin 								goto redefined;
1187*4887Schin 					}
1188*4887Schin 					else
1189*4887Schin #endif
1190*4887Schin 					if (!streq(mac->formals, old.formals)) goto redefined;
1191*4887Schin 				}
1192*4887Schin #if MACKEYARGS
1193*4887Schin 				if (pp.option & KEYARGS)
1194*4887Schin 				{
1195*4887Schin 					if (mac->formkeys) free(mac->formkeys);
1196*4887Schin 					mac->formkeys = old.formkeys;
1197*4887Schin 				}
1198*4887Schin 				else
1199*4887Schin #endif
1200*4887Schin 				{
1201*4887Schin 					if (mac->formals) free(mac->formals);
1202*4887Schin 					mac->formals = old.formals;
1203*4887Schin 				}
1204*4887Schin 				free(mac->value);
1205*4887Schin 				mac->value = old.value;
1206*4887Schin 				goto benign;
1207*4887Schin 			redefined:
1208*4887Schin 				if (!(pp.mode & HOSTED) || !(i0 & SYM_INITIAL))
1209*4887Schin 					error(1, "%s redefined", sym->name);
1210*4887Schin #if MACKEYARGS
1211*4887Schin 				if ((pp.option & KEYARGS) && mac->formkeys)
1212*4887Schin 					free(mac->formkeys);
1213*4887Schin #endif
1214*4887Schin #if MACKEYARGS
1215*4887Schin 				if (!(pp.option & KEYARGS))
1216*4887Schin #endif
1217*4887Schin 				if (old.formals) free(old.formals);
1218*4887Schin 				free(old.value);
1219*4887Schin 			}
1220*4887Schin 			else if (!pp.truncate) ppfsm(FSM_MACRO, sym->name);
1221*4887Schin 			mac->value = newof(mac->value, char, (mac->size = p - mac->value) + 1, 0);
1222*4887Schin 			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)))
1223*4887Schin 			{
1224*4887Schin 				ppsync();
1225*4887Schin 				ppprintf("#%s %s", dirname(DEFINE), sym->name);
1226*4887Schin 				if (sym->flags & SYM_FUNCTION)
1227*4887Schin 				{
1228*4887Schin 					ppputchar('(');
1229*4887Schin 					if (mac->formals)
1230*4887Schin 						ppprintf("%s", mac->formals);
1231*4887Schin 					ppputchar(')');
1232*4887Schin 				}
1233*4887Schin 				if ((p = mac->value) && *p)
1234*4887Schin 				{
1235*4887Schin 					ppputchar(' ');
1236*4887Schin 					i0 = 0;
1237*4887Schin 					while (n = *p++)
1238*4887Schin 					{
1239*4887Schin 						if (n != MARK || (n = *p++) == MARK)
1240*4887Schin 						{
1241*4887Schin 							ppputchar(n);
1242*4887Schin 							i0 = ppisid(n);
1243*4887Schin 						}
1244*4887Schin 						else
1245*4887Schin 						{
1246*4887Schin 							if (n == 'Q')
1247*4887Schin 								ppputchar('#');
1248*4887Schin 							else if (i0)
1249*4887Schin 							{
1250*4887Schin 								ppputchar('#');
1251*4887Schin 								ppputchar('#');
1252*4887Schin 							}
1253*4887Schin 							s = formargs[*p++ - ARGOFFSET];
1254*4887Schin 							while ((n = *s++) && n != ',')
1255*4887Schin 								ppputchar(n);
1256*4887Schin 							if (ppisid(*p) || *p == MARK)
1257*4887Schin 							{
1258*4887Schin 								ppputchar('#');
1259*4887Schin 								ppputchar('#');
1260*4887Schin 							}
1261*4887Schin 							i0 = 0;
1262*4887Schin 						}
1263*4887Schin 						ppcheckout();
1264*4887Schin 					}
1265*4887Schin 				}
1266*4887Schin 				emitted = 1;
1267*4887Schin 			}
1268*4887Schin 		benign:
1269*4887Schin 			if (pp.mode & BUILTIN) sym->flags |= SYM_BUILTIN;
1270*4887Schin 			if (pp.option & FINAL) sym->flags |= SYM_FINAL;
1271*4887Schin 			if (pp.mode & INIT) sym->flags |= SYM_INIT;
1272*4887Schin 			if (pp.option & INITIAL) sym->flags |= SYM_INITIAL;
1273*4887Schin 			if (pp.state & NOEXPAND)  sym->flags |= SYM_NOEXPAND;
1274*4887Schin 			if (pp.option & PREDEFINED) sym->flags |= SYM_PREDEFINED;
1275*4887Schin 			if (pp.mode & READONLY) sym->flags |= SYM_READONLY;
1276*4887Schin 			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);
1277*4887Schin 			break;
1278*4887Schin 		assertion:
1279*4887Schin 			c = pplex();
1280*4887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1281*4887Schin 				error(1, "#%s #%s: assertions are non-standard", dirname(directive), pptokstr(pp.token, 0));
1282*4887Schin 			if (c != T_ID)
1283*4887Schin 			{
1284*4887Schin 				error(2, "%s: invalid predicate name", pptokstr(pp.token, 0));
1285*4887Schin 				goto eatdirective;
1286*4887Schin 			}
1287*4887Schin 			switch ((int)hashref(pp.strtab, pp.token))
1288*4887Schin 			{
1289*4887Schin 			case X_DEFINED:
1290*4887Schin 			case X_EXISTS:
1291*4887Schin 			case X_STRCMP:
1292*4887Schin 				error(2, "%s is a builtin predicate", pp.token);
1293*4887Schin 				goto eatdirective;
1294*4887Schin 			case X_SIZEOF:
1295*4887Schin 				error(2, "%s cannot be a predicate", pp.token);
1296*4887Schin 				goto eatdirective;
1297*4887Schin 			}
1298*4887Schin 			strcpy(pp.tmpbuf, pp.token);
1299*4887Schin 			switch (pppredargs())
1300*4887Schin 			{
1301*4887Schin 			case T_ID:
1302*4887Schin 			case T_STRING:
1303*4887Schin 				assert(directive, pp.tmpbuf, pp.args);
1304*4887Schin 				break;
1305*4887Schin 			case 0:
1306*4887Schin 				assert(directive, pp.tmpbuf, NiL);
1307*4887Schin 				break;
1308*4887Schin 			default:
1309*4887Schin 				error(2, "invalid predicate argument list");
1310*4887Schin 				goto eatdirective;
1311*4887Schin 			}
1312*4887Schin 			break;
1313*4887Schin 		tuple:
1314*4887Schin 			pp.state |= DEFINITION|NOEXPAND|NOSPACE;
1315*4887Schin 			rp = 0;
1316*4887Schin 			tp = mac->tuple;
1317*4887Schin 			if (!tp && !mac->value)
1318*4887Schin 				ppfsm(FSM_MACRO, sym->name);
1319*4887Schin 			while ((c = pplex()) && c != '>' && c != '\n')
1320*4887Schin 			{
1321*4887Schin 				for (; tp; tp = tp->nomatch)
1322*4887Schin 					if (streq(tp->token, pp.token))
1323*4887Schin 						break;
1324*4887Schin 				if (!tp)
1325*4887Schin 				{
1326*4887Schin 					if (!(tp = newof(0, struct pptuple, 1, strlen(pp.token))))
1327*4887Schin 						error(3, "out of space");
1328*4887Schin 					strcpy(tp->token, pp.token);
1329*4887Schin 					if (rp)
1330*4887Schin 					{
1331*4887Schin 						tp->nomatch = rp;
1332*4887Schin 						rp->nomatch = tp;
1333*4887Schin 					}
1334*4887Schin 					else
1335*4887Schin 					{
1336*4887Schin 						tp->nomatch = mac->tuple;
1337*4887Schin 						mac->tuple = tp;
1338*4887Schin 					}
1339*4887Schin 				}
1340*4887Schin 				rp = tp;
1341*4887Schin 				tp = tp->match;
1342*4887Schin 			}
1343*4887Schin 			pp.state &= ~NOSPACE;
1344*4887Schin 			if (!rp || c != '>')
1345*4887Schin 				error(2, "%s: > omitted in tuple macro definition", sym->name);
1346*4887Schin 			else
1347*4887Schin 			{
1348*4887Schin 				n = 2 * MAXTOKEN;
1349*4887Schin 				p = v = oldof(0, char, 0, n);
1350*4887Schin 				while ((c = pplex()) && c != '\n')
1351*4887Schin 					if (p > v || c != ' ')
1352*4887Schin 					{
1353*4887Schin 						STRCOPY(p, pp.token, s);
1354*4887Schin 						if (p > &v[n - MAXTOKEN] && (s = newof(v, char, n += MAXTOKEN, 0)) != v)
1355*4887Schin 						{
1356*4887Schin 							c = p - v;
1357*4887Schin 							v = s;
1358*4887Schin 							p = v + c;
1359*4887Schin 						}
1360*4887Schin 					}
1361*4887Schin 				while (p > v && *(p - 1) == ' ')
1362*4887Schin 					p--;
1363*4887Schin 				n = p - v;
1364*4887Schin 				tp = newof(0, struct pptuple, 1, n);
1365*4887Schin 				strcpy(tp->token, v);
1366*4887Schin 				tp->match = rp->match;
1367*4887Schin 				rp->match = tp;
1368*4887Schin 			}
1369*4887Schin 			goto benign;
1370*4887Schin 		case WARNING:
1371*4887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1372*4887Schin 				error(1, "#%s: non-standard directive", pp.token);
1373*4887Schin 			/*FALLTHROUGH*/
1374*4887Schin 		case ERROR:
1375*4887Schin 			pp.state &= ~DISABLE;
1376*4887Schin 			p = pp.tmpbuf;
1377*4887Schin 			while ((c = pplex()) != '\n')
1378*4887Schin 				if (p + strlen(pp.token) < &pp.tmpbuf[MAXTOKEN])
1379*4887Schin 				{
1380*4887Schin 					STRCOPY(p, pp.token, s);
1381*4887Schin 					pp.state &= ~NOSPACE;
1382*4887Schin 				}
1383*4887Schin 			*p = 0;
1384*4887Schin 			p = *pp.tmpbuf ? pp.tmpbuf : ((directive == WARNING) ? "user warning" : "user error");
1385*4887Schin 			n = (directive == WARNING) ? 1 : 3;
1386*4887Schin 			error(n, "%s", p);
1387*4887Schin 			break;
1388*4887Schin 		case LET:
1389*4887Schin 			n2 = error_info.line;
1390*4887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1391*4887Schin 				error(1, "#%s: non-standard directive", pp.token);
1392*4887Schin 			if (!(sym = macsym(c = pplex()))) goto eatdirective;
1393*4887Schin 			if ((c = pplex()) != '=')
1394*4887Schin 			{
1395*4887Schin 				error(2, "%s: = expected", sym->name);
1396*4887Schin 				goto eatdirective;
1397*4887Schin 			}
1398*4887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_MULTILINE|SYM_PREDEFINED|SYM_VARIADIC);
1399*4887Schin 			mac = sym->macro;
1400*4887Schin 			mac->arity = 0;
1401*4887Schin 			if (mac->value)
1402*4887Schin 			{
1403*4887Schin 				if (!(sym->flags & SYM_REDEFINE) && !sym->hidden)
1404*4887Schin 					error(1, "%s: redefined", sym->name);
1405*4887Schin #if MACKEYARGS
1406*4887Schin 				if ((pp.option & KEYARGS) && mac->formkeys) free(mac->formkeys);
1407*4887Schin 				else
1408*4887Schin #endif
1409*4887Schin 				free(mac->formals);
1410*4887Schin 				mac->formals = 0;
1411*4887Schin 				n = strlen(mac->value) + 1;
1412*4887Schin 			}
1413*4887Schin 			else
1414*4887Schin 			{
1415*4887Schin 				ppfsm(FSM_MACRO, sym->name);
1416*4887Schin 				n = 0;
1417*4887Schin 			}
1418*4887Schin 			n1 = ppexpr(&i1);
1419*4887Schin 			if (i1) c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%luU", n1);
1420*4887Schin 			else c = sfsprintf(pp.tmpbuf, MAXTOKEN, "%ld", n1);
1421*4887Schin 			if (n < ++c)
1422*4887Schin 			{
1423*4887Schin 				if (mac->value) free(mac->value);
1424*4887Schin 				mac->value = oldof(0, char, 0, c);
1425*4887Schin 			}
1426*4887Schin 			strcpy(mac->value, pp.tmpbuf);
1427*4887Schin 			sym->flags |= SYM_REDEFINE;
1428*4887Schin 			c = (pp.state & NEWLINE) ? '\n' : ' ';
1429*4887Schin 			goto benign;
1430*4887Schin 		case LINE:
1431*4887Schin 			pp.state &= ~DISABLE;
1432*4887Schin 			if ((c = pplex()) == '#')
1433*4887Schin 			{
1434*4887Schin 				c = pplex();
1435*4887Schin 				directive = INCLUDE;
1436*4887Schin 			}
1437*4887Schin 			if (c != T_DECIMAL && c != T_OCTAL)
1438*4887Schin 			{
1439*4887Schin 				error(1, "#%s: line number expected", dirname(LINE));
1440*4887Schin 				goto eatdirective;
1441*4887Schin 			}
1442*4887Schin 		linesync:
1443*4887Schin 			n = error_info.line;
1444*4887Schin 			error_info.line = strtol(pp.token, NiL, 0);
1445*4887Schin 			if (error_info.line == 0 && directive == LINE && (pp.state & STRICT) && !(pp.mode & HOSTED))
1446*4887Schin 				error(1, "#%s: line number should be > 0", dirname(LINE));
1447*4887Schin 			pp.state &= ~DISABLE;
1448*4887Schin 			pp.state |= STRIP;
1449*4887Schin 			switch (c = pplex())
1450*4887Schin 			{
1451*4887Schin 			case T_STRING:
1452*4887Schin 				s = error_info.file;
1453*4887Schin 				if (*(p = pp.token)) pathcanon(p, 0);
1454*4887Schin 				fp = ppsetfile(p);
1455*4887Schin 				error_info.file = fp->name;
1456*4887Schin 				if (error_info.line == 1)
1457*4887Schin 					ppmultiple(fp, INC_TEST);
1458*4887Schin 				switch (c = pplex())
1459*4887Schin 				{
1460*4887Schin 				case '\n':
1461*4887Schin 					break;
1462*4887Schin 				case T_DECIMAL:
1463*4887Schin 				case T_OCTAL:
1464*4887Schin 					if (directive == LINE && (pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1465*4887Schin 						error(1, "#%s: integer file type argument is non-standard", dirname(LINE));
1466*4887Schin 					break;
1467*4887Schin 				default:
1468*4887Schin 					error(1, "#%s: integer file type argument expected", dirname(LINE));
1469*4887Schin 					break;
1470*4887Schin 				}
1471*4887Schin 				if (directive == LINE) pp.in->flags &= ~IN_ignoreline;
1472*4887Schin 				else if (pp.incref)
1473*4887Schin 				{
1474*4887Schin 					if (error_info.file != s)
1475*4887Schin 					{
1476*4887Schin 						switch (*pp.token)
1477*4887Schin 						{
1478*4887Schin 						case PP_sync_push:
1479*4887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1480*4887Schin 							else (*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
1481*4887Schin 							break;
1482*4887Schin 						case PP_sync_pop:
1483*4887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1484*4887Schin 							else (*pp.incref)(s, error_info.file, n - 1, PP_SYNC_POP);
1485*4887Schin 							break;
1486*4887Schin 						case PP_sync_ignore:
1487*4887Schin 							if (pp.insert) (*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1488*4887Schin 							else
1489*4887Schin 							{
1490*4887Schin 								(*pp.incref)(s, error_info.file, n, PP_SYNC_IGNORE);
1491*4887Schin 								error_info.file = s;
1492*4887Schin 							}
1493*4887Schin 							break;
1494*4887Schin 						default:
1495*4887Schin 							if (*s)
1496*4887Schin 							{
1497*4887Schin 								if (fp == pp.insert)
1498*4887Schin 									pp.insert = 0;
1499*4887Schin 								else if (error_info.line == 1 && !pp.insert)
1500*4887Schin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_PUSH);
1501*4887Schin 								else
1502*4887Schin 								{
1503*4887Schin 									if (!pp.insert) pp.insert = ppgetfile(s);
1504*4887Schin 									(*pp.incref)(s, error_info.file, n, PP_SYNC_INSERT);
1505*4887Schin 								}
1506*4887Schin 							}
1507*4887Schin 							break;
1508*4887Schin 						}
1509*4887Schin 					}
1510*4887Schin 				}
1511*4887Schin 				break;
1512*4887Schin 			case '\n':
1513*4887Schin 				break;
1514*4887Schin 			default:
1515*4887Schin 				error(1, "#%s: \"file-name\" expected", dirname(LINE));
1516*4887Schin 				break;
1517*4887Schin 			}
1518*4887Schin 			if (directive == LINE && (pp.in->flags & IN_ignoreline))
1519*4887Schin 				error_info.line = n + 1;
1520*4887Schin 			else
1521*4887Schin 			{
1522*4887Schin 				pp.hidden = 0;
1523*4887Schin 				pp.state &= ~HIDDEN;
1524*4887Schin 				if (pp.linesync)
1525*4887Schin 				{
1526*4887Schin #if CATSTRINGS
1527*4887Schin 					if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
1528*4887Schin 					else
1529*4887Schin #endif
1530*4887Schin 					{
1531*4887Schin 						s = pp.lineid;
1532*4887Schin 						n = pp.flags;
1533*4887Schin 						if (directive == LINE)
1534*4887Schin 						{
1535*4887Schin 							pp.flags &= ~PP_linetype;
1536*4887Schin 							if (pp.macref) pp.lineid = dirname(LINE);
1537*4887Schin 						}
1538*4887Schin 						(*pp.linesync)(error_info.line, error_info.file);
1539*4887Schin 						pp.flags = n;
1540*4887Schin 						pp.lineid = s;
1541*4887Schin 					}
1542*4887Schin 				}
1543*4887Schin 			}
1544*4887Schin 			directive = LINE;
1545*4887Schin 			break;
1546*4887Schin 		case PRAGMA:
1547*4887Schin 			/*
1548*4887Schin 			 * #pragma [STDC] [pass:] [no]option [arg ...]
1549*4887Schin 			 *
1550*4887Schin 			 * pragma args are not expanded by default
1551*4887Schin 			 *
1552*4887Schin 			 * if STDC is present then it is silently passed on
1553*4887Schin 			 *
1554*4887Schin 			 * if pass is pp.pass then the option is used
1555*4887Schin 			 * and verified but is not passed on
1556*4887Schin 			 *
1557*4887Schin 			 * if pass is omitted then the option is passed on
1558*4887Schin 			 *
1559*4887Schin 			 * otherwise if pass is non-null and not pp.pass then
1560*4887Schin 			 * the option is passed on but not used
1561*4887Schin 			 *
1562*4887Schin 			 * if the line does not match this form then
1563*4887Schin 			 * it is passed on unchanged
1564*4887Schin 			 *
1565*4887Schin 			 *	#directive   pass:  option  [...]
1566*4887Schin 			 *	^         ^  ^   ^  ^     ^  ^   ^
1567*4887Schin 			 *	pp.valbuf p0 p1  p2 p3    p4 p5  p6
1568*4887Schin 			 *
1569*4887Schin 			 * p?	0 if component omitted
1570*4887Schin 			 * i0	0 if ``no''option
1571*4887Schin 			 */
1572*4887Schin 
1573*4887Schin 			p = pp.valbuf;
1574*4887Schin 			*p++ = '#';
1575*4887Schin 			STRCOPY(p, pp.token, s);
1576*4887Schin 			p0 = p;
1577*4887Schin 			if (pp.option & PRAGMAEXPAND)
1578*4887Schin 				pp.state &= ~DISABLE;
1579*4887Schin 			if (!(p6 = getline(p, &pp.valbuf[MAXTOKEN], !!(pp.option & PRAGMAEXPAND))))
1580*4887Schin 			{
1581*4887Schin 				*p0 = 0;
1582*4887Schin 				error(2, "%s: directive too long", pp.valbuf);
1583*4887Schin 				c = 0;
1584*4887Schin 				goto eatdirective;
1585*4887Schin 			}
1586*4887Schin 			p1 = ++p;
1587*4887Schin 			while (ppisid(*p))
1588*4887Schin 				p++;
1589*4887Schin 			if (p == p1)
1590*4887Schin 			{
1591*4887Schin 				p5 = p;
1592*4887Schin 				p4 = 0;
1593*4887Schin 				p3 = 0;
1594*4887Schin 				p2 = 0;
1595*4887Schin 				p1 = 0;
1596*4887Schin 			}
1597*4887Schin 			else if (*p != ':')
1598*4887Schin 			{
1599*4887Schin 				p5 = *p ? p + (*p == ' ') : 0;
1600*4887Schin 				p4 = p;
1601*4887Schin 				p3 = p1;
1602*4887Schin 				p2 = 0;
1603*4887Schin 				p1 = 0;
1604*4887Schin 			}
1605*4887Schin 			else
1606*4887Schin 			{
1607*4887Schin 				p2 = p++;
1608*4887Schin 				p3 = p;
1609*4887Schin 				while (ppisid(*p))
1610*4887Schin 					p++;
1611*4887Schin 				if (p == p3)
1612*4887Schin 				{
1613*4887Schin 					p4 = p1;
1614*4887Schin 					p3 = 0;
1615*4887Schin 					p2 = 0;
1616*4887Schin 					p1 = 0;
1617*4887Schin 				}
1618*4887Schin 				else
1619*4887Schin 					p4 = p;
1620*4887Schin 				p5 = *p4 ? p4 + (*p4 == ' ') : 0;
1621*4887Schin 			}
1622*4887Schin 			if (!p1 && p3 && (p4 - p3) == 4 && strneq(p3, "STDC", 4))
1623*4887Schin 				goto pass;
1624*4887Schin 			if ((pp.state & WARN) && !(pp.mode & (HOSTED|RELAX)))
1625*4887Schin 				error(1, "#%s: non-standard directive", dirname(PRAGMA));
1626*4887Schin 			i0 = !p3 || *p3 != 'n' || *(p3 + 1) != 'o';
1627*4887Schin 			if (!p3)
1628*4887Schin 				goto checkmap;
1629*4887Schin 			if (p1)
1630*4887Schin 			{
1631*4887Schin 				*p2 = 0;
1632*4887Schin 				n = streq(p1, pp.pass);
1633*4887Schin 				*p2 = ':';
1634*4887Schin 				if (!n)
1635*4887Schin 					goto checkmap;
1636*4887Schin 			}
1637*4887Schin 			else
1638*4887Schin 				n = 0;
1639*4887Schin 			i2 = *p4;
1640*4887Schin 			*p4 = 0;
1641*4887Schin 			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))
1642*4887Schin 				i1 = 0;
1643*4887Schin 			if ((pp.state & (COMPATIBILITY|STRICT)) == STRICT && !(pp.mode & (HOSTED|RELAX)))
1644*4887Schin 			{
1645*4887Schin 				if (pp.optflags[i1] & OPT_GLOBAL)
1646*4887Schin 					goto donedirective;
1647*4887Schin 				if (n || (pp.mode & WARN))
1648*4887Schin 				{
1649*4887Schin 					n = 0;
1650*4887Schin 					error(1, "#%s: non-standard directive ignored", dirname(PRAGMA));
1651*4887Schin 				}
1652*4887Schin 				i1 = 0;
1653*4887Schin 			}
1654*4887Schin 			if (!n)
1655*4887Schin 			{
1656*4887Schin 				if (!(pp.optflags[i1] & OPT_GLOBAL))
1657*4887Schin 				{
1658*4887Schin 					*p4 = i2;
1659*4887Schin 					goto checkmap;
1660*4887Schin 				}
1661*4887Schin 				if (!(pp.optflags[i1] & OPT_PASS))
1662*4887Schin 					n = 1;
1663*4887Schin 			}
1664*4887Schin 			else if (!i1)
1665*4887Schin 				error(2, "%s: unknown option", p1);
1666*4887Schin 			else if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
1667*4887Schin 				error(1, "%s: non-standard option", p1);
1668*4887Schin 			p = p5;
1669*4887Schin 			switch (i1)
1670*4887Schin 			{
1671*4887Schin 			case X_ALLMULTIPLE:
1672*4887Schin 				ppop(PP_MULTIPLE, i0);
1673*4887Schin 				break;
1674*4887Schin 			case X_ALLPOSSIBLE:
1675*4887Schin 				setoption(ALLPOSSIBLE, i0);
1676*4887Schin 				break;
1677*4887Schin 			case X_BUILTIN:
1678*4887Schin 				setmode(BUILTIN, i0);
1679*4887Schin 				break;
1680*4887Schin 			case X_CATLITERAL:
1681*4887Schin 				setmode(CATLITERAL, i0);
1682*4887Schin 				if (pp.mode & CATLITERAL)
1683*4887Schin 					setoption(STRINGSPLIT, 0);
1684*4887Schin 				break;
1685*4887Schin 			case X_CDIR:
1686*4887Schin 				tokop(PP_CDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
1687*4887Schin 				break;
1688*4887Schin 			case X_CHECKPOINT:
1689*4887Schin #if CHECKPOINT
1690*4887Schin 				ppload(p);
1691*4887Schin #else
1692*4887Schin 				error(3, "%s: preprocessor not compiled with checkpoint enabled", p3);
1693*4887Schin #endif
1694*4887Schin 				break;
1695*4887Schin 			case X_CHOP:
1696*4887Schin 				tokop(PP_CHOP, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1697*4887Schin 				break;
1698*4887Schin 			case X_COMPATIBILITY:
1699*4887Schin 				ppop(PP_COMPATIBILITY, i0);
1700*4887Schin 				break;
1701*4887Schin 			case X_DEBUG:
1702*4887Schin 				error_info.trace = i0 ? (p ? -strtol(p, NiL, 0) : -1) : 0;
1703*4887Schin 				break;
1704*4887Schin 			case X_ELSEIF:
1705*4887Schin 				setoption(ELSEIF, i0);
1706*4887Schin 				break;
1707*4887Schin 			case X_EXTERNALIZE:
1708*4887Schin 				setmode(EXTERNALIZE, i0);
1709*4887Schin 				break;
1710*4887Schin 			case X_FINAL:
1711*4887Schin 				setoption(FINAL, i0);
1712*4887Schin 				break;
1713*4887Schin 			case X_HEADEREXPAND:
1714*4887Schin 				setoption(HEADEREXPAND, i0);
1715*4887Schin 				break;
1716*4887Schin 			case X_HEADEREXPANDALL:
1717*4887Schin 				setoption(HEADEREXPANDALL, i0);
1718*4887Schin 				break;
1719*4887Schin 			case X_HIDE:
1720*4887Schin 			case X_NOTE:
1721*4887Schin 				PUSH_LINE(p);
1722*4887Schin 				/* UNDENT...*/
1723*4887Schin 	while (c = pplex())
1724*4887Schin 	{
1725*4887Schin 		if (c != T_ID) error(1, "%s: %s: identifier expected", p3, pp.token);
1726*4887Schin 		else if (sym = ppsymset(pp.symtab, pp.token))
1727*4887Schin 		{
1728*4887Schin 			if (i1 == X_NOTE)
1729*4887Schin 			{
1730*4887Schin 				sym->flags &= ~SYM_NOTICED;
1731*4887Schin 				ppfsm(FSM_MACRO, sym->name);
1732*4887Schin 			}
1733*4887Schin 			else if (i0)
1734*4887Schin 			{
1735*4887Schin 				if (!sym->hidden && !(sym->hidden = newof(0, struct pphide, 1, 0)))
1736*4887Schin 					error(3, "out of space");
1737*4887Schin 				if (!sym->macro)
1738*4887Schin 					ppfsm(FSM_MACRO, sym->name);
1739*4887Schin 				if (!sym->hidden->level++)
1740*4887Schin 				{
1741*4887Schin 					pp.hiding++;
1742*4887Schin 					if (sym->macro && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
1743*4887Schin 					{
1744*4887Schin 						sym->hidden->macro = sym->macro;
1745*4887Schin 						sym->macro = 0;
1746*4887Schin 						sym->hidden->flags = sym->flags;
1747*4887Schin 						sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
1748*4887Schin 					}
1749*4887Schin 				}
1750*4887Schin 			}
1751*4887Schin 			else if (sym->hidden)
1752*4887Schin 			{
1753*4887Schin 				if ((mac = sym->macro) && !(sym->flags & (SYM_ACTIVE|SYM_READONLY)))
1754*4887Schin 				{
1755*4887Schin 					if (mac->formals) free(mac->formals);
1756*4887Schin 					free(mac->value);
1757*4887Schin 					free(mac);
1758*4887Schin 					sym->macro = 0;
1759*4887Schin 					sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
1760*4887Schin 				}
1761*4887Schin 				if (!--sym->hidden->level)
1762*4887Schin 				{
1763*4887Schin 					pp.hiding--;
1764*4887Schin 					if (sym->hidden->macro)
1765*4887Schin 					{
1766*4887Schin 						sym->macro = sym->hidden->macro;
1767*4887Schin 						sym->flags = sym->hidden->flags;
1768*4887Schin 					}
1769*4887Schin 					free(sym->hidden);
1770*4887Schin 					sym->hidden = 0;
1771*4887Schin 				}
1772*4887Schin 			}
1773*4887Schin 		}
1774*4887Schin 	}
1775*4887Schin 				/*...INDENT*/
1776*4887Schin 				POP_LINE();
1777*4887Schin 				break;
1778*4887Schin 			case X_HOSTDIR:
1779*4887Schin 				tokop(PP_HOSTDIR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
1780*4887Schin 				break;
1781*4887Schin 			case X_HOSTED:
1782*4887Schin 				setmode(HOSTED, i0);
1783*4887Schin 				break;
1784*4887Schin 			case X_HOSTEDTRANSITION:
1785*4887Schin 				setmode(HOSTEDTRANSITION, i0);
1786*4887Schin 				break;
1787*4887Schin 			case X_ID:
1788*4887Schin 				tokop(PP_ID, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1789*4887Schin 				break;
1790*4887Schin 			case X_IGNORE:
1791*4887Schin 				tokop(PP_IGNORE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
1792*4887Schin 				break;
1793*4887Schin 			case X_INCLUDE:
1794*4887Schin 				tokop(PP_INCLUDE, p3, p, i0, TOKOP_STRING|TOKOP_DUP);
1795*4887Schin 				break;
1796*4887Schin 			case X_INITIAL:
1797*4887Schin 				setoption(INITIAL, i0);
1798*4887Schin 				break;
1799*4887Schin 			case X_KEYARGS:
1800*4887Schin 				ppop(PP_KEYARGS, i0);
1801*4887Schin 				break;
1802*4887Schin 			case X_LINE:
1803*4887Schin 				if (pp.linesync) pp.olinesync = pp.linesync;
1804*4887Schin 				pp.linesync = i0 ? pp.olinesync : (PPLINESYNC)0;
1805*4887Schin 				break;
1806*4887Schin 			case X_LINEBASE:
1807*4887Schin 				ppop(PP_LINEBASE, i0);
1808*4887Schin 				break;
1809*4887Schin 			case X_LINEFILE:
1810*4887Schin 				ppop(PP_LINEFILE, i0);
1811*4887Schin 				break;
1812*4887Schin 			case X_LINEID:
1813*4887Schin 				ppop(PP_LINEID, i0 ? p : (char*)0);
1814*4887Schin 				break;
1815*4887Schin 			case X_LINETYPE:
1816*4887Schin 				ppop(PP_LINETYPE, i0 ? (p ? strtol(p, NiL, 0) : 1) : 0);
1817*4887Schin 				break;
1818*4887Schin 			case X_MACREF:
1819*4887Schin 				if (!p)
1820*4887Schin 				{
1821*4887Schin 					if (i0 && !pp.macref)
1822*4887Schin 					{
1823*4887Schin 						ppop(PP_LINETYPE, 1);
1824*4887Schin 						ppop(PP_MACREF, ppmacref);
1825*4887Schin 					}
1826*4887Schin 					else error(2, "%s: option cannot be unset", p3);
1827*4887Schin 				}
1828*4887Schin 				else if (s = strchr(p, ' '))
1829*4887Schin 				{
1830*4887Schin 					if (pp.macref && (s = strchr(p, ' ')))
1831*4887Schin 					{
1832*4887Schin 						*s++ = 0;
1833*4887Schin 						c = strtol(s, NiL, 0);
1834*4887Schin 						var.type = pp.truncate;
1835*4887Schin 						pp.truncate = PPTOKSIZ;
1836*4887Schin 						(*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);
1837*4887Schin 						pp.truncate = var.type;
1838*4887Schin 					}
1839*4887Schin 					error_info.line -= 2;
1840*4887Schin 				}
1841*4887Schin 				break;
1842*4887Schin 			case X_MAP:
1843*4887Schin 				/*UNDENT*/
1844*4887Schin 	/*
1845*4887Schin 	 * #pragma pp:map [id ...] "/from/[,/to/]" [ "/old/new/[glnu]" ... ]
1846*4887Schin 	 */
1847*4887Schin 
1848*4887Schin 	if (!i0)
1849*4887Schin 	{
1850*4887Schin 		error(2, "%s: option cannot be unset", p3);
1851*4887Schin 		goto donedirective;
1852*4887Schin 	}
1853*4887Schin 	if (!p5)
1854*4887Schin 	{
1855*4887Schin 		error(2, "%s: address argument expected", p3);
1856*4887Schin 		goto donedirective;
1857*4887Schin 	}
1858*4887Schin 	PUSH_LINE(p5);
1859*4887Schin 	while ((c = pplex()) == T_ID)
1860*4887Schin 	{
1861*4887Schin 		sfsprintf(pp.tmpbuf, MAXTOKEN, "__%s__", s = pp.token);
1862*4887Schin 		if (c = (int)hashget(pp.dirtab, s))
1863*4887Schin 		{
1864*4887Schin 			hashput(pp.dirtab, 0, 0);
1865*4887Schin 			hashput(pp.dirtab, pp.tmpbuf, c);
1866*4887Schin 		}
1867*4887Schin 		if (c = (int)hashget(pp.strtab, s))
1868*4887Schin 		{
1869*4887Schin 			hashput(pp.strtab, 0, 0);
1870*4887Schin 			hashput(pp.strtab, pp.tmpbuf, c);
1871*4887Schin 		}
1872*4887Schin 	}
1873*4887Schin 	if (c != T_STRING || !*(s = pp.token))
1874*4887Schin 	{
1875*4887Schin 		if (c)
1876*4887Schin 			error(2, "%s: %s: address argument expected", p3, pptokstr(pp.token, 0));
1877*4887Schin 		goto eatmap;
1878*4887Schin 	}
1879*4887Schin 	map = newof(0, struct map, 1, 0);
1880*4887Schin 
1881*4887Schin 	/*
1882*4887Schin 	 * /from/
1883*4887Schin 	 */
1884*4887Schin 
1885*4887Schin 	if (i0 = regcomp(&map->re, s, REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL))
1886*4887Schin 		regfatal(&map->re, 3, i0);
1887*4887Schin 	if (*(s += map->re.re_npat))
1888*4887Schin 	{
1889*4887Schin 		error(2, "%s: invalid characters after pattern: %s ", p3, s);
1890*4887Schin 		goto eatmap;
1891*4887Schin 	}
1892*4887Schin 
1893*4887Schin 	/*
1894*4887Schin 	 * /old/new/[flags]
1895*4887Schin 	 */
1896*4887Schin 
1897*4887Schin 	edit = 0;
1898*4887Schin 	while ((c = pplex()) == T_STRING)
1899*4887Schin 	{
1900*4887Schin 		if (!*(s = pp.token))
1901*4887Schin 		{
1902*4887Schin 			error(2, "%s: substitution argument expected", p3);
1903*4887Schin 			goto eatmap;
1904*4887Schin 		}
1905*4887Schin 		if (edit)
1906*4887Schin 			edit = edit->next = newof(0, struct edit, 1, 0);
1907*4887Schin 		else
1908*4887Schin 			edit = map->edit = newof(0, struct edit, 1, 0);
1909*4887Schin 		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)))
1910*4887Schin 			s += edit->re.re_npat;
1911*4887Schin 		if (i0)
1912*4887Schin 			regfatal(&edit->re, 3, i0);
1913*4887Schin 		if (*s)
1914*4887Schin 		{
1915*4887Schin 			error(2, "%s: invalid characters after substitution: %s ", p3, s);
1916*4887Schin 			goto eatmap;
1917*4887Schin 		}
1918*4887Schin 	}
1919*4887Schin 	if (c)
1920*4887Schin 	{
1921*4887Schin 		error(2, "%s: %s: substitution argument expected", p3, pptokstr(pp.token, 0));
1922*4887Schin 		goto eatmap;
1923*4887Schin 	}
1924*4887Schin 	map->next = (struct map*)pp.maps;
1925*4887Schin 	pp.maps = (char*)map;
1926*4887Schin  eatmap:
1927*4887Schin 	POP_LINE();
1928*4887Schin 				/*INDENT*/
1929*4887Schin 				break;
1930*4887Schin 			case X_MAPINCLUDE:
1931*4887Schin 				ppmapinclude(NiL, p5);
1932*4887Schin 				break;
1933*4887Schin 			case X_MODERN:
1934*4887Schin 				setoption(MODERN, i0);
1935*4887Schin 				break;
1936*4887Schin 			case X_MULTIPLE:
1937*4887Schin 				n = 1;
1938*4887Schin 				if (pp.in->type == IN_FILE)
1939*4887Schin 					ppmultiple(ppsetfile(error_info.file), i0 ? INC_CLEAR : INC_TEST);
1940*4887Schin 				break;
1941*4887Schin 			case X_NATIVE:
1942*4887Schin 				setoption(NATIVE, i0);
1943*4887Schin 				break;
1944*4887Schin 			case X_OPSPACE:
1945*4887Schin 				ppfsm(FSM_OPSPACE, i0 ? p4 : (char*)0);
1946*4887Schin 				break;
1947*4887Schin 			case X_PASSTHROUGH:
1948*4887Schin 				ppop(PP_PASSTHROUGH, i0);
1949*4887Schin 				break;
1950*4887Schin 			case X_PEDANTIC:
1951*4887Schin 				ppop(PP_PEDANTIC, i0);
1952*4887Schin 				break;
1953*4887Schin 			case X_PLUSCOMMENT:
1954*4887Schin 				ppop(PP_PLUSCOMMENT, i0);
1955*4887Schin 				break;
1956*4887Schin 			case X_PLUSPLUS:
1957*4887Schin 				ppop(PP_PLUSPLUS, i0);
1958*4887Schin 				break;
1959*4887Schin 			case X_PLUSSPLICE:
1960*4887Schin 				setoption(PLUSSPLICE, i0);
1961*4887Schin 				break;
1962*4887Schin 			case X_PRAGMAEXPAND:
1963*4887Schin 				setoption(PRAGMAEXPAND, i0);
1964*4887Schin 				break;
1965*4887Schin 			case X_PRAGMAFLAGS:
1966*4887Schin 				tokop(PP_PRAGMAFLAGS, p3, p, i0, 0);
1967*4887Schin 				break;
1968*4887Schin 			case X_PREDEFINED:
1969*4887Schin 				setoption(PREDEFINED, i0);
1970*4887Schin 				break;
1971*4887Schin 			case X_PREFIX:
1972*4887Schin 				setoption(PREFIX, i0);
1973*4887Schin 				break;
1974*4887Schin 			case X_PRESERVE:
1975*4887Schin 				setoption(PRESERVE, i0);
1976*4887Schin 				if (pp.option & PRESERVE)
1977*4887Schin 				{
1978*4887Schin 					setmode(CATLITERAL, 0);
1979*4887Schin 					ppop(PP_COMPATIBILITY, 1);
1980*4887Schin 					ppop(PP_TRANSITION, 0);
1981*4887Schin 					ppop(PP_PLUSCOMMENT, 1);
1982*4887Schin 					ppop(PP_SPACEOUT, 1);
1983*4887Schin 					setoption(STRINGSPAN, 1);
1984*4887Schin 					setoption(STRINGSPLIT, 0);
1985*4887Schin 					ppop(PP_HOSTDIR, "-", 1);
1986*4887Schin 				}
1987*4887Schin 				break;
1988*4887Schin 			case X_PROTOTYPED:
1989*4887Schin 				/*
1990*4887Schin 				 * this option doesn't bump the token count
1991*4887Schin 				 */
1992*4887Schin 
1993*4887Schin 				n = 1;
1994*4887Schin 				directive = ENDIF;
1995*4887Schin #if PROTOTYPE
1996*4887Schin 				setoption(PROTOTYPED, i0);
1997*4887Schin #else
1998*4887Schin 				error(1, "preprocessor not compiled with prototype conversion enabled");
1999*4887Schin #endif
2000*4887Schin 				break;
2001*4887Schin 			case X_PROTO:
2002*4887Schin 				setoption(NOPROTO, !i0);
2003*4887Schin 				break;
2004*4887Schin 			case X_QUOTE:
2005*4887Schin 				tokop(PP_QUOTE, p3, p, i0, TOKOP_UNSET|TOKOP_STRING);
2006*4887Schin 				break;
2007*4887Schin 			case X_READONLY:
2008*4887Schin 				setmode(READONLY, i0);
2009*4887Schin 				break;
2010*4887Schin 			case X_REGUARD:
2011*4887Schin 				setoption(REGUARD, i0);
2012*4887Schin 				break;
2013*4887Schin 			case X_RESERVED:
2014*4887Schin 				tokop(PP_RESERVED, p3, p, i0, 0);
2015*4887Schin 				break;
2016*4887Schin 			case X_SPACEOUT:
2017*4887Schin 				if (!(pp.state & (COMPATIBILITY|COMPILE)))
2018*4887Schin 					ppop(PP_SPACEOUT, i0);
2019*4887Schin 				break;
2020*4887Schin 			case X_SPLICECAT:
2021*4887Schin 				setoption(SPLICECAT, i0);
2022*4887Schin 				break;
2023*4887Schin 			case X_SPLICESPACE:
2024*4887Schin 				setoption(SPLICESPACE, i0);
2025*4887Schin 				break;
2026*4887Schin 			case X_STANDARD:
2027*4887Schin 				tokop(PP_STANDARD, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
2028*4887Schin 				break;
2029*4887Schin 			case X_STRICT:
2030*4887Schin 				ppop(PP_STRICT, i0);
2031*4887Schin 				break;
2032*4887Schin 			case X_STRINGSPAN:
2033*4887Schin 				setoption(STRINGSPAN, i0);
2034*4887Schin 				break;
2035*4887Schin 			case X_STRINGSPLIT:
2036*4887Schin 				setoption(STRINGSPLIT, i0);
2037*4887Schin 				if (pp.option & STRINGSPLIT)
2038*4887Schin 					setmode(CATLITERAL, 0);
2039*4887Schin 				break;
2040*4887Schin 			case X_SYSTEM_HEADER:
2041*4887Schin 				if (i0)
2042*4887Schin 				{
2043*4887Schin 					pp.mode |= HOSTED;
2044*4887Schin 					pp.flags |= PP_hosted;
2045*4887Schin 					pp.in->flags |= IN_hosted;
2046*4887Schin 				}
2047*4887Schin 				else
2048*4887Schin 				{
2049*4887Schin 					pp.mode &= ~HOSTED;
2050*4887Schin 					pp.flags &= ~PP_hosted;
2051*4887Schin 					pp.in->flags &= ~PP_hosted;
2052*4887Schin 				}
2053*4887Schin 				break;
2054*4887Schin 			case X_TEST:
2055*4887Schin 				ppop(PP_TEST, p);
2056*4887Schin 				break;
2057*4887Schin 			case X_TEXT:
2058*4887Schin 				if (!(pp.option & KEEPNOTEXT))
2059*4887Schin 					setstate(NOTEXT, !i0);
2060*4887Schin 				break;
2061*4887Schin 			case X_TRANSITION:
2062*4887Schin 				ppop(PP_TRANSITION, i0);
2063*4887Schin 				if (pp.state & TRANSITION) ppop(PP_COMPATIBILITY, i0);
2064*4887Schin 				break;
2065*4887Schin 			case X_TRUNCATE:
2066*4887Schin 				ppop(PP_TRUNCATE, i0 ? (p ? strtol(p, NiL, 0) : TRUNCLENGTH) : 0);
2067*4887Schin 				break;
2068*4887Schin 			case X_VENDOR:
2069*4887Schin 				tokop(PP_VENDOR, p3, p, i0, TOKOP_UNSET|TOKOP_STRING|TOKOP_DUP);
2070*4887Schin 				break;
2071*4887Schin 			case X_VERSION:
2072*4887Schin 				if (!(*pp.control & SKIP) && pp.pragma && !(pp.state & NOTEXT))
2073*4887Schin 				{
2074*4887Schin 					sfsprintf(pp.tmpbuf, MAXTOKEN, "\"%s\"", pp.version);
2075*4887Schin 					(*pp.pragma)(dirname(PRAGMA), pp.pass, p3, pp.tmpbuf, !n);
2076*4887Schin 					if (pp.linesync && !n)
2077*4887Schin 						(*pp.linesync)(error_info.line, error_info.file);
2078*4887Schin 					emitted = 1;
2079*4887Schin 				}
2080*4887Schin 				break;
2081*4887Schin 			case X_WARN:
2082*4887Schin 				ppop(PP_WARN, i0);
2083*4887Schin 				break;
2084*4887Schin 			case X_ZEOF:
2085*4887Schin 				setoption(ZEOF, i0);
2086*4887Schin 				break;
2087*4887Schin #if DEBUG
2088*4887Schin 			case 0:
2089*4887Schin 			case X_INCLUDED:
2090*4887Schin 			case X_NOTICED:
2091*4887Schin 			case X_OPTION:
2092*4887Schin 			case X_STATEMENT:
2093*4887Schin 				break;
2094*4887Schin 			default:
2095*4887Schin 				error(PANIC, "%s: option recognized but not implemented", pp.valbuf);
2096*4887Schin 				break;
2097*4887Schin #endif
2098*4887Schin 			}
2099*4887Schin 			*p4 = i2;
2100*4887Schin 			if (!n)
2101*4887Schin 				goto checkmap;
2102*4887Schin 			goto donedirective;
2103*4887Schin 		case RENAME:
2104*4887Schin 			if ((pp.state & STRICT) && !(pp.mode & (HOSTED|RELAX)))
2105*4887Schin 				error(1, "#%s: non-standard directive", pp.token);
2106*4887Schin 			if ((c = pplex()) != T_ID)
2107*4887Schin 			{
2108*4887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2109*4887Schin 				goto eatdirective;
2110*4887Schin 			}
2111*4887Schin 			if (!(sym = pprefmac(pp.token, REF_DELETE)) || !sym->macro)
2112*4887Schin 				goto eatdirective;
2113*4887Schin 			if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
2114*4887Schin 			{
2115*4887Schin 				if (!(pp.option & ALLPOSSIBLE))
2116*4887Schin 					error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
2117*4887Schin 				goto eatdirective;
2118*4887Schin 			}
2119*4887Schin 			if ((c = pplex()) != T_ID)
2120*4887Schin 			{
2121*4887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2122*4887Schin 				goto eatdirective;
2123*4887Schin 			}
2124*4887Schin 			var.symbol = pprefmac(pp.token, REF_CREATE);
2125*4887Schin 			if (mac = var.symbol->macro)
2126*4887Schin 			{
2127*4887Schin 				if (var.symbol->flags & (SYM_ACTIVE|SYM_READONLY))
2128*4887Schin 				{
2129*4887Schin 					if (!(pp.option & ALLPOSSIBLE))
2130*4887Schin 						error(2, "%s: macro is %s", var.symbol->name, (var.symbol->flags & SYM_READONLY) ? "readonly" : "active");
2131*4887Schin 					goto eatdirective;
2132*4887Schin 				}
2133*4887Schin 				if (!(pp.mode & HOSTED) || !(var.symbol->flags & SYM_INITIAL))
2134*4887Schin 					error(1, "%s redefined", var.symbol->name);
2135*4887Schin 				if (mac->formals) free(mac->formals);
2136*4887Schin 				free(mac->value);
2137*4887Schin 				free(mac);
2138*4887Schin 			}
2139*4887Schin 			ppfsm(FSM_MACRO, var.symbol->name);
2140*4887Schin 			var.symbol->flags = sym->flags;
2141*4887Schin 			sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
2142*4887Schin 			var.symbol->macro = sym->macro;
2143*4887Schin 			sym->macro = 0;
2144*4887Schin 			break;
2145*4887Schin 		case UNDEF:
2146*4887Schin 			if ((c = pplex()) != T_ID)
2147*4887Schin 			{
2148*4887Schin 				error(1, "%s: invalid macro name", pptokstr(pp.token, 0));
2149*4887Schin 				goto eatdirective;
2150*4887Schin 			}
2151*4887Schin 			if (sym = pprefmac(pp.token, REF_DELETE))
2152*4887Schin 			{
2153*4887Schin 				if (mac = sym->macro)
2154*4887Schin 				{
2155*4887Schin 					if (sym->flags & (SYM_ACTIVE|SYM_READONLY))
2156*4887Schin 					{
2157*4887Schin 						if (!(pp.option & ALLPOSSIBLE))
2158*4887Schin 							error(2, "%s: macro is %s", sym->name, (sym->flags & SYM_READONLY) ? "readonly" : "active");
2159*4887Schin 						goto eatdirective;
2160*4887Schin 					}
2161*4887Schin 					if (mac->formals) free(mac->formals);
2162*4887Schin 					free(mac->value);
2163*4887Schin 					free(mac);
2164*4887Schin 					mac = sym->macro = 0;
2165*4887Schin 				}
2166*4887Schin 				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)))
2167*4887Schin 				{
2168*4887Schin 					ppsync();
2169*4887Schin 					ppprintf("#%s %s", dirname(UNDEF), sym->name);
2170*4887Schin 					emitted = 1;
2171*4887Schin 				}
2172*4887Schin 				sym->flags &= ~(SYM_BUILTIN|SYM_FUNCTION|SYM_INIT|SYM_MULTILINE|SYM_PREDEFINED|SYM_REDEFINE|SYM_VARIADIC);
2173*4887Schin 				n2 = error_info.line;
2174*4887Schin 				goto benign;
2175*4887Schin 			}
2176*4887Schin 			else pprefmac(pp.token, REF_UNDEF);
2177*4887Schin 			break;
2178*4887Schin #if DEBUG
2179*4887Schin 		default:
2180*4887Schin 			error(PANIC, "#%s: directive recognized but not implemented", pp.token);
2181*4887Schin 			goto eatdirective;
2182*4887Schin #endif
2183*4887Schin 		}
2184*4887Schin 		break;
2185*4887Schin 	case '\n':
2186*4887Schin 		break;
2187*4887Schin 	default:
2188*4887Schin 		error(1, "%s: invalid directive name", pptokstr(pp.token, 0));
2189*4887Schin 		goto eatdirective;
2190*4887Schin 	}
2191*4887Schin  enddirective:
2192*4887Schin #if COMPATIBLE
2193*4887Schin 	if (c != '\n' && !(pp.state & COMPATIBILITY))
2194*4887Schin #else
2195*4887Schin 	if (c != '\n')
2196*4887Schin #endif
2197*4887Schin 	{
2198*4887Schin 		pp.state |= DISABLE|NOSPACE;
2199*4887Schin 		if ((c = pplex()) != '\n' && (pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC)
2200*4887Schin 			error(1, "%s: invalid characters after directive", pptokstr(pp.token, 0));
2201*4887Schin 	}
2202*4887Schin  eatdirective:
2203*4887Schin 	if (c != '\n')
2204*4887Schin 	{
2205*4887Schin 		pp.state |= DISABLE;
2206*4887Schin 		while (pplex() != '\n');
2207*4887Schin 	}
2208*4887Schin  donedirective:
2209*4887Schin #if _HUH_2002_05_09
2210*4887Schin 	if (!(pp.state & EOF2NL))
2211*4887Schin 		error(2, "%s in directive", pptokchr(0));
2212*4887Schin #endif
2213*4887Schin 	pp.state &= ~RESTORE;
2214*4887Schin 	pp.mode &= ~RELAX;
2215*4887Schin 	if (!(*pp.control & SKIP))
2216*4887Schin 	{
2217*4887Schin 		pp.state |= restore;
2218*4887Schin 		switch (directive)
2219*4887Schin 		{
2220*4887Schin 		case LINE:
2221*4887Schin 			return 0;
2222*4887Schin 		case INCLUDE:
2223*4887Schin 			if (pp.include)
2224*4887Schin 			{
2225*4887Schin 				error_info.line++;
2226*4887Schin 				PUSH_FILE(pp.include, n);
2227*4887Schin 				if (!pp.vendor && (pp.found->type & TYPE_VENDOR))
2228*4887Schin 					pp.vendor = 1;
2229*4887Schin 				pp.include = 0;
2230*4887Schin 				return 0;
2231*4887Schin 			}
2232*4887Schin 			if (pp.incref)
2233*4887Schin 				(*pp.incref)(error_info.file, ppgetfile(pp.path)->name, error_info.line, PP_SYNC_IGNORE);
2234*4887Schin 			else if (pp.linesync && pp.macref)
2235*4887Schin 			{
2236*4887Schin 				pp.flags |= PP_lineignore;
2237*4887Schin 				(*pp.linesync)(error_info.line, ppgetfile(pp.path)->name);
2238*4887Schin 			}
2239*4887Schin 			/*FALLTHROUGH*/
2240*4887Schin 		default:
2241*4887Schin 			pp.in->flags |= IN_tokens;
2242*4887Schin 			/*FALLTHROUGH*/
2243*4887Schin 		case ENDIF:
2244*4887Schin 			error_info.line++;
2245*4887Schin 			if (emitted)
2246*4887Schin 			{
2247*4887Schin 				ppputchar('\n');
2248*4887Schin 				ppcheckout();
2249*4887Schin 			}
2250*4887Schin 			else
2251*4887Schin 			{
2252*4887Schin 				pp.state |= HIDDEN;
2253*4887Schin 				pp.hidden++;
2254*4887Schin 			}
2255*4887Schin 			return 0;
2256*4887Schin 		}
2257*4887Schin 	}
2258*4887Schin 	pp.state |= restore|HIDDEN|SKIPCONTROL;
2259*4887Schin 	pp.hidden++;
2260*4887Schin 	pp.level++;
2261*4887Schin 	error_info.line++;
2262*4887Schin 	return 0;
2263*4887Schin }
2264*4887Schin 
2265*4887Schin /*
2266*4887Schin  * grow the pp nesting control stack
2267*4887Schin  */
2268*4887Schin 
2269*4887Schin void
2270*4887Schin ppnest(void)
2271*4887Schin {
2272*4887Schin 	register struct ppinstk*	ip;
2273*4887Schin 	int				oz;
2274*4887Schin 	int				nz;
2275*4887Schin 	long				adjust;
2276*4887Schin 	long*				op;
2277*4887Schin 	long*				np;
2278*4887Schin 
2279*4887Schin 	oz = pp.constack;
2280*4887Schin 	op = pp.maxcon - oz + 1;
2281*4887Schin 	nz = oz * 2;
2282*4887Schin 	np = newof(op, long, nz, 0);
2283*4887Schin 	if (adjust = (np - op))
2284*4887Schin 	{
2285*4887Schin 		ip = pp.in;
2286*4887Schin 		do
2287*4887Schin 		{
2288*4887Schin 			if (ip->control)
2289*4887Schin 				ip->control += adjust;
2290*4887Schin 		} while (ip = ip->prev);
2291*4887Schin 	}
2292*4887Schin 	pp.control = np + oz;
2293*4887Schin 	pp.constack = nz;
2294*4887Schin 	pp.maxcon = np + nz - 1;
2295*4887Schin }
2296