xref: /titanic_50/usr/src/lib/libpp/common/ppop.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
1*da2e3ebdSchin /***********************************************************************
2*da2e3ebdSchin *                                                                      *
3*da2e3ebdSchin *               This software is part of the ast package               *
4*da2e3ebdSchin *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5*da2e3ebdSchin *                      and is licensed under the                       *
6*da2e3ebdSchin *                  Common Public License, Version 1.0                  *
7*da2e3ebdSchin *                      by AT&T Knowledge Ventures                      *
8*da2e3ebdSchin *                                                                      *
9*da2e3ebdSchin *                A copy of the License is available at                 *
10*da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*da2e3ebdSchin *                                                                      *
13*da2e3ebdSchin *              Information and Software Systems Research               *
14*da2e3ebdSchin *                            AT&T Research                             *
15*da2e3ebdSchin *                           Florham Park NJ                            *
16*da2e3ebdSchin *                                                                      *
17*da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18*da2e3ebdSchin *                                                                      *
19*da2e3ebdSchin ***********************************************************************/
20*da2e3ebdSchin #pragma prototyped
21*da2e3ebdSchin /*
22*da2e3ebdSchin  * Glenn Fowler
23*da2e3ebdSchin  * AT&T Research
24*da2e3ebdSchin  *
25*da2e3ebdSchin  * preprocessor library control interface
26*da2e3ebdSchin  */
27*da2e3ebdSchin 
28*da2e3ebdSchin #include "pplib.h"
29*da2e3ebdSchin #include "pptab.h"
30*da2e3ebdSchin 
31*da2e3ebdSchin #include <ls.h>
32*da2e3ebdSchin 
33*da2e3ebdSchin #define REFONE	(pp.truncate?(Hash_table_t*)0:pp.symtab)
34*da2e3ebdSchin #define REFALL	(pp.truncate?pp.dirtab:pp.symtab)
35*da2e3ebdSchin 
36*da2e3ebdSchin #define ppiskey(t,v,p)	(p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
37*da2e3ebdSchin 
38*da2e3ebdSchin /*
39*da2e3ebdSchin  * set option value
40*da2e3ebdSchin  * initialization files have lowest precedence
41*da2e3ebdSchin  */
42*da2e3ebdSchin 
43*da2e3ebdSchin static void
44*da2e3ebdSchin set(register long* p, register long op, int val)
45*da2e3ebdSchin {
46*da2e3ebdSchin 	long*	r;
47*da2e3ebdSchin 
48*da2e3ebdSchin 	r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
49*da2e3ebdSchin 	if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op))
50*da2e3ebdSchin 	{
51*da2e3ebdSchin 		if (!pp.initialized && !(pp.mode & INIT))
52*da2e3ebdSchin 			*r |= op;
53*da2e3ebdSchin 		if (val)
54*da2e3ebdSchin 			*p |= op;
55*da2e3ebdSchin 		else
56*da2e3ebdSchin 			*p &= ~op;
57*da2e3ebdSchin 	}
58*da2e3ebdSchin 	debug((-7, "set(%s)=%s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*p) : p == &pp.mode ? ppmodestr(*p) : ppoptionstr(*p)));
59*da2e3ebdSchin }
60*da2e3ebdSchin 
61*da2e3ebdSchin /*
62*da2e3ebdSchin  * initialize hash table with keywords from key
63*da2e3ebdSchin  */
64*da2e3ebdSchin 
65*da2e3ebdSchin static void
66*da2e3ebdSchin inithash(register Hash_table_t* tab, register struct ppkeyword* key)
67*da2e3ebdSchin {
68*da2e3ebdSchin 	register char*	s;
69*da2e3ebdSchin 
70*da2e3ebdSchin 	for (; s = key->name; key++)
71*da2e3ebdSchin 	{
72*da2e3ebdSchin 		if (!ppisid(*s))
73*da2e3ebdSchin 			s++;
74*da2e3ebdSchin 		hashput(tab, s, key->value);
75*da2e3ebdSchin 	}
76*da2e3ebdSchin }
77*da2e3ebdSchin 
78*da2e3ebdSchin /*
79*da2e3ebdSchin  * return ppkeyword table name given value
80*da2e3ebdSchin  */
81*da2e3ebdSchin 
82*da2e3ebdSchin char*
83*da2e3ebdSchin ppkeyname(register int value, int dir)
84*da2e3ebdSchin {
85*da2e3ebdSchin 	register char*			s;
86*da2e3ebdSchin 	register struct ppkeyword*	p;
87*da2e3ebdSchin 
88*da2e3ebdSchin 	if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
89*da2e3ebdSchin 	{
90*da2e3ebdSchin 		s = (p + (value - p->value))->name;
91*da2e3ebdSchin 		return s + !ppisid(*s);
92*da2e3ebdSchin 	}
93*da2e3ebdSchin #if DEBUG
94*da2e3ebdSchin 	error(PANIC, "no keyword table name for value=%d", value);
95*da2e3ebdSchin #endif
96*da2e3ebdSchin 	return "UNKNOWN";
97*da2e3ebdSchin }
98*da2e3ebdSchin 
99*da2e3ebdSchin /*
100*da2e3ebdSchin  * add to the include maps
101*da2e3ebdSchin  */
102*da2e3ebdSchin 
103*da2e3ebdSchin void
104*da2e3ebdSchin ppmapinclude(char* file, register char* s)
105*da2e3ebdSchin {
106*da2e3ebdSchin 	register int		c;
107*da2e3ebdSchin 	register struct ppdirs*	dp;
108*da2e3ebdSchin 	int			fd;
109*da2e3ebdSchin 	int			flags;
110*da2e3ebdSchin 	int			index;
111*da2e3ebdSchin 	int			token;
112*da2e3ebdSchin 	char*			t;
113*da2e3ebdSchin 	char*			old_file;
114*da2e3ebdSchin 	long			old_state;
115*da2e3ebdSchin 	struct ppfile*		fp;
116*da2e3ebdSchin 	struct ppfile*		mp;
117*da2e3ebdSchin 
118*da2e3ebdSchin 	old_file = error_info.file;
119*da2e3ebdSchin 	old_state = pp.state;
120*da2e3ebdSchin 	if (s)
121*da2e3ebdSchin 		PUSH_BUFFER("mapinclude", s, 1);
122*da2e3ebdSchin 	else if (file)
123*da2e3ebdSchin 	{
124*da2e3ebdSchin 		if (*file == '-')
125*da2e3ebdSchin 		{
126*da2e3ebdSchin 			if (!error_info.file)
127*da2e3ebdSchin 			{
128*da2e3ebdSchin 				error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
129*da2e3ebdSchin 				return;
130*da2e3ebdSchin 			}
131*da2e3ebdSchin 			s = t = strcopy(pp.tmpbuf, error_info.file);
132*da2e3ebdSchin 			c = *++file;
133*da2e3ebdSchin 			for (;;)
134*da2e3ebdSchin 			{
135*da2e3ebdSchin 				if (s <= pp.tmpbuf || *s == '/')
136*da2e3ebdSchin 				{
137*da2e3ebdSchin 					s = t;
138*da2e3ebdSchin 					break;
139*da2e3ebdSchin 				}
140*da2e3ebdSchin 				else if (*s == c)
141*da2e3ebdSchin 					break;
142*da2e3ebdSchin 				s--;
143*da2e3ebdSchin 			}
144*da2e3ebdSchin 			strcpy(s, file);
145*da2e3ebdSchin 			file = pp.tmpbuf;
146*da2e3ebdSchin 		}
147*da2e3ebdSchin 		if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
148*da2e3ebdSchin 			return;
149*da2e3ebdSchin 		PUSH_FILE(file, fd);
150*da2e3ebdSchin 	}
151*da2e3ebdSchin 	else
152*da2e3ebdSchin 		return;
153*da2e3ebdSchin #if CATSTRINGS
154*da2e3ebdSchin 	pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
155*da2e3ebdSchin #else
156*da2e3ebdSchin 	pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
157*da2e3ebdSchin #endif
158*da2e3ebdSchin 	pp.level++;
159*da2e3ebdSchin 	flags = INC_MAPALL;
160*da2e3ebdSchin 	fp = mp = 0;
161*da2e3ebdSchin 	for (;;)
162*da2e3ebdSchin 	{
163*da2e3ebdSchin 		switch (token = pplex())
164*da2e3ebdSchin 		{
165*da2e3ebdSchin 		case 0:
166*da2e3ebdSchin 		case T_STRING:
167*da2e3ebdSchin 		case T_HEADER:
168*da2e3ebdSchin 			if (fp)
169*da2e3ebdSchin 			{
170*da2e3ebdSchin 				fp->guard = INC_IGNORE;
171*da2e3ebdSchin 				for (dp = pp.firstdir->next; dp; dp = dp->next)
172*da2e3ebdSchin 					if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
173*da2e3ebdSchin 					{
174*da2e3ebdSchin 						ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
175*da2e3ebdSchin 						break;
176*da2e3ebdSchin 					}
177*da2e3ebdSchin 			}
178*da2e3ebdSchin 			if (!token)
179*da2e3ebdSchin 				break;
180*da2e3ebdSchin 			pathcanon(pp.token, 0);
181*da2e3ebdSchin 			fp = ppsetfile(pp.token);
182*da2e3ebdSchin 			if (mp)
183*da2e3ebdSchin 			{
184*da2e3ebdSchin 				mp->flags |= flags;
185*da2e3ebdSchin 				if (streq(fp->name, "."))
186*da2e3ebdSchin 					mp->flags |= INC_MAPNOLOCAL;
187*da2e3ebdSchin 				else
188*da2e3ebdSchin 					mp->bound[index] = fp;
189*da2e3ebdSchin 
190*da2e3ebdSchin 				fp = mp = 0;
191*da2e3ebdSchin 			}
192*da2e3ebdSchin 			else
193*da2e3ebdSchin 				index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
194*da2e3ebdSchin 			continue;
195*da2e3ebdSchin 		case '=':
196*da2e3ebdSchin 			if (!(mp = fp))
197*da2e3ebdSchin 				error(3, "%s: \"name\" = \"binding\" expected");
198*da2e3ebdSchin 			fp = 0;
199*da2e3ebdSchin 			continue;
200*da2e3ebdSchin 		case '\n':
201*da2e3ebdSchin 			continue;
202*da2e3ebdSchin 		case T_ID:
203*da2e3ebdSchin 			if (streq(pp.token, "all"))
204*da2e3ebdSchin 			{
205*da2e3ebdSchin 				flags = INC_MAPALL;
206*da2e3ebdSchin 				continue;
207*da2e3ebdSchin 			}
208*da2e3ebdSchin 			else if (streq(pp.token, "hosted"))
209*da2e3ebdSchin 			{
210*da2e3ebdSchin 				flags = INC_MAPHOSTED;
211*da2e3ebdSchin 				continue;
212*da2e3ebdSchin 			}
213*da2e3ebdSchin 			else if (streq(pp.token, "nohosted"))
214*da2e3ebdSchin 			{
215*da2e3ebdSchin 				flags = INC_MAPNOHOSTED;
216*da2e3ebdSchin 				continue;
217*da2e3ebdSchin 			}
218*da2e3ebdSchin 			/*FALLTHROUGH*/
219*da2e3ebdSchin 		default:
220*da2e3ebdSchin 			error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
221*da2e3ebdSchin 			break;
222*da2e3ebdSchin 		}
223*da2e3ebdSchin 		break;
224*da2e3ebdSchin 	}
225*da2e3ebdSchin 	pp.level--;
226*da2e3ebdSchin 	error_info.file = old_file;
227*da2e3ebdSchin 	pp.state = old_state;
228*da2e3ebdSchin }
229*da2e3ebdSchin 
230*da2e3ebdSchin /*
231*da2e3ebdSchin  * return non-0 if file is identical to fd
232*da2e3ebdSchin  */
233*da2e3ebdSchin 
234*da2e3ebdSchin static int
235*da2e3ebdSchin identical(char* file, int fd)
236*da2e3ebdSchin {
237*da2e3ebdSchin 	struct stat	a;
238*da2e3ebdSchin 	struct stat	b;
239*da2e3ebdSchin 
240*da2e3ebdSchin 	return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
241*da2e3ebdSchin }
242*da2e3ebdSchin 
243*da2e3ebdSchin /*
244*da2e3ebdSchin  * compare up to pp.truncate chars
245*da2e3ebdSchin  *
246*da2e3ebdSchin  * NOTE: __STD* and symbols containing ' ' are not truncated
247*da2e3ebdSchin  */
248*da2e3ebdSchin 
249*da2e3ebdSchin static int
250*da2e3ebdSchin trunccomp(register char* a, register char* b)
251*da2e3ebdSchin {
252*da2e3ebdSchin 	return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
253*da2e3ebdSchin }
254*da2e3ebdSchin 
255*da2e3ebdSchin /*
256*da2e3ebdSchin  * hash up to pp.truncate chars
257*da2e3ebdSchin  *
258*da2e3ebdSchin  * NOTE: __STD* and symbols containing ' ' are not truncated
259*da2e3ebdSchin  */
260*da2e3ebdSchin 
261*da2e3ebdSchin static unsigned int
262*da2e3ebdSchin trunchash(char* a)
263*da2e3ebdSchin {
264*da2e3ebdSchin 	int	n;
265*da2e3ebdSchin 
266*da2e3ebdSchin 	return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
267*da2e3ebdSchin }
268*da2e3ebdSchin 
269*da2e3ebdSchin #if DEBUG & TRACE_debug
270*da2e3ebdSchin /*
271*da2e3ebdSchin  * append context to debug trace
272*da2e3ebdSchin  */
273*da2e3ebdSchin 
274*da2e3ebdSchin static int
275*da2e3ebdSchin context(Sfio_t* sp, int level, int flags)
276*da2e3ebdSchin {
277*da2e3ebdSchin 	static int	state;
278*da2e3ebdSchin 
279*da2e3ebdSchin 	NoP(level);
280*da2e3ebdSchin 	NoP(flags);
281*da2e3ebdSchin 	if (error_info.trace <= -10 && pp.state != state)
282*da2e3ebdSchin 	{
283*da2e3ebdSchin 		state = pp.state;
284*da2e3ebdSchin 		sfprintf(sp, " %s", ppstatestr(pp.state));
285*da2e3ebdSchin 	}
286*da2e3ebdSchin 	return 1;
287*da2e3ebdSchin }
288*da2e3ebdSchin #endif
289*da2e3ebdSchin 
290*da2e3ebdSchin /*
291*da2e3ebdSchin  * reset include guard
292*da2e3ebdSchin  */
293*da2e3ebdSchin 
294*da2e3ebdSchin static int
295*da2e3ebdSchin unguard(const char* name, char* v, void* handle)
296*da2e3ebdSchin {
297*da2e3ebdSchin 	register struct ppfile*		fp = (struct ppfile*)v;
298*da2e3ebdSchin 
299*da2e3ebdSchin 	fp->guard = 0;
300*da2e3ebdSchin 	return 0;
301*da2e3ebdSchin }
302*da2e3ebdSchin 
303*da2e3ebdSchin /*
304*da2e3ebdSchin  * reset macro definition
305*da2e3ebdSchin  */
306*da2e3ebdSchin 
307*da2e3ebdSchin static void
308*da2e3ebdSchin undefine(void* p)
309*da2e3ebdSchin {
310*da2e3ebdSchin 	struct ppmacro*		mac = ((struct ppsymbol*)p)->macro;
311*da2e3ebdSchin 
312*da2e3ebdSchin 	if (mac)
313*da2e3ebdSchin 	{
314*da2e3ebdSchin 		if (mac->formals)
315*da2e3ebdSchin 			free(mac->formals);
316*da2e3ebdSchin 		free(mac->value);
317*da2e3ebdSchin 		free(mac);
318*da2e3ebdSchin 	}
319*da2e3ebdSchin }
320*da2e3ebdSchin 
321*da2e3ebdSchin /*
322*da2e3ebdSchin  * pp operations
323*da2e3ebdSchin  *
324*da2e3ebdSchin  * NOTE: PP_INIT must be done before the first pplex() call
325*da2e3ebdSchin  *	 PP_DONE must be done after the last pplex() call
326*da2e3ebdSchin  *	 PP_INIT-PP_DONE must be done for each new PP_INPUT
327*da2e3ebdSchin  */
328*da2e3ebdSchin 
329*da2e3ebdSchin void
330*da2e3ebdSchin ppop(int op, ...)
331*da2e3ebdSchin {
332*da2e3ebdSchin 	va_list				ap;
333*da2e3ebdSchin 	register char*			p;
334*da2e3ebdSchin 	register struct ppkeyword*	kp;
335*da2e3ebdSchin 	register char*			s;
336*da2e3ebdSchin 	int				c;
337*da2e3ebdSchin 	long				n;
338*da2e3ebdSchin 	char*				t;
339*da2e3ebdSchin 	struct ppdirs*			dp;
340*da2e3ebdSchin 	struct ppdirs*			hp;
341*da2e3ebdSchin 	struct ppsymkey*		key;
342*da2e3ebdSchin 	struct oplist*			xp;
343*da2e3ebdSchin 	Sfio_t*				sp;
344*da2e3ebdSchin 	struct stat			st;
345*da2e3ebdSchin 	PPCOMMENT			ppcomment;
346*da2e3ebdSchin 	PPLINESYNC			pplinesync;
347*da2e3ebdSchin 
348*da2e3ebdSchin 	static int			initialized;
349*da2e3ebdSchin 
350*da2e3ebdSchin 	va_start(ap, op);
351*da2e3ebdSchin 	switch (op)
352*da2e3ebdSchin 	{
353*da2e3ebdSchin 	case PP_ASSERT:
354*da2e3ebdSchin 	case PP_DEFINE:
355*da2e3ebdSchin 	case PP_DIRECTIVE:
356*da2e3ebdSchin 	case PP_OPTION:
357*da2e3ebdSchin 	case PP_READ:
358*da2e3ebdSchin 	case PP_UNDEF:
359*da2e3ebdSchin 		if (pp.initialized)
360*da2e3ebdSchin 			goto before;
361*da2e3ebdSchin 		if ((p = va_arg(ap, char*)) && *p)
362*da2e3ebdSchin 		{
363*da2e3ebdSchin 			if (pp.lastop)
364*da2e3ebdSchin 				pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
365*da2e3ebdSchin 			else
366*da2e3ebdSchin 				pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
367*da2e3ebdSchin 			pp.lastop->op = op;
368*da2e3ebdSchin 			pp.lastop->value = p;
369*da2e3ebdSchin 		}
370*da2e3ebdSchin 		break;
371*da2e3ebdSchin 	case PP_BUILTIN:
372*da2e3ebdSchin 		pp.builtin = va_arg(ap, PPBUILTIN);
373*da2e3ebdSchin 		break;
374*da2e3ebdSchin 	case PP_CDIR:
375*da2e3ebdSchin 		p = va_arg(ap, char*);
376*da2e3ebdSchin 		c = va_arg(ap, int);
377*da2e3ebdSchin 		pp.cdir.path = 0;
378*da2e3ebdSchin 		if (!p)
379*da2e3ebdSchin 			pp.c = c;
380*da2e3ebdSchin 		else if (streq(p, "-"))
381*da2e3ebdSchin 		{
382*da2e3ebdSchin 			pp.c = c;
383*da2e3ebdSchin 			for (dp = pp.firstdir; dp; dp = dp->next)
384*da2e3ebdSchin 				dp->c = c;
385*da2e3ebdSchin 		}
386*da2e3ebdSchin 		else if (!pp.c)
387*da2e3ebdSchin 		{
388*da2e3ebdSchin 			if (!*p || stat((pathcanon(p, 0), p), &st))
389*da2e3ebdSchin 				pp.c = c;
390*da2e3ebdSchin 			else
391*da2e3ebdSchin 			{
392*da2e3ebdSchin 				for (dp = pp.firstdir; dp; dp = dp->next)
393*da2e3ebdSchin 				{
394*da2e3ebdSchin 					if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
395*da2e3ebdSchin 						pp.c = 1;
396*da2e3ebdSchin 					dp->c = pp.c == 1;
397*da2e3ebdSchin 				}
398*da2e3ebdSchin 				if (!pp.c)
399*da2e3ebdSchin 				{
400*da2e3ebdSchin 					pp.cdir.path = p;
401*da2e3ebdSchin 					SAVEID(&pp.cdir.id, &st);
402*da2e3ebdSchin 				}
403*da2e3ebdSchin 			}
404*da2e3ebdSchin 		}
405*da2e3ebdSchin 		break;
406*da2e3ebdSchin 	case PP_CHOP:
407*da2e3ebdSchin 		if (p = va_arg(ap, char*))
408*da2e3ebdSchin 		{
409*da2e3ebdSchin 			c = strlen(p);
410*da2e3ebdSchin 			xp = newof(0, struct oplist, 1, c + 1);
411*da2e3ebdSchin 			xp->value = ((char*)xp) + sizeof(struct oplist);
412*da2e3ebdSchin 			s = xp->value;
413*da2e3ebdSchin 			c = *p++;
414*da2e3ebdSchin 			while (*p && *p != c)
415*da2e3ebdSchin 				*s++ = *p++;
416*da2e3ebdSchin 			*s++ = '/';
417*da2e3ebdSchin 			xp->op = s - xp->value;
418*da2e3ebdSchin 			*s++ = 0;
419*da2e3ebdSchin 			if (*p && *++p && *p != c)
420*da2e3ebdSchin 			{
421*da2e3ebdSchin 				while (*p && *p != c)
422*da2e3ebdSchin 					*s++ = *p++;
423*da2e3ebdSchin 				*s++ = '/';
424*da2e3ebdSchin 			}
425*da2e3ebdSchin 			*s = 0;
426*da2e3ebdSchin 			xp->next = pp.chop;
427*da2e3ebdSchin 			pp.chop = xp;
428*da2e3ebdSchin 		}
429*da2e3ebdSchin 		break;
430*da2e3ebdSchin 	case PP_COMMENT:
431*da2e3ebdSchin 		if (pp.comment = va_arg(ap, PPCOMMENT))
432*da2e3ebdSchin 			pp.flags |= PP_comment;
433*da2e3ebdSchin 		else
434*da2e3ebdSchin 			pp.flags &= ~PP_comment;
435*da2e3ebdSchin 		break;
436*da2e3ebdSchin 	case PP_COMPATIBILITY:
437*da2e3ebdSchin 		set(&pp.state, COMPATIBILITY, va_arg(ap, int));
438*da2e3ebdSchin #if COMPATIBLE
439*da2e3ebdSchin 		if (pp.initialized)
440*da2e3ebdSchin 			ppfsm(FSM_COMPATIBILITY, NiL);
441*da2e3ebdSchin #else
442*da2e3ebdSchin 		if (pp.state & COMPATIBILITY)
443*da2e3ebdSchin 			error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
444*da2e3ebdSchin #endif
445*da2e3ebdSchin 		if (pp.state & COMPATIBILITY)
446*da2e3ebdSchin 			pp.flags |= PP_compatibility;
447*da2e3ebdSchin 		else
448*da2e3ebdSchin 			pp.flags &= ~PP_compatibility;
449*da2e3ebdSchin 		break;
450*da2e3ebdSchin 	case PP_COMPILE:
451*da2e3ebdSchin 		if (pp.initialized)
452*da2e3ebdSchin 			goto before;
453*da2e3ebdSchin 		pp.state |= COMPILE;
454*da2e3ebdSchin 		if (!pp.symtab)
455*da2e3ebdSchin 			pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
456*da2e3ebdSchin 		if (kp = va_arg(ap, struct ppkeyword*))
457*da2e3ebdSchin 			for (; s = kp->name; kp++)
458*da2e3ebdSchin 		{
459*da2e3ebdSchin 			n = SYM_LEX;
460*da2e3ebdSchin 			switch (*s)
461*da2e3ebdSchin 			{
462*da2e3ebdSchin 			case '-':
463*da2e3ebdSchin 				s++;
464*da2e3ebdSchin 				break;
465*da2e3ebdSchin 			case '+':
466*da2e3ebdSchin 				s++;
467*da2e3ebdSchin 				if (!(pp.option & PLUSPLUS))
468*da2e3ebdSchin 					break;
469*da2e3ebdSchin 				/*FALLTHROUGH*/
470*da2e3ebdSchin 			default:
471*da2e3ebdSchin 				n |= SYM_KEYWORD;
472*da2e3ebdSchin 				break;
473*da2e3ebdSchin 			}
474*da2e3ebdSchin 			if (key = ppkeyset(pp.symtab, s))
475*da2e3ebdSchin 			{
476*da2e3ebdSchin 				key->sym.flags = n;
477*da2e3ebdSchin 				key->lex = kp->value;
478*da2e3ebdSchin 			}
479*da2e3ebdSchin 		}
480*da2e3ebdSchin 		break;
481*da2e3ebdSchin 	case PP_DEBUG:
482*da2e3ebdSchin 		error_info.trace = va_arg(ap, int);
483*da2e3ebdSchin 		break;
484*da2e3ebdSchin 	case PP_DEFAULT:
485*da2e3ebdSchin 		if (p = va_arg(ap, char*))
486*da2e3ebdSchin 			p = strdup(p);
487*da2e3ebdSchin 		if (pp.ppdefault)
488*da2e3ebdSchin 			free(pp.ppdefault);
489*da2e3ebdSchin 		pp.ppdefault = p;
490*da2e3ebdSchin 		break;
491*da2e3ebdSchin 	case PP_DONE:
492*da2e3ebdSchin #if CHECKPOINT
493*da2e3ebdSchin 		if (pp.mode & DUMP)
494*da2e3ebdSchin 			ppdump();
495*da2e3ebdSchin #endif
496*da2e3ebdSchin 		if (pp.mode & FILEDEPS)
497*da2e3ebdSchin 		{
498*da2e3ebdSchin 			sfputc(pp.filedeps.sp, '\n');
499*da2e3ebdSchin 			if (pp.filedeps.sp == sfstdout)
500*da2e3ebdSchin 				sfsync(pp.filedeps.sp);
501*da2e3ebdSchin 			else
502*da2e3ebdSchin 				sfclose(pp.filedeps.sp);
503*da2e3ebdSchin 		}
504*da2e3ebdSchin 		if (pp.state & STANDALONE)
505*da2e3ebdSchin 		{
506*da2e3ebdSchin 			if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
507*da2e3ebdSchin 				ppputchar('\n');
508*da2e3ebdSchin 			ppflushout();
509*da2e3ebdSchin 		}
510*da2e3ebdSchin 		error_info.file = 0;
511*da2e3ebdSchin 		break;
512*da2e3ebdSchin 	case PP_DUMP:
513*da2e3ebdSchin 		set(&pp.mode, DUMP, va_arg(ap, int));
514*da2e3ebdSchin #if !CHECKPOINT
515*da2e3ebdSchin 		if (pp.mode & DUMP)
516*da2e3ebdSchin 			error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
517*da2e3ebdSchin #endif
518*da2e3ebdSchin 		break;
519*da2e3ebdSchin 	case PP_FILEDEPS:
520*da2e3ebdSchin 		if (n = va_arg(ap, int))
521*da2e3ebdSchin 			pp.filedeps.flags |= n;
522*da2e3ebdSchin 		else
523*da2e3ebdSchin 			pp.filedeps.flags = 0;
524*da2e3ebdSchin 		break;
525*da2e3ebdSchin 	case PP_FILENAME:
526*da2e3ebdSchin 		error_info.file = va_arg(ap, char*);
527*da2e3ebdSchin 		break;
528*da2e3ebdSchin 	case PP_HOSTDIR:
529*da2e3ebdSchin 		if (!(pp.mode & INIT))
530*da2e3ebdSchin 			pp.ro_mode |= HOSTED;
531*da2e3ebdSchin 		else if (pp.ro_mode & HOSTED)
532*da2e3ebdSchin 			break;
533*da2e3ebdSchin 		pp.ro_mode |= INIT;
534*da2e3ebdSchin 		p = va_arg(ap, char*);
535*da2e3ebdSchin 		c = va_arg(ap, int);
536*da2e3ebdSchin 		pp.hostdir.path = 0;
537*da2e3ebdSchin 		if (!p)
538*da2e3ebdSchin 			pp.hosted = c;
539*da2e3ebdSchin 		else if (streq(p, "-"))
540*da2e3ebdSchin 		{
541*da2e3ebdSchin 			if (pp.initialized)
542*da2e3ebdSchin 				set(&pp.mode, HOSTED, c);
543*da2e3ebdSchin 			else
544*da2e3ebdSchin 			{
545*da2e3ebdSchin 				pp.hosted = c ? 1 : 2;
546*da2e3ebdSchin 				for (dp = pp.firstdir; dp; dp = dp->next)
547*da2e3ebdSchin 					if (pp.hosted == 1)
548*da2e3ebdSchin 						dp->type |= TYPE_HOSTED;
549*da2e3ebdSchin 					else
550*da2e3ebdSchin 						dp->type &= ~TYPE_HOSTED;
551*da2e3ebdSchin 			}
552*da2e3ebdSchin 		}
553*da2e3ebdSchin 		else if (!pp.hosted)
554*da2e3ebdSchin 		{
555*da2e3ebdSchin 			if (!*p || stat((pathcanon(p, 0), p), &st))
556*da2e3ebdSchin 				pp.hosted = 1;
557*da2e3ebdSchin 			else
558*da2e3ebdSchin 			{
559*da2e3ebdSchin 				for (dp = pp.firstdir; dp; dp = dp->next)
560*da2e3ebdSchin 				{
561*da2e3ebdSchin 					if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
562*da2e3ebdSchin 						pp.hosted = 1;
563*da2e3ebdSchin 					if (pp.hosted == 1)
564*da2e3ebdSchin 						dp->type |= TYPE_HOSTED;
565*da2e3ebdSchin 					else
566*da2e3ebdSchin 						dp->type &= ~TYPE_HOSTED;
567*da2e3ebdSchin 				}
568*da2e3ebdSchin 				if (!pp.hosted)
569*da2e3ebdSchin 				{
570*da2e3ebdSchin 					pp.hostdir.path = p;
571*da2e3ebdSchin 					SAVEID(&pp.hostdir.id, &st);
572*da2e3ebdSchin 				}
573*da2e3ebdSchin 			}
574*da2e3ebdSchin 		}
575*da2e3ebdSchin 		break;
576*da2e3ebdSchin 	case PP_ID:
577*da2e3ebdSchin 		p = va_arg(ap, char*);
578*da2e3ebdSchin 		c = va_arg(ap, int);
579*da2e3ebdSchin 		if (p)
580*da2e3ebdSchin 			ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
581*da2e3ebdSchin 		break;
582*da2e3ebdSchin 	case PP_IGNORE:
583*da2e3ebdSchin 		if (p = va_arg(ap, char*))
584*da2e3ebdSchin 		{
585*da2e3ebdSchin 			pathcanon(p, 0);
586*da2e3ebdSchin 			ppsetfile(p)->guard = INC_IGNORE;
587*da2e3ebdSchin 			message((-3, "%s: ignore", p));
588*da2e3ebdSchin 		}
589*da2e3ebdSchin 		break;
590*da2e3ebdSchin 	case PP_IGNORELIST:
591*da2e3ebdSchin 		if (pp.initialized)
592*da2e3ebdSchin 			goto before;
593*da2e3ebdSchin 		pp.ignore = va_arg(ap, char*);
594*da2e3ebdSchin 		break;
595*da2e3ebdSchin 	case PP_INCLUDE:
596*da2e3ebdSchin 		if ((p = va_arg(ap, char*)) && *p)
597*da2e3ebdSchin 		{
598*da2e3ebdSchin 			pathcanon(p, 0);
599*da2e3ebdSchin 			if (stat(p, &st))
600*da2e3ebdSchin 				break;
601*da2e3ebdSchin 			for (dp = pp.stddirs; dp = dp->next;)
602*da2e3ebdSchin 				if (dp->name && SAMEID(&dp->id, &st))
603*da2e3ebdSchin 					break;
604*da2e3ebdSchin 			if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
605*da2e3ebdSchin 			{
606*da2e3ebdSchin 				pp.cdir.path = 0;
607*da2e3ebdSchin 				pp.c = 1;
608*da2e3ebdSchin 			}
609*da2e3ebdSchin 			if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
610*da2e3ebdSchin 			{
611*da2e3ebdSchin 				pp.hostdir.path = 0;
612*da2e3ebdSchin 				pp.hosted = 1;
613*da2e3ebdSchin 			}
614*da2e3ebdSchin 			if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
615*da2e3ebdSchin 				pp.hosted = 1;
616*da2e3ebdSchin 			c = dp && dp->c || pp.c == 1;
617*da2e3ebdSchin 			n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
618*da2e3ebdSchin 			if (!dp || dp == pp.lastdir->next)
619*da2e3ebdSchin 			{
620*da2e3ebdSchin 				if (dp)
621*da2e3ebdSchin 				{
622*da2e3ebdSchin 					c = dp->c;
623*da2e3ebdSchin 					n = dp->type & TYPE_HOSTED;
624*da2e3ebdSchin 				}
625*da2e3ebdSchin 				dp = newof(0, struct ppdirs, 1, 0);
626*da2e3ebdSchin 				dp->name = p;
627*da2e3ebdSchin 				SAVEID(&dp->id, &st);
628*da2e3ebdSchin 				dp->type |= TYPE_INCLUDE;
629*da2e3ebdSchin 				dp->index = INC_LOCAL + pp.ignoresrc != 0;
630*da2e3ebdSchin 				dp->next = pp.lastdir->next;
631*da2e3ebdSchin 				pp.lastdir = pp.lastdir->next = dp;
632*da2e3ebdSchin 			}
633*da2e3ebdSchin 			dp->c = c;
634*da2e3ebdSchin 			if (n)
635*da2e3ebdSchin 				dp->type |= TYPE_HOSTED;
636*da2e3ebdSchin 			else
637*da2e3ebdSchin 				dp->type &= ~TYPE_HOSTED;
638*da2e3ebdSchin 		}
639*da2e3ebdSchin 		break;
640*da2e3ebdSchin 	case PP_INCREF:
641*da2e3ebdSchin 		pp.incref = va_arg(ap, PPINCREF);
642*da2e3ebdSchin 		break;
643*da2e3ebdSchin 	case PP_RESET:
644*da2e3ebdSchin 		pp.reset.on = 1;
645*da2e3ebdSchin 		break;
646*da2e3ebdSchin 	case PP_INIT:
647*da2e3ebdSchin 		if (pp.initialized)
648*da2e3ebdSchin 		{
649*da2e3ebdSchin 			error_info.errors = 0;
650*da2e3ebdSchin 			error_info.warnings = 0;
651*da2e3ebdSchin 		}
652*da2e3ebdSchin 		else
653*da2e3ebdSchin 		{
654*da2e3ebdSchin 			/*
655*da2e3ebdSchin 			 * context initialization
656*da2e3ebdSchin 			 */
657*da2e3ebdSchin 
658*da2e3ebdSchin 			if (!initialized)
659*da2e3ebdSchin 			{
660*da2e3ebdSchin 				/*
661*da2e3ebdSchin 				 * out of malloc is fatal
662*da2e3ebdSchin 				 */
663*da2e3ebdSchin 
664*da2e3ebdSchin 				memfatal();
665*da2e3ebdSchin 
666*da2e3ebdSchin 				/*
667*da2e3ebdSchin 				 * initialize the error message interface
668*da2e3ebdSchin 				 */
669*da2e3ebdSchin 
670*da2e3ebdSchin 				error_info.version = (char*)pp.version;
671*da2e3ebdSchin #if DEBUG & TRACE_debug
672*da2e3ebdSchin 				error_info.auxilliary = context;
673*da2e3ebdSchin 				pptrace(0);
674*da2e3ebdSchin #endif
675*da2e3ebdSchin 
676*da2e3ebdSchin 				/*
677*da2e3ebdSchin 				 * initialize pplex tables
678*da2e3ebdSchin 				 */
679*da2e3ebdSchin 
680*da2e3ebdSchin 				ppfsm(FSM_INIT, NiL);
681*da2e3ebdSchin 
682*da2e3ebdSchin 				/*
683*da2e3ebdSchin 				 * fixed macro stack size -- room for improvement
684*da2e3ebdSchin 				 */
685*da2e3ebdSchin 
686*da2e3ebdSchin 				pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
687*da2e3ebdSchin 				pp.macp->next = pp.macp + 1;
688*da2e3ebdSchin 				pp.maxmac = (char*)pp.macp + DEFMACSTACK;
689*da2e3ebdSchin 				initialized = 1;
690*da2e3ebdSchin 
691*da2e3ebdSchin 				/*
692*da2e3ebdSchin 				 * initial include/if control stack
693*da2e3ebdSchin 				 */
694*da2e3ebdSchin 
695*da2e3ebdSchin 				pp.control = newof(0, long, pp.constack, 0);
696*da2e3ebdSchin 				pp.maxcon = pp.control + pp.constack - 1;
697*da2e3ebdSchin 			}
698*da2e3ebdSchin 
699*da2e3ebdSchin 			/*
700*da2e3ebdSchin 			 * validate modes
701*da2e3ebdSchin 			 */
702*da2e3ebdSchin 
703*da2e3ebdSchin 			switch (pp.arg_mode)
704*da2e3ebdSchin 			{
705*da2e3ebdSchin 			case 'a':
706*da2e3ebdSchin 			case 'C':
707*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 0);
708*da2e3ebdSchin 				ppop(PP_TRANSITION, 1);
709*da2e3ebdSchin 				break;
710*da2e3ebdSchin 			case 'A':
711*da2e3ebdSchin 			case 'c':
712*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 0);
713*da2e3ebdSchin 				ppop(PP_STRICT, 1);
714*da2e3ebdSchin 				break;
715*da2e3ebdSchin 			case 'f':
716*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 1);
717*da2e3ebdSchin 				ppop(PP_PLUSPLUS, 1);
718*da2e3ebdSchin 				ppop(PP_TRANSITION, 1);
719*da2e3ebdSchin 				break;
720*da2e3ebdSchin 			case 'F':
721*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 0);
722*da2e3ebdSchin 				ppop(PP_PLUSPLUS, 1);
723*da2e3ebdSchin 				break;
724*da2e3ebdSchin 			case 'k':
725*da2e3ebdSchin 			case 's':
726*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 1);
727*da2e3ebdSchin 				ppop(PP_STRICT, 1);
728*da2e3ebdSchin 				break;
729*da2e3ebdSchin 			case 'o':
730*da2e3ebdSchin 			case 'O':
731*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 1);
732*da2e3ebdSchin 				ppop(PP_TRANSITION, 0);
733*da2e3ebdSchin 				break;
734*da2e3ebdSchin 			case 't':
735*da2e3ebdSchin 				ppop(PP_COMPATIBILITY, 1);
736*da2e3ebdSchin 				ppop(PP_TRANSITION, 1);
737*da2e3ebdSchin 				break;
738*da2e3ebdSchin 			}
739*da2e3ebdSchin 			if (!(pp.arg_style & STYLE_gnu))
740*da2e3ebdSchin 				ppop(PP_PEDANTIC, 1);
741*da2e3ebdSchin 			if (pp.state & PASSTHROUGH)
742*da2e3ebdSchin 			{
743*da2e3ebdSchin 				if (pp.state & COMPILE)
744*da2e3ebdSchin 				{
745*da2e3ebdSchin 					pp.state &= ~PASSTHROUGH;
746*da2e3ebdSchin 					error(1, "passthrough ignored for compile");
747*da2e3ebdSchin 				}
748*da2e3ebdSchin 				else
749*da2e3ebdSchin 				{
750*da2e3ebdSchin 					ppop(PP_COMPATIBILITY, 1);
751*da2e3ebdSchin 					ppop(PP_HOSTDIR, "-", 1);
752*da2e3ebdSchin 					ppop(PP_SPACEOUT, 1);
753*da2e3ebdSchin 					set(&pp.state, DISABLE, va_arg(ap, int));
754*da2e3ebdSchin 				}
755*da2e3ebdSchin 			}
756*da2e3ebdSchin 
757*da2e3ebdSchin 			/*
758*da2e3ebdSchin 			 * create the hash tables
759*da2e3ebdSchin 			 */
760*da2e3ebdSchin 
761*da2e3ebdSchin 			if (!pp.symtab)
762*da2e3ebdSchin 				pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
763*da2e3ebdSchin 			if (!pp.dirtab)
764*da2e3ebdSchin 			{
765*da2e3ebdSchin 				pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
766*da2e3ebdSchin 				inithash(pp.dirtab, directives);
767*da2e3ebdSchin 			}
768*da2e3ebdSchin 			if (!pp.filtab)
769*da2e3ebdSchin 				pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
770*da2e3ebdSchin 			if (!pp.prdtab)
771*da2e3ebdSchin 				pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
772*da2e3ebdSchin 			if (!pp.strtab)
773*da2e3ebdSchin 			{
774*da2e3ebdSchin 				pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
775*da2e3ebdSchin 				inithash(pp.strtab, options);
776*da2e3ebdSchin 				inithash(pp.strtab, predicates);
777*da2e3ebdSchin 				inithash(pp.strtab, variables);
778*da2e3ebdSchin 			}
779*da2e3ebdSchin 			pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
780*da2e3ebdSchin 			pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
781*da2e3ebdSchin 
782*da2e3ebdSchin 			/*
783*da2e3ebdSchin 			 * mark macros that are builtin predicates
784*da2e3ebdSchin 			 */
785*da2e3ebdSchin 
786*da2e3ebdSchin 			for (kp = predicates; s = kp->name; kp++)
787*da2e3ebdSchin 			{
788*da2e3ebdSchin 				if (!ppisid(*s))
789*da2e3ebdSchin 					s++;
790*da2e3ebdSchin 				ppassert(DEFINE, s, 0);
791*da2e3ebdSchin 			}
792*da2e3ebdSchin 
793*da2e3ebdSchin 			/*
794*da2e3ebdSchin 			 * the remaining entry names must be allocated
795*da2e3ebdSchin 			 */
796*da2e3ebdSchin 
797*da2e3ebdSchin 			hashset(pp.dirtab, HASH_ALLOCATE);
798*da2e3ebdSchin 			hashset(pp.filtab, HASH_ALLOCATE);
799*da2e3ebdSchin 			hashset(pp.prdtab, HASH_ALLOCATE);
800*da2e3ebdSchin 			hashset(pp.strtab, HASH_ALLOCATE);
801*da2e3ebdSchin 			hashset(pp.symtab, HASH_ALLOCATE);
802*da2e3ebdSchin 			if (pp.test & TEST_nonoise)
803*da2e3ebdSchin 			{
804*da2e3ebdSchin 				c = error_info.trace;
805*da2e3ebdSchin 				error_info.trace = 0;
806*da2e3ebdSchin 			}
807*da2e3ebdSchin #if DEBUG
808*da2e3ebdSchin 			if (!(pp.test & TEST_noinit))
809*da2e3ebdSchin 			{
810*da2e3ebdSchin #endif
811*da2e3ebdSchin 
812*da2e3ebdSchin 			/*
813*da2e3ebdSchin 			 * compose, push and read the builtin initialization script
814*da2e3ebdSchin 			 */
815*da2e3ebdSchin 
816*da2e3ebdSchin 			if (!(sp = sfstropen()))
817*da2e3ebdSchin 				error(3, "temporary buffer allocation error");
818*da2e3ebdSchin 			sfprintf(sp,
819*da2e3ebdSchin "\
820*da2e3ebdSchin #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
821*da2e3ebdSchin #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
822*da2e3ebdSchin ",
823*da2e3ebdSchin 				dirname(PRAGMA),
824*da2e3ebdSchin 				pp.pass,
825*da2e3ebdSchin 				keyname(X_MAP),
826*da2e3ebdSchin 				dirname(DEFINE),
827*da2e3ebdSchin 				dirname(PRAGMA),
828*da2e3ebdSchin 				pp.pass,
829*da2e3ebdSchin 				keyname(X_MAP),
830*da2e3ebdSchin 				dirname(UNDEF));
831*da2e3ebdSchin 			if (pp.ppdefault && *pp.ppdefault)
832*da2e3ebdSchin 			{
833*da2e3ebdSchin 				if (pp.probe)
834*da2e3ebdSchin 				{
835*da2e3ebdSchin 					c = pp.lastdir->next->type;
836*da2e3ebdSchin 					pp.lastdir->next->type = 0;
837*da2e3ebdSchin 				}
838*da2e3ebdSchin 				if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
839*da2e3ebdSchin 				{
840*da2e3ebdSchin 					free(pp.ppdefault);
841*da2e3ebdSchin 					if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0)))
842*da2e3ebdSchin 						error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
843*da2e3ebdSchin 				}
844*da2e3ebdSchin 				if (pp.ppdefault)
845*da2e3ebdSchin 					sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
846*da2e3ebdSchin 				if (pp.probe)
847*da2e3ebdSchin 					pp.lastdir->next->type = c;
848*da2e3ebdSchin 			}
849*da2e3ebdSchin 			while (pp.firstop)
850*da2e3ebdSchin 			{
851*da2e3ebdSchin 				switch (pp.firstop->op)
852*da2e3ebdSchin 				{
853*da2e3ebdSchin 				case PP_ASSERT:
854*da2e3ebdSchin 					sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
855*da2e3ebdSchin 					break;
856*da2e3ebdSchin 				case PP_DEFINE:
857*da2e3ebdSchin 					if (*pp.firstop->value == '#')
858*da2e3ebdSchin 						sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
859*da2e3ebdSchin 					else
860*da2e3ebdSchin 					{
861*da2e3ebdSchin 						if (s = strchr(pp.firstop->value, '='))
862*da2e3ebdSchin 							sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
863*da2e3ebdSchin 						else
864*da2e3ebdSchin 							sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
865*da2e3ebdSchin 					}
866*da2e3ebdSchin 					break;
867*da2e3ebdSchin 				case PP_DIRECTIVE:
868*da2e3ebdSchin 					sfprintf(sp, "#%s\n", pp.firstop->value);
869*da2e3ebdSchin 					break;
870*da2e3ebdSchin 				case PP_OPTION:
871*da2e3ebdSchin 					if (s = strchr(pp.firstop->value, '='))
872*da2e3ebdSchin 						sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
873*da2e3ebdSchin 					else
874*da2e3ebdSchin 						sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
875*da2e3ebdSchin 					break;
876*da2e3ebdSchin 				case PP_READ:
877*da2e3ebdSchin 					sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
878*da2e3ebdSchin 					break;
879*da2e3ebdSchin 				case PP_UNDEF:
880*da2e3ebdSchin 					sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
881*da2e3ebdSchin 					break;
882*da2e3ebdSchin 				}
883*da2e3ebdSchin 				pp.lastop = pp.firstop;
884*da2e3ebdSchin 				pp.firstop = pp.firstop->next;
885*da2e3ebdSchin 				free(pp.lastop);
886*da2e3ebdSchin 			}
887*da2e3ebdSchin 			sfprintf(sp,
888*da2e3ebdSchin "\
889*da2e3ebdSchin #%s %s:%s\n\
890*da2e3ebdSchin #%s %s:%s\n\
891*da2e3ebdSchin #%s !#%s(%s)\n\
892*da2e3ebdSchin #%s !#%s(%s) || #%s(%s)\n\
893*da2e3ebdSchin "
894*da2e3ebdSchin 				, dirname(PRAGMA)
895*da2e3ebdSchin 				, pp.pass
896*da2e3ebdSchin 				, keyname(X_BUILTIN)
897*da2e3ebdSchin 				, dirname(PRAGMA)
898*da2e3ebdSchin 				, pp.pass
899*da2e3ebdSchin 				, keyname(X_PREDEFINED)
900*da2e3ebdSchin 				, dirname(IF)
901*da2e3ebdSchin 				, keyname(X_OPTION)
902*da2e3ebdSchin 				, keyname(X_PLUSPLUS)
903*da2e3ebdSchin 				, dirname(IF)
904*da2e3ebdSchin 				, keyname(X_OPTION)
905*da2e3ebdSchin 				, keyname(X_COMPATIBILITY)
906*da2e3ebdSchin 				, keyname(X_OPTION)
907*da2e3ebdSchin 				, keyname(X_TRANSITION)
908*da2e3ebdSchin 				);
909*da2e3ebdSchin 			sfprintf(sp,
910*da2e3ebdSchin "\
911*da2e3ebdSchin #%s __STDC__\n\
912*da2e3ebdSchin #%s __STDC__ #(STDC)\n\
913*da2e3ebdSchin #%s\n\
914*da2e3ebdSchin #%s #%s(%s)\n\
915*da2e3ebdSchin #%s %s:%s\n\
916*da2e3ebdSchin #%s %s:%s\n\
917*da2e3ebdSchin #%s __STRICT__ 1\n\
918*da2e3ebdSchin #%s\n\
919*da2e3ebdSchin #%s\n\
920*da2e3ebdSchin "
921*da2e3ebdSchin 				, dirname(IFNDEF)
922*da2e3ebdSchin 				, dirname(DEFINE)
923*da2e3ebdSchin 				, dirname(ENDIF)
924*da2e3ebdSchin 				, dirname(IF)
925*da2e3ebdSchin 				, keyname(X_OPTION)
926*da2e3ebdSchin 				, keyname(X_STRICT)
927*da2e3ebdSchin 				, dirname(PRAGMA)
928*da2e3ebdSchin 				, pp.pass
929*da2e3ebdSchin 				, keyname(X_ALLMULTIPLE)
930*da2e3ebdSchin 				, dirname(PRAGMA)
931*da2e3ebdSchin 				, pp.pass
932*da2e3ebdSchin 				, keyname(X_READONLY)
933*da2e3ebdSchin 				, dirname(DEFINE)
934*da2e3ebdSchin 				, dirname(ENDIF)
935*da2e3ebdSchin 				, dirname(ENDIF)
936*da2e3ebdSchin 				);
937*da2e3ebdSchin 			for (kp = readonlys; s = kp->name; kp++)
938*da2e3ebdSchin 			{
939*da2e3ebdSchin 				if (!ppisid(*s))
940*da2e3ebdSchin 					s++;
941*da2e3ebdSchin 				sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
942*da2e3ebdSchin 			}
943*da2e3ebdSchin 			sfprintf(sp,
944*da2e3ebdSchin "\
945*da2e3ebdSchin #%s\n\
946*da2e3ebdSchin #%s __STDPP__ 1\n\
947*da2e3ebdSchin #%s %s:no%s\n\
948*da2e3ebdSchin "
949*da2e3ebdSchin 				, dirname(ENDIF)
950*da2e3ebdSchin 				, dirname(DEFINE)
951*da2e3ebdSchin 				, dirname(PRAGMA)
952*da2e3ebdSchin 				, pp.pass
953*da2e3ebdSchin 				, keyname(X_PREDEFINED)
954*da2e3ebdSchin 				);
955*da2e3ebdSchin 			if (!pp.truncate)
956*da2e3ebdSchin 				sfprintf(sp,
957*da2e3ebdSchin "\
958*da2e3ebdSchin #%s __STDPP__directive #(%s)\n\
959*da2e3ebdSchin "
960*da2e3ebdSchin 				, dirname(DEFINE)
961*da2e3ebdSchin 				, keyname(V_DIRECTIVE)
962*da2e3ebdSchin 				);
963*da2e3ebdSchin 			for (kp = variables; s = kp->name; kp++)
964*da2e3ebdSchin 				if (ppisid(*s) || *s++ == '+')
965*da2e3ebdSchin 				{
966*da2e3ebdSchin 					t = *s == '_' ? "" : "__";
967*da2e3ebdSchin 					sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
968*da2e3ebdSchin 				}
969*da2e3ebdSchin 			sfprintf(sp,
970*da2e3ebdSchin "\
971*da2e3ebdSchin #%s %s:no%s\n\
972*da2e3ebdSchin #%s %s:no%s\n\
973*da2e3ebdSchin "
974*da2e3ebdSchin 				, dirname(PRAGMA)
975*da2e3ebdSchin 				, pp.pass
976*da2e3ebdSchin 				, keyname(X_READONLY)
977*da2e3ebdSchin 				, dirname(PRAGMA)
978*da2e3ebdSchin 				, pp.pass
979*da2e3ebdSchin 				, keyname(X_BUILTIN)
980*da2e3ebdSchin 				);
981*da2e3ebdSchin 			t = sfstruse(sp);
982*da2e3ebdSchin 			debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
983*da2e3ebdSchin 			ppcomment = pp.comment;
984*da2e3ebdSchin 			pp.comment = 0;
985*da2e3ebdSchin 			pplinesync = pp.linesync;
986*da2e3ebdSchin 			pp.linesync = 0;
987*da2e3ebdSchin 			PUSH_INIT(pp.pass, t);
988*da2e3ebdSchin 			pp.mode |= INIT;
989*da2e3ebdSchin 			while (pplex());
990*da2e3ebdSchin 			pp.mode &= ~INIT;
991*da2e3ebdSchin 			pp.comment = ppcomment;
992*da2e3ebdSchin 			pp.linesync = pplinesync;
993*da2e3ebdSchin 			pp.prefix = 0;
994*da2e3ebdSchin 			sfstrclose(sp);
995*da2e3ebdSchin 			if (error_info.trace)
996*da2e3ebdSchin 				for (dp = pp.firstdir; dp; dp = dp->next)
997*da2e3ebdSchin 					message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
998*da2e3ebdSchin #if DEBUG
999*da2e3ebdSchin 			}
1000*da2e3ebdSchin 			if (pp.test & TEST_nonoise)
1001*da2e3ebdSchin 				error_info.trace = c;
1002*da2e3ebdSchin #endif
1003*da2e3ebdSchin 			{
1004*da2e3ebdSchin 				/*
1005*da2e3ebdSchin 				 * this is sleazy but at least it's
1006*da2e3ebdSchin 				 * hidden in the library
1007*da2e3ebdSchin 				 */
1008*da2e3ebdSchin #include <preroot.h>
1009*da2e3ebdSchin #if FS_PREROOT
1010*da2e3ebdSchin 				struct pplist*	preroot;
1011*da2e3ebdSchin 
1012*da2e3ebdSchin 				if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
1013*da2e3ebdSchin 					setpreroot(NiL, preroot->value);
1014*da2e3ebdSchin #endif
1015*da2e3ebdSchin 			}
1016*da2e3ebdSchin 			if (pp.ignoresrc)
1017*da2e3ebdSchin 			{
1018*da2e3ebdSchin 				if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
1019*da2e3ebdSchin 					error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
1020*da2e3ebdSchin 				pp.lcldirs = pp.lcldirs->next;
1021*da2e3ebdSchin 			}
1022*da2e3ebdSchin 			if (pp.ignore)
1023*da2e3ebdSchin 			{
1024*da2e3ebdSchin 				if (*pp.ignore)
1025*da2e3ebdSchin 					ppmapinclude(pp.ignore, NiL);
1026*da2e3ebdSchin 				else
1027*da2e3ebdSchin 					pp.ignore = 0;
1028*da2e3ebdSchin 			}
1029*da2e3ebdSchin 			if (pp.standalone)
1030*da2e3ebdSchin 				pp.state |= STANDALONE;
1031*da2e3ebdSchin #if COMPATIBLE
1032*da2e3ebdSchin 			ppfsm(FSM_COMPATIBILITY, NiL);
1033*da2e3ebdSchin #endif
1034*da2e3ebdSchin 			ppfsm(FSM_PLUSPLUS, NiL);
1035*da2e3ebdSchin 			pp.initialized = 1;
1036*da2e3ebdSchin 			if (pp.reset.on)
1037*da2e3ebdSchin 			{
1038*da2e3ebdSchin 				pp.reset.symtab = pp.symtab;
1039*da2e3ebdSchin 				pp.symtab = 0;
1040*da2e3ebdSchin 				pp.reset.ro_state = pp.ro_state;
1041*da2e3ebdSchin 				pp.reset.ro_mode = pp.ro_mode;
1042*da2e3ebdSchin 				pp.reset.ro_option = pp.ro_option;
1043*da2e3ebdSchin 			}
1044*da2e3ebdSchin 		}
1045*da2e3ebdSchin 		if (pp.reset.on)
1046*da2e3ebdSchin 		{
1047*da2e3ebdSchin 			if (pp.symtab)
1048*da2e3ebdSchin 			{
1049*da2e3ebdSchin 				hashwalk(pp.filtab, 0, unguard, NiL);
1050*da2e3ebdSchin 				hashfree(pp.symtab);
1051*da2e3ebdSchin 			}
1052*da2e3ebdSchin 			pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
1053*da2e3ebdSchin 			hashview(pp.symtab, pp.reset.symtab);
1054*da2e3ebdSchin 			pp.ro_state = pp.reset.ro_state;
1055*da2e3ebdSchin 			pp.ro_mode = pp.reset.ro_mode;
1056*da2e3ebdSchin 			pp.ro_option = pp.reset.ro_option;
1057*da2e3ebdSchin 		}
1058*da2e3ebdSchin #if CHECKPOINT
1059*da2e3ebdSchin 		if (pp.mode & DUMP)
1060*da2e3ebdSchin 		{
1061*da2e3ebdSchin 			if (!pp.pragma)
1062*da2e3ebdSchin 				error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
1063*da2e3ebdSchin 			(*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
1064*da2e3ebdSchin 		}
1065*da2e3ebdSchin #endif
1066*da2e3ebdSchin 		if (n = pp.filedeps.flags)
1067*da2e3ebdSchin 		{
1068*da2e3ebdSchin 			if (!(n & PP_deps_file))
1069*da2e3ebdSchin 			{
1070*da2e3ebdSchin 				pp.state |= NOTEXT;
1071*da2e3ebdSchin 				pp.option |= KEEPNOTEXT;
1072*da2e3ebdSchin 				pp.linesync = 0;
1073*da2e3ebdSchin 			}
1074*da2e3ebdSchin 			if (n & PP_deps_generated)
1075*da2e3ebdSchin 				pp.mode |= GENDEPS;
1076*da2e3ebdSchin 			if (n & PP_deps_local)
1077*da2e3ebdSchin 				pp.mode &= ~HEADERDEPS;
1078*da2e3ebdSchin 			else if (!(pp.mode & FILEDEPS))
1079*da2e3ebdSchin 				pp.mode |= HEADERDEPS;
1080*da2e3ebdSchin 			pp.mode |= FILEDEPS;
1081*da2e3ebdSchin 		}
1082*da2e3ebdSchin 
1083*da2e3ebdSchin 		/*
1084*da2e3ebdSchin 		 * push the main input file -- special case for hosted mark
1085*da2e3ebdSchin 		 */
1086*da2e3ebdSchin 
1087*da2e3ebdSchin 		if (pp.firstdir->type & TYPE_HOSTED)
1088*da2e3ebdSchin 			pp.mode |= MARKHOSTED;
1089*da2e3ebdSchin 		else
1090*da2e3ebdSchin 			pp.mode &= ~MARKHOSTED;
1091*da2e3ebdSchin #if CHECKPOINT
1092*da2e3ebdSchin 		if (!(pp.mode & DUMP))
1093*da2e3ebdSchin #endif
1094*da2e3ebdSchin 		{
1095*da2e3ebdSchin 			if (!(p = error_info.file))
1096*da2e3ebdSchin 				p = "";
1097*da2e3ebdSchin 			else
1098*da2e3ebdSchin 			{
1099*da2e3ebdSchin 				error_info.file = 0;
1100*da2e3ebdSchin 				if (*p)
1101*da2e3ebdSchin 				{
1102*da2e3ebdSchin 					pathcanon(p, 0);
1103*da2e3ebdSchin 					p = ppsetfile(p)->name;
1104*da2e3ebdSchin 				}
1105*da2e3ebdSchin 			}
1106*da2e3ebdSchin 			PUSH_FILE(p, 0);
1107*da2e3ebdSchin 		}
1108*da2e3ebdSchin 		if (pp.mode & FILEDEPS)
1109*da2e3ebdSchin 		{
1110*da2e3ebdSchin 			if (s = strrchr(error_info.file, '/'))
1111*da2e3ebdSchin 				s++;
1112*da2e3ebdSchin 			else
1113*da2e3ebdSchin 				s = error_info.file;
1114*da2e3ebdSchin 			if (!*s)
1115*da2e3ebdSchin 				s = "-";
1116*da2e3ebdSchin 			s = strcpy(pp.tmpbuf, s);
1117*da2e3ebdSchin 			if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
1118*da2e3ebdSchin 			{
1119*da2e3ebdSchin 				if (c = *++p)
1120*da2e3ebdSchin 					while (*++p == c);
1121*da2e3ebdSchin 				if (*p)
1122*da2e3ebdSchin 					t = 0;
1123*da2e3ebdSchin 				else
1124*da2e3ebdSchin 					t++;
1125*da2e3ebdSchin 			}
1126*da2e3ebdSchin 			if (!t)
1127*da2e3ebdSchin 			{
1128*da2e3ebdSchin 				t = s + strlen(s);
1129*da2e3ebdSchin 				*t++ = '.';
1130*da2e3ebdSchin 			}
1131*da2e3ebdSchin 			*(t + 1) = 0;
1132*da2e3ebdSchin 			if (pp.state & NOTEXT)
1133*da2e3ebdSchin 				pp.filedeps.sp = sfstdout;
1134*da2e3ebdSchin 			else
1135*da2e3ebdSchin 			{
1136*da2e3ebdSchin 				*t = 'd';
1137*da2e3ebdSchin 				if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
1138*da2e3ebdSchin 					error(ERROR_SYSTEM|3, "%s: cannot create", s);
1139*da2e3ebdSchin 			}
1140*da2e3ebdSchin 			*t = 'o';
1141*da2e3ebdSchin 			pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
1142*da2e3ebdSchin 			if (*error_info.file)
1143*da2e3ebdSchin 				pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
1144*da2e3ebdSchin 		}
1145*da2e3ebdSchin 		if (xp = pp.firsttx)
1146*da2e3ebdSchin 		{
1147*da2e3ebdSchin 			if (!(sp = sfstropen()))
1148*da2e3ebdSchin 				error(3, "temporary buffer allocation error");
1149*da2e3ebdSchin 			while (xp)
1150*da2e3ebdSchin 			{
1151*da2e3ebdSchin 				sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
1152*da2e3ebdSchin 				xp = xp->next;
1153*da2e3ebdSchin 			}
1154*da2e3ebdSchin 			t = sfstruse(sp);
1155*da2e3ebdSchin 			PUSH_BUFFER("options", t, 1);
1156*da2e3ebdSchin 			sfstrclose(sp);
1157*da2e3ebdSchin 		}
1158*da2e3ebdSchin 		break;
1159*da2e3ebdSchin 	case PP_INPUT:
1160*da2e3ebdSchin #if CHECKPOINT && POOL
1161*da2e3ebdSchin 		if (!(pp.mode & DUMP) || pp.pool.input)
1162*da2e3ebdSchin #else
1163*da2e3ebdSchin #if CHECKPOINT
1164*da2e3ebdSchin 		if (!(pp.mode & DUMP))
1165*da2e3ebdSchin #else
1166*da2e3ebdSchin #if POOL
1167*da2e3ebdSchin 		if (pp.pool.input)
1168*da2e3ebdSchin #endif
1169*da2e3ebdSchin #endif
1170*da2e3ebdSchin #endif
1171*da2e3ebdSchin 		{
1172*da2e3ebdSchin 			p = va_arg(ap, char*);
1173*da2e3ebdSchin 			if (!error_info.file)
1174*da2e3ebdSchin 				error_info.file = p;
1175*da2e3ebdSchin 			close(0);
1176*da2e3ebdSchin 			if (open(p, O_RDONLY) != 0)
1177*da2e3ebdSchin 				error(ERROR_SYSTEM|3, "%s: cannot read", p);
1178*da2e3ebdSchin 			if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
1179*da2e3ebdSchin 			{
1180*da2e3ebdSchin 				set(&pp.mode, CATLITERAL, 0);
1181*da2e3ebdSchin 				ppop(PP_SPACEOUT, 1);
1182*da2e3ebdSchin 			}
1183*da2e3ebdSchin 			break;
1184*da2e3ebdSchin 		}
1185*da2e3ebdSchin 		/*FALLTHROUGH*/
1186*da2e3ebdSchin 	case PP_TEXT:
1187*da2e3ebdSchin 		if (pp.initialized)
1188*da2e3ebdSchin 			goto before;
1189*da2e3ebdSchin 		if ((p = va_arg(ap, char*)) && *p)
1190*da2e3ebdSchin 		{
1191*da2e3ebdSchin 			if (pp.lasttx)
1192*da2e3ebdSchin 				pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
1193*da2e3ebdSchin 			else
1194*da2e3ebdSchin 				pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
1195*da2e3ebdSchin 			pp.lasttx->op = op;
1196*da2e3ebdSchin 			pp.lasttx->value = p;
1197*da2e3ebdSchin 		}
1198*da2e3ebdSchin 		break;
1199*da2e3ebdSchin 	case PP_KEYARGS:
1200*da2e3ebdSchin 		if (pp.initialized)
1201*da2e3ebdSchin 			goto before;
1202*da2e3ebdSchin 		set(&pp.option, KEYARGS, va_arg(ap, int));
1203*da2e3ebdSchin 		if (pp.option & KEYARGS)
1204*da2e3ebdSchin #if MACKEYARGS
1205*da2e3ebdSchin 			set(&pp.mode, CATLITERAL, 1);
1206*da2e3ebdSchin #else
1207*da2e3ebdSchin 			error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1208*da2e3ebdSchin #endif
1209*da2e3ebdSchin 		break;
1210*da2e3ebdSchin 	case PP_LINE:
1211*da2e3ebdSchin 		pp.linesync = va_arg(ap, PPLINESYNC);
1212*da2e3ebdSchin 		break;
1213*da2e3ebdSchin 	case PP_LINEBASE:
1214*da2e3ebdSchin 		if (va_arg(ap, int))
1215*da2e3ebdSchin 			pp.flags |= PP_linebase;
1216*da2e3ebdSchin 		else
1217*da2e3ebdSchin 			pp.flags &= ~PP_linebase;
1218*da2e3ebdSchin 		break;
1219*da2e3ebdSchin 	case PP_LINEFILE:
1220*da2e3ebdSchin 		if (va_arg(ap, int))
1221*da2e3ebdSchin 			pp.flags |= PP_linefile;
1222*da2e3ebdSchin 		else
1223*da2e3ebdSchin 			pp.flags &= ~PP_linefile;
1224*da2e3ebdSchin 		break;
1225*da2e3ebdSchin 	case PP_LINEID:
1226*da2e3ebdSchin 		if (!(p = va_arg(ap, char*)))
1227*da2e3ebdSchin 			pp.lineid = "";
1228*da2e3ebdSchin 		else if (*p != '-')
1229*da2e3ebdSchin 			pp.lineid = strdup(p);
1230*da2e3ebdSchin 		else
1231*da2e3ebdSchin 			pp.option |= IGNORELINE;
1232*da2e3ebdSchin 		break;
1233*da2e3ebdSchin 	case PP_LINETYPE:
1234*da2e3ebdSchin 		if ((n = va_arg(ap, int)) >= 1)
1235*da2e3ebdSchin 			pp.flags |= PP_linetype;
1236*da2e3ebdSchin 		else
1237*da2e3ebdSchin 			pp.flags &= ~PP_linetype;
1238*da2e3ebdSchin 		if (n >= 2)
1239*da2e3ebdSchin 			pp.flags |= PP_linehosted;
1240*da2e3ebdSchin 		else
1241*da2e3ebdSchin 			pp.flags &= ~PP_linehosted;
1242*da2e3ebdSchin 		break;
1243*da2e3ebdSchin 	case PP_LOCAL:
1244*da2e3ebdSchin 		if (pp.initialized)
1245*da2e3ebdSchin 			goto before;
1246*da2e3ebdSchin 		pp.ignoresrc++;
1247*da2e3ebdSchin 		pp.stddirs = pp.lastdir;
1248*da2e3ebdSchin 		if (!(pp.ro_option & PREFIX))
1249*da2e3ebdSchin 			pp.option &= ~PREFIX;
1250*da2e3ebdSchin 		break;
1251*da2e3ebdSchin 	case PP_MACREF:
1252*da2e3ebdSchin 		pp.macref = va_arg(ap, PPMACREF);
1253*da2e3ebdSchin 		break;
1254*da2e3ebdSchin 	case PP_MULTIPLE:
1255*da2e3ebdSchin 		set(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
1256*da2e3ebdSchin 		break;
1257*da2e3ebdSchin 	case PP_NOHASH:
1258*da2e3ebdSchin 		set(&pp.option, NOHASH, va_arg(ap, int));
1259*da2e3ebdSchin 		break;
1260*da2e3ebdSchin 	case PP_NOISE:
1261*da2e3ebdSchin 		op = va_arg(ap, int);
1262*da2e3ebdSchin 		set(&pp.option, NOISE, op);
1263*da2e3ebdSchin 		set(&pp.option, NOISEFILTER, op < 0);
1264*da2e3ebdSchin 		break;
1265*da2e3ebdSchin 	case PP_OPTARG:
1266*da2e3ebdSchin 		pp.optarg = va_arg(ap, PPOPTARG);
1267*da2e3ebdSchin 		break;
1268*da2e3ebdSchin 	case PP_OUTPUT:
1269*da2e3ebdSchin 		pp.outfile = va_arg(ap, char*);
1270*da2e3ebdSchin 		if (identical(pp.outfile, 0))
1271*da2e3ebdSchin 			error(3, "%s: identical to input", pp.outfile);
1272*da2e3ebdSchin 		close(1);
1273*da2e3ebdSchin 		if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
1274*da2e3ebdSchin 			error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
1275*da2e3ebdSchin 		break;
1276*da2e3ebdSchin 	case PP_PASSTHROUGH:
1277*da2e3ebdSchin 		if (!(pp.state & COMPILE))
1278*da2e3ebdSchin 			set(&pp.state, PASSTHROUGH, va_arg(ap, int));
1279*da2e3ebdSchin 		break;
1280*da2e3ebdSchin 	case PP_PEDANTIC:
1281*da2e3ebdSchin 		set(&pp.mode, PEDANTIC, va_arg(ap, int));
1282*da2e3ebdSchin 		break;
1283*da2e3ebdSchin 	case PP_PLUSCOMMENT:
1284*da2e3ebdSchin 		set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
1285*da2e3ebdSchin 		if (pp.initialized)
1286*da2e3ebdSchin 			ppfsm(FSM_PLUSPLUS, NiL);
1287*da2e3ebdSchin 		break;
1288*da2e3ebdSchin 	case PP_PLUSPLUS:
1289*da2e3ebdSchin 		set(&pp.option, PLUSPLUS, va_arg(ap, int));
1290*da2e3ebdSchin 		set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
1291*da2e3ebdSchin 		if (pp.initialized)
1292*da2e3ebdSchin 			ppfsm(FSM_PLUSPLUS, NiL);
1293*da2e3ebdSchin 		break;
1294*da2e3ebdSchin 	case PP_POOL:
1295*da2e3ebdSchin 		if (pp.initialized)
1296*da2e3ebdSchin 			goto before;
1297*da2e3ebdSchin 		if (va_arg(ap, int))
1298*da2e3ebdSchin 		{
1299*da2e3ebdSchin #if POOL
1300*da2e3ebdSchin 			pp.pool.input = dup(0);
1301*da2e3ebdSchin 			pp.pool.output = dup(1);
1302*da2e3ebdSchin 			p = "/dev/null";
1303*da2e3ebdSchin 			if (!identical(p, 0))
1304*da2e3ebdSchin 			{
1305*da2e3ebdSchin 				if (!identical(p, 1))
1306*da2e3ebdSchin 					ppop(PP_OUTPUT, p);
1307*da2e3ebdSchin 				ppop(PP_INPUT, p);
1308*da2e3ebdSchin 			}
1309*da2e3ebdSchin #else
1310*da2e3ebdSchin 			error(3, "preprocessor not compiled with input pool enabled [POOL]");
1311*da2e3ebdSchin #endif
1312*da2e3ebdSchin 		}
1313*da2e3ebdSchin 		break;
1314*da2e3ebdSchin 	case PP_PRAGMA:
1315*da2e3ebdSchin 		pp.pragma = va_arg(ap, PPPRAGMA);
1316*da2e3ebdSchin 		break;
1317*da2e3ebdSchin 	case PP_PRAGMAFLAGS:
1318*da2e3ebdSchin 		if (p = va_arg(ap, char*))
1319*da2e3ebdSchin 		{
1320*da2e3ebdSchin 			n = OPT_GLOBAL;
1321*da2e3ebdSchin 			if (*p == '-')
1322*da2e3ebdSchin 				p++;
1323*da2e3ebdSchin 			else
1324*da2e3ebdSchin 				n |= OPT_PASS;
1325*da2e3ebdSchin 			if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
1326*da2e3ebdSchin 				pp.optflags[c] = n;
1327*da2e3ebdSchin 		}
1328*da2e3ebdSchin 		break;
1329*da2e3ebdSchin 	case PP_PROBE:
1330*da2e3ebdSchin 		pp.probe = va_arg(ap, char*);
1331*da2e3ebdSchin 		break;
1332*da2e3ebdSchin 	case PP_QUOTE:
1333*da2e3ebdSchin 		p = va_arg(ap, char*);
1334*da2e3ebdSchin 		c = va_arg(ap, int);
1335*da2e3ebdSchin 		if (p)
1336*da2e3ebdSchin 			ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
1337*da2e3ebdSchin 		break;
1338*da2e3ebdSchin 	case PP_REGUARD:
1339*da2e3ebdSchin 		set(&pp.option, REGUARD, va_arg(ap, int));
1340*da2e3ebdSchin 		break;
1341*da2e3ebdSchin 	case PP_RESERVED:
1342*da2e3ebdSchin 		if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
1343*da2e3ebdSchin 		{
1344*da2e3ebdSchin 			if (!(sp = sfstropen()))
1345*da2e3ebdSchin 				error(3, "temporary buffer allocation error");
1346*da2e3ebdSchin 			sfputr(sp, p, -1);
1347*da2e3ebdSchin 			p = sfstruse(sp);
1348*da2e3ebdSchin 			if (s = strchr(p, '='))
1349*da2e3ebdSchin 				*s++ = 0;
1350*da2e3ebdSchin 			else
1351*da2e3ebdSchin 				s = p;
1352*da2e3ebdSchin 			while (*s == '_')
1353*da2e3ebdSchin 				s++;
1354*da2e3ebdSchin 			for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
1355*da2e3ebdSchin 			if (*t == '_')
1356*da2e3ebdSchin 				*t = 0;
1357*da2e3ebdSchin 			else
1358*da2e3ebdSchin 				t = 0;
1359*da2e3ebdSchin 			op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
1360*da2e3ebdSchin 			if (pp.test & 0x0400)
1361*da2e3ebdSchin 				error(1, "reserved#1 `%s' %d", s, op);
1362*da2e3ebdSchin 			if (t)
1363*da2e3ebdSchin 				*t = '_';
1364*da2e3ebdSchin 			if (!(key = ppkeyget(pp.symtab, p)))
1365*da2e3ebdSchin 				key = ppkeyset(pp.symtab, NiL);
1366*da2e3ebdSchin 			else if (!(key->sym.flags & SYM_LEX))
1367*da2e3ebdSchin 			{
1368*da2e3ebdSchin 				struct ppsymbol	tmp;
1369*da2e3ebdSchin 
1370*da2e3ebdSchin 				tmp = key->sym;
1371*da2e3ebdSchin 				hashlook(pp.symtab, p, HASH_DELETE, NiL);
1372*da2e3ebdSchin 				key = ppkeyset(pp.symtab, NiL);
1373*da2e3ebdSchin 				key->sym.flags = tmp.flags;
1374*da2e3ebdSchin 				key->sym.macro = tmp.macro;
1375*da2e3ebdSchin 				key->sym.value = tmp.value;
1376*da2e3ebdSchin 				key->sym.hidden = tmp.hidden;
1377*da2e3ebdSchin 			}
1378*da2e3ebdSchin 			if (!(key->sym.flags & SYM_KEYWORD))
1379*da2e3ebdSchin 			{
1380*da2e3ebdSchin 				key->sym.flags |= SYM_KEYWORD|SYM_LEX;
1381*da2e3ebdSchin 				key->lex = op;
1382*da2e3ebdSchin 				if (pp.test & 0x0400)
1383*da2e3ebdSchin 					error(1, "reserved#2 `%s' %d", p, op);
1384*da2e3ebdSchin 			}
1385*da2e3ebdSchin 			sfstrclose(sp);
1386*da2e3ebdSchin 		}
1387*da2e3ebdSchin 		break;
1388*da2e3ebdSchin 	case PP_SPACEOUT:
1389*da2e3ebdSchin 		set(&pp.state, SPACEOUT, va_arg(ap, int));
1390*da2e3ebdSchin 		break;
1391*da2e3ebdSchin 	case PP_STANDALONE:
1392*da2e3ebdSchin 		if (pp.initialized)
1393*da2e3ebdSchin 			goto before;
1394*da2e3ebdSchin 		pp.standalone = 1;
1395*da2e3ebdSchin 		break;
1396*da2e3ebdSchin 	case PP_STANDARD:
1397*da2e3ebdSchin 		if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
1398*da2e3ebdSchin 			SAVEID(&pp.lastdir->next->id, &st);
1399*da2e3ebdSchin 		for (dp = pp.firstdir; dp; dp = dp->next)
1400*da2e3ebdSchin 			if (dp->name)
1401*da2e3ebdSchin 				for (hp = pp.firstdir; hp != dp; hp = hp->next)
1402*da2e3ebdSchin 					if (hp->name && SAMEID(&hp->id, &dp->id))
1403*da2e3ebdSchin 					{
1404*da2e3ebdSchin 						hp->c = dp->c;
1405*da2e3ebdSchin 						if (dp->type & TYPE_HOSTED)
1406*da2e3ebdSchin 							hp->type |= TYPE_HOSTED;
1407*da2e3ebdSchin 						else
1408*da2e3ebdSchin 							hp->type &= ~TYPE_HOSTED;
1409*da2e3ebdSchin 					}
1410*da2e3ebdSchin 		break;
1411*da2e3ebdSchin 	case PP_STRICT:
1412*da2e3ebdSchin 		set(&pp.state, TRANSITION, 0);
1413*da2e3ebdSchin 		pp.flags &= ~PP_transition;
1414*da2e3ebdSchin 		set(&pp.state, STRICT, va_arg(ap, int));
1415*da2e3ebdSchin 		if (pp.state & STRICT)
1416*da2e3ebdSchin 			pp.flags |= PP_strict;
1417*da2e3ebdSchin 		else
1418*da2e3ebdSchin 			pp.flags &= ~PP_strict;
1419*da2e3ebdSchin 		break;
1420*da2e3ebdSchin 	case PP_TEST:
1421*da2e3ebdSchin 		if (p = va_arg(ap, char*))
1422*da2e3ebdSchin 			for (;;)
1423*da2e3ebdSchin 			{
1424*da2e3ebdSchin 				while (*p == ' ' || *p == '\t') p++;
1425*da2e3ebdSchin 				for (s = p; n = *s; s++)
1426*da2e3ebdSchin 					if (n == ',' || n == ' ' || n == '\t')
1427*da2e3ebdSchin 					{
1428*da2e3ebdSchin 						*s++ = 0;
1429*da2e3ebdSchin 						break;
1430*da2e3ebdSchin 					}
1431*da2e3ebdSchin 				if (!*p)
1432*da2e3ebdSchin 					break;
1433*da2e3ebdSchin 				n = 0;
1434*da2e3ebdSchin 				if (*p == 'n' && *(p + 1) == 'o')
1435*da2e3ebdSchin 				{
1436*da2e3ebdSchin 					p += 2;
1437*da2e3ebdSchin 					op = 0;
1438*da2e3ebdSchin 				}
1439*da2e3ebdSchin 				else
1440*da2e3ebdSchin 					op = 1;
1441*da2e3ebdSchin 				if (streq(p, "count"))
1442*da2e3ebdSchin 					n = TEST_count;
1443*da2e3ebdSchin 				else if (streq(p, "hashcount"))
1444*da2e3ebdSchin 					n = TEST_hashcount;
1445*da2e3ebdSchin 				else if (streq(p, "hashdump"))
1446*da2e3ebdSchin 					n = TEST_hashdump;
1447*da2e3ebdSchin 				else if (streq(p, "hit"))
1448*da2e3ebdSchin 					n = TEST_hit;
1449*da2e3ebdSchin 				else if (streq(p, "init"))
1450*da2e3ebdSchin 					n = TEST_noinit|TEST_INVERT;
1451*da2e3ebdSchin 				else if (streq(p, "noise"))
1452*da2e3ebdSchin 					n = TEST_nonoise|TEST_INVERT;
1453*da2e3ebdSchin 				else if (streq(p, "proto"))
1454*da2e3ebdSchin 					n = TEST_noproto|TEST_INVERT;
1455*da2e3ebdSchin 				else if (*p >= '0' && *p <= '9')
1456*da2e3ebdSchin 					n = strtoul(p, NiL, 0);
1457*da2e3ebdSchin 				else
1458*da2e3ebdSchin 				{
1459*da2e3ebdSchin 					error(1, "%s: unknown test", p);
1460*da2e3ebdSchin 					break;
1461*da2e3ebdSchin 				}
1462*da2e3ebdSchin 				if (n & TEST_INVERT)
1463*da2e3ebdSchin 				{
1464*da2e3ebdSchin 					n &= ~TEST_INVERT;
1465*da2e3ebdSchin 					op = !op;
1466*da2e3ebdSchin 				}
1467*da2e3ebdSchin 				if (op)
1468*da2e3ebdSchin 					pp.test |= n;
1469*da2e3ebdSchin 				else
1470*da2e3ebdSchin 					pp.test &= ~n;
1471*da2e3ebdSchin 				p = s;
1472*da2e3ebdSchin 				debug((-4, "test = 0%o", pp.test));
1473*da2e3ebdSchin 			}
1474*da2e3ebdSchin 		break;
1475*da2e3ebdSchin 	case PP_TRANSITION:
1476*da2e3ebdSchin 		set(&pp.state, STRICT, 0);
1477*da2e3ebdSchin 		pp.flags &= ~PP_strict;
1478*da2e3ebdSchin 		set(&pp.state, TRANSITION, va_arg(ap, int));
1479*da2e3ebdSchin 		if (pp.state & TRANSITION)
1480*da2e3ebdSchin 			pp.flags |= PP_transition;
1481*da2e3ebdSchin 		else
1482*da2e3ebdSchin 			pp.flags &= ~PP_transition;
1483*da2e3ebdSchin 		break;
1484*da2e3ebdSchin 	case PP_TRUNCATE:
1485*da2e3ebdSchin 		if (pp.initialized)
1486*da2e3ebdSchin 			goto before;
1487*da2e3ebdSchin 		if ((op = va_arg(ap, int)) < 0)
1488*da2e3ebdSchin 			op = 0;
1489*da2e3ebdSchin 		set(&pp.option, TRUNCATE, op);
1490*da2e3ebdSchin 		if (pp.option & TRUNCATE)
1491*da2e3ebdSchin 		{
1492*da2e3ebdSchin 			Hash_bucket_t*		b;
1493*da2e3ebdSchin 			Hash_bucket_t*		p;
1494*da2e3ebdSchin 			Hash_position_t*	pos;
1495*da2e3ebdSchin 			Hash_table_t*		tab;
1496*da2e3ebdSchin 
1497*da2e3ebdSchin 			pp.truncate = op;
1498*da2e3ebdSchin 			tab = pp.symtab;
1499*da2e3ebdSchin 			pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
1500*da2e3ebdSchin 			if (tab && (pos = hashscan(tab, 0)))
1501*da2e3ebdSchin 			{
1502*da2e3ebdSchin 				if (p = hashnext(pos))
1503*da2e3ebdSchin 					do
1504*da2e3ebdSchin 					{
1505*da2e3ebdSchin 						b = hashnext(pos);
1506*da2e3ebdSchin 						hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
1507*da2e3ebdSchin 					} while (p = b);
1508*da2e3ebdSchin 				hashdone(pos);
1509*da2e3ebdSchin 			}
1510*da2e3ebdSchin 		}
1511*da2e3ebdSchin 		else
1512*da2e3ebdSchin 			pp.truncate = 0;
1513*da2e3ebdSchin 		break;
1514*da2e3ebdSchin 	case PP_VENDOR:
1515*da2e3ebdSchin 		p = va_arg(ap, char*);
1516*da2e3ebdSchin 		c = va_arg(ap, int) != 0;
1517*da2e3ebdSchin 		if (!p || !*p)
1518*da2e3ebdSchin 			for (dp = pp.firstdir; dp; dp = dp->next)
1519*da2e3ebdSchin 				dp->type &= ~TYPE_VENDOR;
1520*da2e3ebdSchin 		else if (streq(p, "-"))
1521*da2e3ebdSchin 		{
1522*da2e3ebdSchin 			for (dp = pp.firstdir; dp; dp = dp->next)
1523*da2e3ebdSchin 				if (c)
1524*da2e3ebdSchin 					dp->type |= TYPE_VENDOR;
1525*da2e3ebdSchin 				else
1526*da2e3ebdSchin 					dp->type &= ~TYPE_VENDOR;
1527*da2e3ebdSchin 		}
1528*da2e3ebdSchin 		else if (!stat((pathcanon(p, 0), p), &st))
1529*da2e3ebdSchin 		{
1530*da2e3ebdSchin 			c = 0;
1531*da2e3ebdSchin 			for (dp = pp.firstdir; dp; dp = dp->next)
1532*da2e3ebdSchin 			{
1533*da2e3ebdSchin 				if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
1534*da2e3ebdSchin 					c = 1;
1535*da2e3ebdSchin 				if (c)
1536*da2e3ebdSchin 					dp->type |= TYPE_VENDOR;
1537*da2e3ebdSchin 				else
1538*da2e3ebdSchin 					dp->type &= ~TYPE_VENDOR;
1539*da2e3ebdSchin 			}
1540*da2e3ebdSchin 		}
1541*da2e3ebdSchin 		break;
1542*da2e3ebdSchin 	case PP_WARN:
1543*da2e3ebdSchin 		set(&pp.state, WARN, va_arg(ap, int));
1544*da2e3ebdSchin 		break;
1545*da2e3ebdSchin 	before:
1546*da2e3ebdSchin 		error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
1547*da2e3ebdSchin 		break;
1548*da2e3ebdSchin 	default:
1549*da2e3ebdSchin 		error(3, "ppop(%d): invalid preprocessor operation", op);
1550*da2e3ebdSchin 		break;
1551*da2e3ebdSchin 	}
1552*da2e3ebdSchin 	va_end(ap);
1553*da2e3ebdSchin }
1554