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