xref: /onnv-gate/usr/src/lib/libpp/common/ppop.c (revision 10898:1883b621b3ea)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*10898Sroland.mainz@nrubsig.org *          Copyright (c) 1986-2009 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Glenn Fowler
234887Schin  * AT&T Research
244887Schin  *
254887Schin  * preprocessor library control interface
264887Schin  */
274887Schin 
284887Schin #include "pplib.h"
294887Schin #include "pptab.h"
304887Schin 
314887Schin #include <ls.h>
324887Schin 
334887Schin #define REFONE	(pp.truncate?(Hash_table_t*)0:pp.symtab)
344887Schin #define REFALL	(pp.truncate?pp.dirtab:pp.symtab)
354887Schin 
364887Schin #define ppiskey(t,v,p)	(p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
374887Schin 
384887Schin /*
394887Schin  * set option value
404887Schin  * initialization files have lowest precedence
414887Schin  */
424887Schin 
434887Schin static void
set(register long * p,register long op,int val)444887Schin set(register long* p, register long op, int val)
454887Schin {
464887Schin 	long*	r;
474887Schin 
484887Schin 	r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
494887Schin 	if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op))
504887Schin 	{
514887Schin 		if (!pp.initialized && !(pp.mode & INIT))
524887Schin 			*r |= op;
534887Schin 		if (val)
544887Schin 			*p |= op;
554887Schin 		else
564887Schin 			*p &= ~op;
574887Schin 	}
584887Schin 	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)));
594887Schin }
604887Schin 
614887Schin /*
624887Schin  * initialize hash table with keywords from key
634887Schin  */
644887Schin 
654887Schin static void
inithash(register Hash_table_t * tab,register struct ppkeyword * key)664887Schin inithash(register Hash_table_t* tab, register struct ppkeyword* key)
674887Schin {
684887Schin 	register char*	s;
694887Schin 
704887Schin 	for (; s = key->name; key++)
714887Schin 	{
724887Schin 		if (!ppisid(*s))
734887Schin 			s++;
744887Schin 		hashput(tab, s, key->value);
754887Schin 	}
764887Schin }
774887Schin 
784887Schin /*
794887Schin  * return ppkeyword table name given value
804887Schin  */
814887Schin 
824887Schin char*
ppkeyname(register int value,int dir)834887Schin ppkeyname(register int value, int dir)
844887Schin {
854887Schin 	register char*			s;
864887Schin 	register struct ppkeyword*	p;
874887Schin 
884887Schin 	if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
894887Schin 	{
904887Schin 		s = (p + (value - p->value))->name;
914887Schin 		return s + !ppisid(*s);
924887Schin 	}
934887Schin #if DEBUG
944887Schin 	error(PANIC, "no keyword table name for value=%d", value);
954887Schin #endif
964887Schin 	return "UNKNOWN";
974887Schin }
984887Schin 
994887Schin /*
1004887Schin  * add to the include maps
1014887Schin  */
1024887Schin 
1034887Schin void
ppmapinclude(char * file,register char * s)1044887Schin ppmapinclude(char* file, register char* s)
1054887Schin {
1064887Schin 	register int		c;
1074887Schin 	register struct ppdirs*	dp;
1084887Schin 	int			fd;
1094887Schin 	int			flags;
1104887Schin 	int			index;
1114887Schin 	int			token;
1124887Schin 	char*			t;
1134887Schin 	char*			old_file;
1144887Schin 	long			old_state;
1154887Schin 	struct ppfile*		fp;
1164887Schin 	struct ppfile*		mp;
1174887Schin 
1184887Schin 	old_file = error_info.file;
1194887Schin 	old_state = pp.state;
1204887Schin 	if (s)
1214887Schin 		PUSH_BUFFER("mapinclude", s, 1);
1224887Schin 	else if (file)
1234887Schin 	{
1244887Schin 		if (*file == '-')
1254887Schin 		{
1264887Schin 			if (!error_info.file)
1274887Schin 			{
1284887Schin 				error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
1294887Schin 				return;
1304887Schin 			}
1314887Schin 			s = t = strcopy(pp.tmpbuf, error_info.file);
1324887Schin 			c = *++file;
1334887Schin 			for (;;)
1344887Schin 			{
1354887Schin 				if (s <= pp.tmpbuf || *s == '/')
1364887Schin 				{
1374887Schin 					s = t;
1384887Schin 					break;
1394887Schin 				}
1404887Schin 				else if (*s == c)
1414887Schin 					break;
1424887Schin 				s--;
1434887Schin 			}
1444887Schin 			strcpy(s, file);
1454887Schin 			file = pp.tmpbuf;
1464887Schin 		}
1474887Schin 		if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
1484887Schin 			return;
1494887Schin 		PUSH_FILE(file, fd);
1504887Schin 	}
1514887Schin 	else
1524887Schin 		return;
1534887Schin #if CATSTRINGS
1544887Schin 	pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
1554887Schin #else
1564887Schin 	pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
1574887Schin #endif
1584887Schin 	pp.level++;
1594887Schin 	flags = INC_MAPALL;
1604887Schin 	fp = mp = 0;
1614887Schin 	for (;;)
1624887Schin 	{
1634887Schin 		switch (token = pplex())
1644887Schin 		{
1654887Schin 		case 0:
1664887Schin 		case T_STRING:
1674887Schin 		case T_HEADER:
1684887Schin 			if (fp)
1694887Schin 			{
1704887Schin 				fp->guard = INC_IGNORE;
1714887Schin 				for (dp = pp.firstdir->next; dp; dp = dp->next)
1724887Schin 					if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
1734887Schin 					{
1744887Schin 						ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
1754887Schin 						break;
1764887Schin 					}
1774887Schin 			}
1784887Schin 			if (!token)
1794887Schin 				break;
1804887Schin 			pathcanon(pp.token, 0);
1814887Schin 			fp = ppsetfile(pp.token);
1824887Schin 			if (mp)
1834887Schin 			{
1844887Schin 				mp->flags |= flags;
1854887Schin 				if (streq(fp->name, "."))
1864887Schin 					mp->flags |= INC_MAPNOLOCAL;
1874887Schin 				else
1884887Schin 					mp->bound[index] = fp;
1894887Schin 
1904887Schin 				fp = mp = 0;
1914887Schin 			}
1924887Schin 			else
1934887Schin 				index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
1944887Schin 			continue;
1954887Schin 		case '=':
1964887Schin 			if (!(mp = fp))
1974887Schin 				error(3, "%s: \"name\" = \"binding\" expected");
1984887Schin 			fp = 0;
1994887Schin 			continue;
2004887Schin 		case '\n':
2014887Schin 			continue;
2024887Schin 		case T_ID:
2034887Schin 			if (streq(pp.token, "all"))
2044887Schin 			{
2054887Schin 				flags = INC_MAPALL;
2064887Schin 				continue;
2074887Schin 			}
2084887Schin 			else if (streq(pp.token, "hosted"))
2094887Schin 			{
2104887Schin 				flags = INC_MAPHOSTED;
2114887Schin 				continue;
2124887Schin 			}
2134887Schin 			else if (streq(pp.token, "nohosted"))
2144887Schin 			{
2154887Schin 				flags = INC_MAPNOHOSTED;
2164887Schin 				continue;
2174887Schin 			}
2184887Schin 			/*FALLTHROUGH*/
2194887Schin 		default:
2204887Schin 			error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
2214887Schin 			break;
2224887Schin 		}
2234887Schin 		break;
2244887Schin 	}
2254887Schin 	pp.level--;
2264887Schin 	error_info.file = old_file;
2274887Schin 	pp.state = old_state;
2284887Schin }
2294887Schin 
2304887Schin /*
2314887Schin  * return non-0 if file is identical to fd
2324887Schin  */
2334887Schin 
2344887Schin static int
identical(char * file,int fd)2354887Schin identical(char* file, int fd)
2364887Schin {
2374887Schin 	struct stat	a;
2384887Schin 	struct stat	b;
2394887Schin 
2404887Schin 	return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
2414887Schin }
2424887Schin 
2434887Schin /*
2444887Schin  * compare up to pp.truncate chars
2454887Schin  *
2464887Schin  * NOTE: __STD* and symbols containing ' ' are not truncated
2474887Schin  */
2484887Schin 
2494887Schin static int
trunccomp(register char * a,register char * b)2504887Schin trunccomp(register char* a, register char* b)
2514887Schin {
2524887Schin 	return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
2534887Schin }
2544887Schin 
2554887Schin /*
2564887Schin  * hash up to pp.truncate chars
2574887Schin  *
2584887Schin  * NOTE: __STD* and symbols containing ' ' are not truncated
2594887Schin  */
2604887Schin 
2614887Schin static unsigned int
trunchash(char * a)2624887Schin trunchash(char* a)
2634887Schin {
2644887Schin 	int	n;
2654887Schin 
2664887Schin 	return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
2674887Schin }
2684887Schin 
2694887Schin #if DEBUG & TRACE_debug
2704887Schin /*
2714887Schin  * append context to debug trace
2724887Schin  */
2734887Schin 
2744887Schin static int
context(Sfio_t * sp,int level,int flags)2754887Schin context(Sfio_t* sp, int level, int flags)
2764887Schin {
2774887Schin 	static int	state;
2784887Schin 
2794887Schin 	NoP(level);
2804887Schin 	NoP(flags);
2814887Schin 	if (error_info.trace <= -10 && pp.state != state)
2824887Schin 	{
2834887Schin 		state = pp.state;
2844887Schin 		sfprintf(sp, " %s", ppstatestr(pp.state));
2854887Schin 	}
2864887Schin 	return 1;
2874887Schin }
2884887Schin #endif
2894887Schin 
2904887Schin /*
2914887Schin  * reset include guard
2924887Schin  */
2934887Schin 
2944887Schin static int
unguard(const char * name,char * v,void * handle)2954887Schin unguard(const char* name, char* v, void* handle)
2964887Schin {
2974887Schin 	register struct ppfile*		fp = (struct ppfile*)v;
2984887Schin 
2994887Schin 	fp->guard = 0;
3004887Schin 	return 0;
3014887Schin }
3024887Schin 
3034887Schin /*
3044887Schin  * reset macro definition
3054887Schin  */
3064887Schin 
3074887Schin static void
undefine(void * p)3084887Schin undefine(void* p)
3094887Schin {
3104887Schin 	struct ppmacro*		mac = ((struct ppsymbol*)p)->macro;
3114887Schin 
3124887Schin 	if (mac)
3134887Schin 	{
3144887Schin 		if (mac->formals)
3154887Schin 			free(mac->formals);
3164887Schin 		free(mac->value);
3174887Schin 		free(mac);
3184887Schin 	}
3194887Schin }
3204887Schin 
3214887Schin /*
3224887Schin  * pp operations
3234887Schin  *
3244887Schin  * NOTE: PP_INIT must be done before the first pplex() call
3254887Schin  *	 PP_DONE must be done after the last pplex() call
3264887Schin  *	 PP_INIT-PP_DONE must be done for each new PP_INPUT
3274887Schin  */
3284887Schin 
3294887Schin void
ppop(int op,...)3304887Schin ppop(int op, ...)
3314887Schin {
3324887Schin 	va_list				ap;
3334887Schin 	register char*			p;
3344887Schin 	register struct ppkeyword*	kp;
3354887Schin 	register char*			s;
3364887Schin 	int				c;
3374887Schin 	long				n;
3384887Schin 	char*				t;
3394887Schin 	struct ppdirs*			dp;
3404887Schin 	struct ppdirs*			hp;
3414887Schin 	struct ppsymkey*		key;
3424887Schin 	struct oplist*			xp;
3434887Schin 	Sfio_t*				sp;
3444887Schin 	struct stat			st;
3454887Schin 	PPCOMMENT			ppcomment;
3464887Schin 	PPLINESYNC			pplinesync;
3474887Schin 
3484887Schin 	static int			initialized;
3494887Schin 
3504887Schin 	va_start(ap, op);
3514887Schin 	switch (op)
3524887Schin 	{
3534887Schin 	case PP_ASSERT:
3544887Schin 	case PP_DEFINE:
3554887Schin 	case PP_DIRECTIVE:
3564887Schin 	case PP_OPTION:
3574887Schin 	case PP_READ:
3584887Schin 	case PP_UNDEF:
3594887Schin 		if (pp.initialized)
3604887Schin 			goto before;
3614887Schin 		if ((p = va_arg(ap, char*)) && *p)
3624887Schin 		{
3634887Schin 			if (pp.lastop)
3644887Schin 				pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
3654887Schin 			else
3664887Schin 				pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
3674887Schin 			pp.lastop->op = op;
3684887Schin 			pp.lastop->value = p;
3694887Schin 		}
3704887Schin 		break;
3714887Schin 	case PP_BUILTIN:
3724887Schin 		pp.builtin = va_arg(ap, PPBUILTIN);
3734887Schin 		break;
3744887Schin 	case PP_CDIR:
3754887Schin 		p = va_arg(ap, char*);
3764887Schin 		c = va_arg(ap, int);
3774887Schin 		pp.cdir.path = 0;
3784887Schin 		if (!p)
3794887Schin 			pp.c = c;
3804887Schin 		else if (streq(p, "-"))
3814887Schin 		{
3824887Schin 			pp.c = c;
3834887Schin 			for (dp = pp.firstdir; dp; dp = dp->next)
3844887Schin 				dp->c = c;
3854887Schin 		}
3864887Schin 		else if (!pp.c)
3874887Schin 		{
3884887Schin 			if (!*p || stat((pathcanon(p, 0), p), &st))
3894887Schin 				pp.c = c;
3904887Schin 			else
3914887Schin 			{
3924887Schin 				for (dp = pp.firstdir; dp; dp = dp->next)
3934887Schin 				{
3944887Schin 					if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
3954887Schin 						pp.c = 1;
3964887Schin 					dp->c = pp.c == 1;
3974887Schin 				}
3984887Schin 				if (!pp.c)
3994887Schin 				{
4004887Schin 					pp.cdir.path = p;
4014887Schin 					SAVEID(&pp.cdir.id, &st);
4024887Schin 				}
4034887Schin 			}
4044887Schin 		}
4054887Schin 		break;
4064887Schin 	case PP_CHOP:
4074887Schin 		if (p = va_arg(ap, char*))
4084887Schin 		{
4094887Schin 			c = strlen(p);
4104887Schin 			xp = newof(0, struct oplist, 1, c + 1);
4114887Schin 			xp->value = ((char*)xp) + sizeof(struct oplist);
4124887Schin 			s = xp->value;
4134887Schin 			c = *p++;
4144887Schin 			while (*p && *p != c)
4154887Schin 				*s++ = *p++;
4164887Schin 			*s++ = '/';
4174887Schin 			xp->op = s - xp->value;
4184887Schin 			*s++ = 0;
4194887Schin 			if (*p && *++p && *p != c)
4204887Schin 			{
4214887Schin 				while (*p && *p != c)
4224887Schin 					*s++ = *p++;
4234887Schin 				*s++ = '/';
4244887Schin 			}
4254887Schin 			*s = 0;
4264887Schin 			xp->next = pp.chop;
4274887Schin 			pp.chop = xp;
4284887Schin 		}
4294887Schin 		break;
4304887Schin 	case PP_COMMENT:
4314887Schin 		if (pp.comment = va_arg(ap, PPCOMMENT))
4324887Schin 			pp.flags |= PP_comment;
4334887Schin 		else
4344887Schin 			pp.flags &= ~PP_comment;
4354887Schin 		break;
4364887Schin 	case PP_COMPATIBILITY:
4374887Schin 		set(&pp.state, COMPATIBILITY, va_arg(ap, int));
4384887Schin #if COMPATIBLE
4394887Schin 		if (pp.initialized)
4404887Schin 			ppfsm(FSM_COMPATIBILITY, NiL);
4414887Schin #else
4424887Schin 		if (pp.state & COMPATIBILITY)
4434887Schin 			error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
4444887Schin #endif
4454887Schin 		if (pp.state & COMPATIBILITY)
4464887Schin 			pp.flags |= PP_compatibility;
4474887Schin 		else
4484887Schin 			pp.flags &= ~PP_compatibility;
4494887Schin 		break;
4504887Schin 	case PP_COMPILE:
4514887Schin 		if (pp.initialized)
4524887Schin 			goto before;
4534887Schin 		pp.state |= COMPILE;
4544887Schin 		if (!pp.symtab)
4554887Schin 			pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
4564887Schin 		if (kp = va_arg(ap, struct ppkeyword*))
4574887Schin 			for (; s = kp->name; kp++)
4584887Schin 		{
4594887Schin 			n = SYM_LEX;
4604887Schin 			switch (*s)
4614887Schin 			{
4624887Schin 			case '-':
4634887Schin 				s++;
4644887Schin 				break;
4654887Schin 			case '+':
4664887Schin 				s++;
4674887Schin 				if (!(pp.option & PLUSPLUS))
4684887Schin 					break;
4694887Schin 				/*FALLTHROUGH*/
4704887Schin 			default:
4714887Schin 				n |= SYM_KEYWORD;
4724887Schin 				break;
4734887Schin 			}
4744887Schin 			if (key = ppkeyset(pp.symtab, s))
4754887Schin 			{
4764887Schin 				key->sym.flags = n;
4774887Schin 				key->lex = kp->value;
4784887Schin 			}
4794887Schin 		}
4804887Schin 		break;
4814887Schin 	case PP_DEBUG:
4824887Schin 		error_info.trace = va_arg(ap, int);
4834887Schin 		break;
4844887Schin 	case PP_DEFAULT:
4854887Schin 		if (p = va_arg(ap, char*))
4864887Schin 			p = strdup(p);
4874887Schin 		if (pp.ppdefault)
4884887Schin 			free(pp.ppdefault);
4894887Schin 		pp.ppdefault = p;
4904887Schin 		break;
4914887Schin 	case PP_DONE:
4924887Schin #if CHECKPOINT
4934887Schin 		if (pp.mode & DUMP)
4944887Schin 			ppdump();
4954887Schin #endif
4964887Schin 		if (pp.mode & FILEDEPS)
4974887Schin 		{
4984887Schin 			sfputc(pp.filedeps.sp, '\n');
4994887Schin 			if (pp.filedeps.sp == sfstdout)
5004887Schin 				sfsync(pp.filedeps.sp);
5014887Schin 			else
5024887Schin 				sfclose(pp.filedeps.sp);
5034887Schin 		}
5044887Schin 		if (pp.state & STANDALONE)
5054887Schin 		{
5064887Schin 			if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
5074887Schin 				ppputchar('\n');
5084887Schin 			ppflushout();
5094887Schin 		}
5104887Schin 		error_info.file = 0;
5114887Schin 		break;
5124887Schin 	case PP_DUMP:
5134887Schin 		set(&pp.mode, DUMP, va_arg(ap, int));
5144887Schin #if !CHECKPOINT
5154887Schin 		if (pp.mode & DUMP)
5164887Schin 			error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
5174887Schin #endif
5184887Schin 		break;
5194887Schin 	case PP_FILEDEPS:
5204887Schin 		if (n = va_arg(ap, int))
5214887Schin 			pp.filedeps.flags |= n;
5224887Schin 		else
5234887Schin 			pp.filedeps.flags = 0;
5244887Schin 		break;
5254887Schin 	case PP_FILENAME:
5264887Schin 		error_info.file = va_arg(ap, char*);
5274887Schin 		break;
5284887Schin 	case PP_HOSTDIR:
5294887Schin 		if (!(pp.mode & INIT))
5304887Schin 			pp.ro_mode |= HOSTED;
5314887Schin 		else if (pp.ro_mode & HOSTED)
5324887Schin 			break;
5334887Schin 		pp.ro_mode |= INIT;
5344887Schin 		p = va_arg(ap, char*);
5354887Schin 		c = va_arg(ap, int);
5364887Schin 		pp.hostdir.path = 0;
5374887Schin 		if (!p)
5384887Schin 			pp.hosted = c;
5394887Schin 		else if (streq(p, "-"))
5404887Schin 		{
5414887Schin 			if (pp.initialized)
5424887Schin 				set(&pp.mode, HOSTED, c);
5434887Schin 			else
5444887Schin 			{
5454887Schin 				pp.hosted = c ? 1 : 2;
5464887Schin 				for (dp = pp.firstdir; dp; dp = dp->next)
5474887Schin 					if (pp.hosted == 1)
5484887Schin 						dp->type |= TYPE_HOSTED;
5494887Schin 					else
5504887Schin 						dp->type &= ~TYPE_HOSTED;
5514887Schin 			}
5524887Schin 		}
5534887Schin 		else if (!pp.hosted)
5544887Schin 		{
5554887Schin 			if (!*p || stat((pathcanon(p, 0), p), &st))
5564887Schin 				pp.hosted = 1;
5574887Schin 			else
5584887Schin 			{
5594887Schin 				for (dp = pp.firstdir; dp; dp = dp->next)
5604887Schin 				{
5614887Schin 					if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
5624887Schin 						pp.hosted = 1;
5634887Schin 					if (pp.hosted == 1)
5644887Schin 						dp->type |= TYPE_HOSTED;
5654887Schin 					else
5664887Schin 						dp->type &= ~TYPE_HOSTED;
5674887Schin 				}
5684887Schin 				if (!pp.hosted)
5694887Schin 				{
5704887Schin 					pp.hostdir.path = p;
5714887Schin 					SAVEID(&pp.hostdir.id, &st);
5724887Schin 				}
5734887Schin 			}
5744887Schin 		}
5754887Schin 		break;
5764887Schin 	case PP_ID:
5774887Schin 		p = va_arg(ap, char*);
5784887Schin 		c = va_arg(ap, int);
5794887Schin 		if (p)
5804887Schin 			ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
5814887Schin 		break;
5824887Schin 	case PP_IGNORE:
5834887Schin 		if (p = va_arg(ap, char*))
5844887Schin 		{
5854887Schin 			pathcanon(p, 0);
5864887Schin 			ppsetfile(p)->guard = INC_IGNORE;
5874887Schin 			message((-3, "%s: ignore", p));
5884887Schin 		}
5894887Schin 		break;
5904887Schin 	case PP_IGNORELIST:
5914887Schin 		if (pp.initialized)
5924887Schin 			goto before;
5934887Schin 		pp.ignore = va_arg(ap, char*);
5944887Schin 		break;
5954887Schin 	case PP_INCLUDE:
5964887Schin 		if ((p = va_arg(ap, char*)) && *p)
5974887Schin 		{
5984887Schin 			pathcanon(p, 0);
5994887Schin 			if (stat(p, &st))
6004887Schin 				break;
6014887Schin 			for (dp = pp.stddirs; dp = dp->next;)
6024887Schin 				if (dp->name && SAMEID(&dp->id, &st))
6034887Schin 					break;
6044887Schin 			if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
6054887Schin 			{
6064887Schin 				pp.cdir.path = 0;
6074887Schin 				pp.c = 1;
6084887Schin 			}
6094887Schin 			if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
6104887Schin 			{
6114887Schin 				pp.hostdir.path = 0;
6124887Schin 				pp.hosted = 1;
6134887Schin 			}
6144887Schin 			if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
6154887Schin 				pp.hosted = 1;
6164887Schin 			c = dp && dp->c || pp.c == 1;
6174887Schin 			n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
6184887Schin 			if (!dp || dp == pp.lastdir->next)
6194887Schin 			{
6204887Schin 				if (dp)
6214887Schin 				{
6224887Schin 					c = dp->c;
6234887Schin 					n = dp->type & TYPE_HOSTED;
6244887Schin 				}
6254887Schin 				dp = newof(0, struct ppdirs, 1, 0);
6264887Schin 				dp->name = p;
6274887Schin 				SAVEID(&dp->id, &st);
6284887Schin 				dp->type |= TYPE_INCLUDE;
6294887Schin 				dp->index = INC_LOCAL + pp.ignoresrc != 0;
6304887Schin 				dp->next = pp.lastdir->next;
6314887Schin 				pp.lastdir = pp.lastdir->next = dp;
6324887Schin 			}
6334887Schin 			dp->c = c;
6344887Schin 			if (n)
6354887Schin 				dp->type |= TYPE_HOSTED;
6364887Schin 			else
6374887Schin 				dp->type &= ~TYPE_HOSTED;
6384887Schin 		}
6394887Schin 		break;
6404887Schin 	case PP_INCREF:
6414887Schin 		pp.incref = va_arg(ap, PPINCREF);
6424887Schin 		break;
6434887Schin 	case PP_RESET:
6444887Schin 		pp.reset.on = 1;
6454887Schin 		break;
6464887Schin 	case PP_INIT:
6474887Schin 		if (pp.initialized)
6484887Schin 		{
6494887Schin 			error_info.errors = 0;
6504887Schin 			error_info.warnings = 0;
6514887Schin 		}
6524887Schin 		else
6534887Schin 		{
6544887Schin 			/*
6554887Schin 			 * context initialization
6564887Schin 			 */
6574887Schin 
6584887Schin 			if (!initialized)
6594887Schin 			{
6604887Schin 				/*
6614887Schin 				 * out of malloc is fatal
6624887Schin 				 */
6634887Schin 
6644887Schin 				memfatal();
6654887Schin 
6664887Schin 				/*
6674887Schin 				 * initialize the error message interface
6684887Schin 				 */
6694887Schin 
6704887Schin 				error_info.version = (char*)pp.version;
6714887Schin #if DEBUG & TRACE_debug
6724887Schin 				error_info.auxilliary = context;
6734887Schin 				pptrace(0);
6744887Schin #endif
6754887Schin 
6764887Schin 				/*
6774887Schin 				 * initialize pplex tables
6784887Schin 				 */
6794887Schin 
6804887Schin 				ppfsm(FSM_INIT, NiL);
6814887Schin 
6824887Schin 				/*
6834887Schin 				 * fixed macro stack size -- room for improvement
6844887Schin 				 */
6854887Schin 
6864887Schin 				pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
6874887Schin 				pp.macp->next = pp.macp + 1;
6884887Schin 				pp.maxmac = (char*)pp.macp + DEFMACSTACK;
6894887Schin 				initialized = 1;
6904887Schin 
6914887Schin 				/*
6924887Schin 				 * initial include/if control stack
6934887Schin 				 */
6944887Schin 
6954887Schin 				pp.control = newof(0, long, pp.constack, 0);
6964887Schin 				pp.maxcon = pp.control + pp.constack - 1;
6974887Schin 			}
6984887Schin 
6994887Schin 			/*
7004887Schin 			 * validate modes
7014887Schin 			 */
7024887Schin 
7034887Schin 			switch (pp.arg_mode)
7044887Schin 			{
7054887Schin 			case 'a':
7064887Schin 			case 'C':
7074887Schin 				ppop(PP_COMPATIBILITY, 0);
7084887Schin 				ppop(PP_TRANSITION, 1);
7094887Schin 				break;
7104887Schin 			case 'A':
7114887Schin 			case 'c':
7124887Schin 				ppop(PP_COMPATIBILITY, 0);
7134887Schin 				ppop(PP_STRICT, 1);
7144887Schin 				break;
7154887Schin 			case 'f':
7164887Schin 				ppop(PP_COMPATIBILITY, 1);
7174887Schin 				ppop(PP_PLUSPLUS, 1);
7184887Schin 				ppop(PP_TRANSITION, 1);
7194887Schin 				break;
7204887Schin 			case 'F':
7214887Schin 				ppop(PP_COMPATIBILITY, 0);
7224887Schin 				ppop(PP_PLUSPLUS, 1);
7234887Schin 				break;
7244887Schin 			case 'k':
7254887Schin 			case 's':
7264887Schin 				ppop(PP_COMPATIBILITY, 1);
7274887Schin 				ppop(PP_STRICT, 1);
7284887Schin 				break;
7294887Schin 			case 'o':
7304887Schin 			case 'O':
7314887Schin 				ppop(PP_COMPATIBILITY, 1);
7324887Schin 				ppop(PP_TRANSITION, 0);
7334887Schin 				break;
7344887Schin 			case 't':
7354887Schin 				ppop(PP_COMPATIBILITY, 1);
7364887Schin 				ppop(PP_TRANSITION, 1);
7374887Schin 				break;
7384887Schin 			}
7398462SApril.Chin@Sun.COM 			if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
7404887Schin 				ppop(PP_PEDANTIC, 1);
7414887Schin 			if (pp.state & PASSTHROUGH)
7424887Schin 			{
7434887Schin 				if (pp.state & COMPILE)
7444887Schin 				{
7454887Schin 					pp.state &= ~PASSTHROUGH;
7464887Schin 					error(1, "passthrough ignored for compile");
7474887Schin 				}
7484887Schin 				else
7494887Schin 				{
7504887Schin 					ppop(PP_COMPATIBILITY, 1);
7514887Schin 					ppop(PP_HOSTDIR, "-", 1);
7524887Schin 					ppop(PP_SPACEOUT, 1);
7534887Schin 					set(&pp.state, DISABLE, va_arg(ap, int));
7544887Schin 				}
7554887Schin 			}
7564887Schin 
7574887Schin 			/*
7584887Schin 			 * create the hash tables
7594887Schin 			 */
7604887Schin 
7614887Schin 			if (!pp.symtab)
7624887Schin 				pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
7634887Schin 			if (!pp.dirtab)
7644887Schin 			{
7654887Schin 				pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
7664887Schin 				inithash(pp.dirtab, directives);
7674887Schin 			}
7684887Schin 			if (!pp.filtab)
7694887Schin 				pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
7704887Schin 			if (!pp.prdtab)
7714887Schin 				pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
7724887Schin 			if (!pp.strtab)
7734887Schin 			{
7744887Schin 				pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
7754887Schin 				inithash(pp.strtab, options);
7764887Schin 				inithash(pp.strtab, predicates);
7774887Schin 				inithash(pp.strtab, variables);
7784887Schin 			}
7794887Schin 			pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
7804887Schin 			pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
7814887Schin 
7824887Schin 			/*
7834887Schin 			 * mark macros that are builtin predicates
7844887Schin 			 */
7854887Schin 
7864887Schin 			for (kp = predicates; s = kp->name; kp++)
7874887Schin 			{
7884887Schin 				if (!ppisid(*s))
7894887Schin 					s++;
7904887Schin 				ppassert(DEFINE, s, 0);
7914887Schin 			}
7924887Schin 
7934887Schin 			/*
7944887Schin 			 * the remaining entry names must be allocated
7954887Schin 			 */
7964887Schin 
7974887Schin 			hashset(pp.dirtab, HASH_ALLOCATE);
7984887Schin 			hashset(pp.filtab, HASH_ALLOCATE);
7994887Schin 			hashset(pp.prdtab, HASH_ALLOCATE);
8004887Schin 			hashset(pp.strtab, HASH_ALLOCATE);
8014887Schin 			hashset(pp.symtab, HASH_ALLOCATE);
8024887Schin 			if (pp.test & TEST_nonoise)
8034887Schin 			{
8044887Schin 				c = error_info.trace;
8054887Schin 				error_info.trace = 0;
8064887Schin 			}
8074887Schin #if DEBUG
8084887Schin 			if (!(pp.test & TEST_noinit))
8094887Schin 			{
8104887Schin #endif
8114887Schin 
8124887Schin 			/*
8134887Schin 			 * compose, push and read the builtin initialization script
8144887Schin 			 */
8154887Schin 
8164887Schin 			if (!(sp = sfstropen()))
8174887Schin 				error(3, "temporary buffer allocation error");
8184887Schin 			sfprintf(sp,
8194887Schin "\
8204887Schin #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
8214887Schin #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
8224887Schin ",
8234887Schin 				dirname(PRAGMA),
8244887Schin 				pp.pass,
8254887Schin 				keyname(X_MAP),
8264887Schin 				dirname(DEFINE),
8274887Schin 				dirname(PRAGMA),
8284887Schin 				pp.pass,
8294887Schin 				keyname(X_MAP),
8304887Schin 				dirname(UNDEF));
8314887Schin 			if (pp.ppdefault && *pp.ppdefault)
8324887Schin 			{
8334887Schin 				if (pp.probe)
8344887Schin 				{
8354887Schin 					c = pp.lastdir->next->type;
8364887Schin 					pp.lastdir->next->type = 0;
8374887Schin 				}
8384887Schin 				if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
8394887Schin 				{
8404887Schin 					free(pp.ppdefault);
8414887Schin 					if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0)))
8424887Schin 						error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
8434887Schin 				}
8444887Schin 				if (pp.probe)
8454887Schin 					pp.lastdir->next->type = c;
8464887Schin 			}
8474887Schin 			while (pp.firstop)
8484887Schin 			{
8494887Schin 				switch (pp.firstop->op)
8504887Schin 				{
8514887Schin 				case PP_ASSERT:
8524887Schin 					sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
8534887Schin 					break;
8544887Schin 				case PP_DEFINE:
8554887Schin 					if (*pp.firstop->value == '#')
8564887Schin 						sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
8574887Schin 					else
8584887Schin 					{
8594887Schin 						if (s = strchr(pp.firstop->value, '='))
8604887Schin 							sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
8614887Schin 						else
8624887Schin 							sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
8634887Schin 					}
8644887Schin 					break;
8654887Schin 				case PP_DIRECTIVE:
8664887Schin 					sfprintf(sp, "#%s\n", pp.firstop->value);
8674887Schin 					break;
8684887Schin 				case PP_OPTION:
8694887Schin 					if (s = strchr(pp.firstop->value, '='))
8704887Schin 						sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
8714887Schin 					else
8724887Schin 						sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
8734887Schin 					break;
8744887Schin 				case PP_READ:
8754887Schin 					sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
8764887Schin 					break;
8774887Schin 				case PP_UNDEF:
8784887Schin 					sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
8794887Schin 					break;
8804887Schin 				}
8814887Schin 				pp.lastop = pp.firstop;
8824887Schin 				pp.firstop = pp.firstop->next;
8834887Schin 				free(pp.lastop);
8844887Schin 			}
8854887Schin 			sfprintf(sp,
8864887Schin "\
8874887Schin #%s %s:%s\n\
8884887Schin #%s %s:%s\n\
8894887Schin #%s !#%s(%s)\n\
8904887Schin #%s !#%s(%s) || #%s(%s)\n\
8914887Schin "
8924887Schin 				, dirname(PRAGMA)
8934887Schin 				, pp.pass
8944887Schin 				, keyname(X_BUILTIN)
8954887Schin 				, dirname(PRAGMA)
8964887Schin 				, pp.pass
8974887Schin 				, keyname(X_PREDEFINED)
8984887Schin 				, dirname(IF)
8994887Schin 				, keyname(X_OPTION)
9004887Schin 				, keyname(X_PLUSPLUS)
9014887Schin 				, dirname(IF)
9024887Schin 				, keyname(X_OPTION)
9034887Schin 				, keyname(X_COMPATIBILITY)
9044887Schin 				, keyname(X_OPTION)
9054887Schin 				, keyname(X_TRANSITION)
9064887Schin 				);
9074887Schin 			sfprintf(sp,
9084887Schin "\
9094887Schin #%s #%s(%s)\n\
9104887Schin #%s %s:%s\n\
9114887Schin #%s %s:%s\n\
9124887Schin #%s __STRICT__ 1\n\
9134887Schin #%s\n\
9144887Schin #%s\n\
9154887Schin "
9164887Schin 				, dirname(IF)
9174887Schin 				, keyname(X_OPTION)
9184887Schin 				, keyname(X_STRICT)
9194887Schin 				, dirname(PRAGMA)
9204887Schin 				, pp.pass
9214887Schin 				, keyname(X_ALLMULTIPLE)
9224887Schin 				, dirname(PRAGMA)
9234887Schin 				, pp.pass
9244887Schin 				, keyname(X_READONLY)
9254887Schin 				, dirname(DEFINE)
9264887Schin 				, dirname(ENDIF)
9274887Schin 				, dirname(ENDIF)
9284887Schin 				);
9294887Schin 			for (kp = readonlys; s = kp->name; kp++)
9304887Schin 			{
9314887Schin 				if (!ppisid(*s))
9324887Schin 					s++;
9334887Schin 				sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
9344887Schin 			}
9354887Schin 			sfprintf(sp,
9364887Schin "\
9374887Schin #%s\n\
9384887Schin #%s __STDPP__ 1\n\
9394887Schin #%s %s:no%s\n\
9404887Schin "
9414887Schin 				, dirname(ENDIF)
9424887Schin 				, dirname(DEFINE)
9434887Schin 				, dirname(PRAGMA)
9444887Schin 				, pp.pass
9454887Schin 				, keyname(X_PREDEFINED)
9464887Schin 				);
9474887Schin 			if (!pp.truncate)
9484887Schin 				sfprintf(sp,
9494887Schin "\
9504887Schin #%s __STDPP__directive #(%s)\n\
9514887Schin "
9524887Schin 				, dirname(DEFINE)
9534887Schin 				, keyname(V_DIRECTIVE)
9544887Schin 				);
9554887Schin 			for (kp = variables; s = kp->name; kp++)
9564887Schin 				if (ppisid(*s) || *s++ == '+')
9574887Schin 				{
9584887Schin 					t = *s == '_' ? "" : "__";
9594887Schin 					sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
9604887Schin 				}
9614887Schin 			sfprintf(sp,
9624887Schin "\
9634887Schin #%s %s:no%s\n\
9644887Schin #%s %s:no%s\n\
9654887Schin "
9664887Schin 				, dirname(PRAGMA)
9674887Schin 				, pp.pass
9684887Schin 				, keyname(X_READONLY)
9694887Schin 				, dirname(PRAGMA)
9704887Schin 				, pp.pass
9714887Schin 				, keyname(X_BUILTIN)
9724887Schin 				);
973*10898Sroland.mainz@nrubsig.org 			if (pp.ppdefault && *pp.ppdefault)
974*10898Sroland.mainz@nrubsig.org 				sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
975*10898Sroland.mainz@nrubsig.org 			sfprintf(sp,
976*10898Sroland.mainz@nrubsig.org "\
977*10898Sroland.mainz@nrubsig.org #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
978*10898Sroland.mainz@nrubsig.org #%s __STDC__ #(STDC)\n\
979*10898Sroland.mainz@nrubsig.org #%s\n\
980*10898Sroland.mainz@nrubsig.org "
981*10898Sroland.mainz@nrubsig.org 				, dirname(IF)
982*10898Sroland.mainz@nrubsig.org 				, dirname(DEFINE)
983*10898Sroland.mainz@nrubsig.org 				, dirname(ENDIF)
984*10898Sroland.mainz@nrubsig.org 				);
9854887Schin 			t = sfstruse(sp);
9864887Schin 			debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
9874887Schin 			ppcomment = pp.comment;
9884887Schin 			pp.comment = 0;
9894887Schin 			pplinesync = pp.linesync;
9904887Schin 			pp.linesync = 0;
9914887Schin 			PUSH_INIT(pp.pass, t);
9924887Schin 			pp.mode |= INIT;
9934887Schin 			while (pplex());
9944887Schin 			pp.mode &= ~INIT;
9954887Schin 			pp.comment = ppcomment;
9964887Schin 			pp.linesync = pplinesync;
9974887Schin 			pp.prefix = 0;
9984887Schin 			sfstrclose(sp);
9994887Schin 			if (error_info.trace)
10004887Schin 				for (dp = pp.firstdir; dp; dp = dp->next)
10014887Schin 					message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
10024887Schin #if DEBUG
10034887Schin 			}
10044887Schin 			if (pp.test & TEST_nonoise)
10054887Schin 				error_info.trace = c;
10064887Schin #endif
10074887Schin 			{
10084887Schin 				/*
10094887Schin 				 * this is sleazy but at least it's
10104887Schin 				 * hidden in the library
10114887Schin 				 */
10124887Schin #include <preroot.h>
10134887Schin #if FS_PREROOT
10144887Schin 				struct pplist*	preroot;
10154887Schin 
10164887Schin 				if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
10174887Schin 					setpreroot(NiL, preroot->value);
10184887Schin #endif
10194887Schin 			}
10204887Schin 			if (pp.ignoresrc)
10214887Schin 			{
10224887Schin 				if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
10234887Schin 					error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
10244887Schin 				pp.lcldirs = pp.lcldirs->next;
10254887Schin 			}
10264887Schin 			if (pp.ignore)
10274887Schin 			{
10284887Schin 				if (*pp.ignore)
10294887Schin 					ppmapinclude(pp.ignore, NiL);
10304887Schin 				else
10314887Schin 					pp.ignore = 0;
10324887Schin 			}
10334887Schin 			if (pp.standalone)
10344887Schin 				pp.state |= STANDALONE;
10354887Schin #if COMPATIBLE
10364887Schin 			ppfsm(FSM_COMPATIBILITY, NiL);
10374887Schin #endif
10384887Schin 			ppfsm(FSM_PLUSPLUS, NiL);
10394887Schin 			pp.initialized = 1;
10404887Schin 			if (pp.reset.on)
10414887Schin 			{
10424887Schin 				pp.reset.symtab = pp.symtab;
10434887Schin 				pp.symtab = 0;
10444887Schin 				pp.reset.ro_state = pp.ro_state;
10454887Schin 				pp.reset.ro_mode = pp.ro_mode;
10464887Schin 				pp.reset.ro_option = pp.ro_option;
10474887Schin 			}
10484887Schin 		}
10494887Schin 		if (pp.reset.on)
10504887Schin 		{
10514887Schin 			if (pp.symtab)
10524887Schin 			{
10534887Schin 				hashwalk(pp.filtab, 0, unguard, NiL);
10544887Schin 				hashfree(pp.symtab);
10554887Schin 			}
10564887Schin 			pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
10574887Schin 			hashview(pp.symtab, pp.reset.symtab);
10584887Schin 			pp.ro_state = pp.reset.ro_state;
10594887Schin 			pp.ro_mode = pp.reset.ro_mode;
10604887Schin 			pp.ro_option = pp.reset.ro_option;
10614887Schin 		}
10624887Schin #if CHECKPOINT
10634887Schin 		if (pp.mode & DUMP)
10644887Schin 		{
10654887Schin 			if (!pp.pragma)
10664887Schin 				error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
10674887Schin 			(*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
10684887Schin 		}
10694887Schin #endif
10704887Schin 		if (n = pp.filedeps.flags)
10714887Schin 		{
10724887Schin 			if (!(n & PP_deps_file))
10734887Schin 			{
10744887Schin 				pp.state |= NOTEXT;
10754887Schin 				pp.option |= KEEPNOTEXT;
10764887Schin 				pp.linesync = 0;
10774887Schin 			}
10784887Schin 			if (n & PP_deps_generated)
10794887Schin 				pp.mode |= GENDEPS;
10804887Schin 			if (n & PP_deps_local)
10814887Schin 				pp.mode &= ~HEADERDEPS;
10824887Schin 			else if (!(pp.mode & FILEDEPS))
10834887Schin 				pp.mode |= HEADERDEPS;
10844887Schin 			pp.mode |= FILEDEPS;
10854887Schin 		}
10864887Schin 
10874887Schin 		/*
10884887Schin 		 * push the main input file -- special case for hosted mark
10894887Schin 		 */
10904887Schin 
10914887Schin 		if (pp.firstdir->type & TYPE_HOSTED)
10924887Schin 			pp.mode |= MARKHOSTED;
10934887Schin 		else
10944887Schin 			pp.mode &= ~MARKHOSTED;
10954887Schin #if CHECKPOINT
10964887Schin 		if (!(pp.mode & DUMP))
10974887Schin #endif
10984887Schin 		{
10994887Schin 			if (!(p = error_info.file))
11004887Schin 				p = "";
11014887Schin 			else
11024887Schin 			{
11034887Schin 				error_info.file = 0;
11044887Schin 				if (*p)
11054887Schin 				{
11064887Schin 					pathcanon(p, 0);
11074887Schin 					p = ppsetfile(p)->name;
11084887Schin 				}
11094887Schin 			}
11104887Schin 			PUSH_FILE(p, 0);
11114887Schin 		}
11124887Schin 		if (pp.mode & FILEDEPS)
11134887Schin 		{
11144887Schin 			if (s = strrchr(error_info.file, '/'))
11154887Schin 				s++;
11164887Schin 			else
11174887Schin 				s = error_info.file;
11184887Schin 			if (!*s)
11194887Schin 				s = "-";
11204887Schin 			s = strcpy(pp.tmpbuf, s);
11214887Schin 			if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
11224887Schin 			{
11234887Schin 				if (c = *++p)
11244887Schin 					while (*++p == c);
11254887Schin 				if (*p)
11264887Schin 					t = 0;
11274887Schin 				else
11284887Schin 					t++;
11294887Schin 			}
11304887Schin 			if (!t)
11314887Schin 			{
11324887Schin 				t = s + strlen(s);
11334887Schin 				*t++ = '.';
11344887Schin 			}
11354887Schin 			*(t + 1) = 0;
11364887Schin 			if (pp.state & NOTEXT)
11374887Schin 				pp.filedeps.sp = sfstdout;
11384887Schin 			else
11394887Schin 			{
11404887Schin 				*t = 'd';
11414887Schin 				if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
11424887Schin 					error(ERROR_SYSTEM|3, "%s: cannot create", s);
11434887Schin 			}
11444887Schin 			*t = 'o';
11454887Schin 			pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
11464887Schin 			if (*error_info.file)
11474887Schin 				pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
11484887Schin 		}
11494887Schin 		if (xp = pp.firsttx)
11504887Schin 		{
11514887Schin 			if (!(sp = sfstropen()))
11524887Schin 				error(3, "temporary buffer allocation error");
11534887Schin 			while (xp)
11544887Schin 			{
11554887Schin 				sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
11564887Schin 				xp = xp->next;
11574887Schin 			}
11584887Schin 			t = sfstruse(sp);
11594887Schin 			PUSH_BUFFER("options", t, 1);
11604887Schin 			sfstrclose(sp);
11614887Schin 		}
11624887Schin 		break;
11634887Schin 	case PP_INPUT:
11644887Schin #if CHECKPOINT && POOL
11654887Schin 		if (!(pp.mode & DUMP) || pp.pool.input)
11664887Schin #else
11674887Schin #if CHECKPOINT
11684887Schin 		if (!(pp.mode & DUMP))
11694887Schin #else
11704887Schin #if POOL
11714887Schin 		if (pp.pool.input)
11724887Schin #endif
11734887Schin #endif
11744887Schin #endif
11754887Schin 		{
11764887Schin 			p = va_arg(ap, char*);
11774887Schin 			if (!error_info.file)
11784887Schin 				error_info.file = p;
11794887Schin 			close(0);
11804887Schin 			if (open(p, O_RDONLY) != 0)
11814887Schin 				error(ERROR_SYSTEM|3, "%s: cannot read", p);
11824887Schin 			if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
11834887Schin 			{
11844887Schin 				set(&pp.mode, CATLITERAL, 0);
11854887Schin 				ppop(PP_SPACEOUT, 1);
11864887Schin 			}
11874887Schin 			break;
11884887Schin 		}
11894887Schin 		/*FALLTHROUGH*/
11904887Schin 	case PP_TEXT:
11914887Schin 		if (pp.initialized)
11924887Schin 			goto before;
11934887Schin 		if ((p = va_arg(ap, char*)) && *p)
11944887Schin 		{
11954887Schin 			if (pp.lasttx)
11964887Schin 				pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
11974887Schin 			else
11984887Schin 				pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
11994887Schin 			pp.lasttx->op = op;
12004887Schin 			pp.lasttx->value = p;
12014887Schin 		}
12024887Schin 		break;
12034887Schin 	case PP_KEYARGS:
12044887Schin 		if (pp.initialized)
12054887Schin 			goto before;
12064887Schin 		set(&pp.option, KEYARGS, va_arg(ap, int));
12074887Schin 		if (pp.option & KEYARGS)
12084887Schin #if MACKEYARGS
12094887Schin 			set(&pp.mode, CATLITERAL, 1);
12104887Schin #else
12114887Schin 			error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
12124887Schin #endif
12134887Schin 		break;
12144887Schin 	case PP_LINE:
12154887Schin 		pp.linesync = va_arg(ap, PPLINESYNC);
12164887Schin 		break;
12174887Schin 	case PP_LINEBASE:
12184887Schin 		if (va_arg(ap, int))
12194887Schin 			pp.flags |= PP_linebase;
12204887Schin 		else
12214887Schin 			pp.flags &= ~PP_linebase;
12224887Schin 		break;
12234887Schin 	case PP_LINEFILE:
12244887Schin 		if (va_arg(ap, int))
12254887Schin 			pp.flags |= PP_linefile;
12264887Schin 		else
12274887Schin 			pp.flags &= ~PP_linefile;
12284887Schin 		break;
12294887Schin 	case PP_LINEID:
12304887Schin 		if (!(p = va_arg(ap, char*)))
12314887Schin 			pp.lineid = "";
12324887Schin 		else if (*p != '-')
12334887Schin 			pp.lineid = strdup(p);
12344887Schin 		else
12354887Schin 			pp.option |= IGNORELINE;
12364887Schin 		break;
12374887Schin 	case PP_LINETYPE:
12384887Schin 		if ((n = va_arg(ap, int)) >= 1)
12394887Schin 			pp.flags |= PP_linetype;
12404887Schin 		else
12414887Schin 			pp.flags &= ~PP_linetype;
12424887Schin 		if (n >= 2)
12434887Schin 			pp.flags |= PP_linehosted;
12444887Schin 		else
12454887Schin 			pp.flags &= ~PP_linehosted;
12464887Schin 		break;
12474887Schin 	case PP_LOCAL:
12484887Schin 		if (pp.initialized)
12494887Schin 			goto before;
12504887Schin 		pp.ignoresrc++;
12514887Schin 		pp.stddirs = pp.lastdir;
12524887Schin 		if (!(pp.ro_option & PREFIX))
12534887Schin 			pp.option &= ~PREFIX;
12544887Schin 		break;
12554887Schin 	case PP_MACREF:
12564887Schin 		pp.macref = va_arg(ap, PPMACREF);
12574887Schin 		break;
12584887Schin 	case PP_MULTIPLE:
12594887Schin 		set(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
12604887Schin 		break;
12614887Schin 	case PP_NOHASH:
12624887Schin 		set(&pp.option, NOHASH, va_arg(ap, int));
12634887Schin 		break;
12644887Schin 	case PP_NOISE:
12654887Schin 		op = va_arg(ap, int);
12664887Schin 		set(&pp.option, NOISE, op);
12674887Schin 		set(&pp.option, NOISEFILTER, op < 0);
12684887Schin 		break;
12694887Schin 	case PP_OPTARG:
12704887Schin 		pp.optarg = va_arg(ap, PPOPTARG);
12714887Schin 		break;
12724887Schin 	case PP_OUTPUT:
12734887Schin 		pp.outfile = va_arg(ap, char*);
12744887Schin 		if (identical(pp.outfile, 0))
12754887Schin 			error(3, "%s: identical to input", pp.outfile);
12764887Schin 		close(1);
12774887Schin 		if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
12784887Schin 			error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
12794887Schin 		break;
12804887Schin 	case PP_PASSTHROUGH:
12814887Schin 		if (!(pp.state & COMPILE))
12824887Schin 			set(&pp.state, PASSTHROUGH, va_arg(ap, int));
12834887Schin 		break;
12844887Schin 	case PP_PEDANTIC:
12854887Schin 		set(&pp.mode, PEDANTIC, va_arg(ap, int));
12864887Schin 		break;
12874887Schin 	case PP_PLUSCOMMENT:
12884887Schin 		set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
12894887Schin 		if (pp.initialized)
12904887Schin 			ppfsm(FSM_PLUSPLUS, NiL);
12914887Schin 		break;
12924887Schin 	case PP_PLUSPLUS:
12934887Schin 		set(&pp.option, PLUSPLUS, va_arg(ap, int));
12944887Schin 		set(&pp.option, PLUSCOMMENT, va_arg(ap, int));
12954887Schin 		if (pp.initialized)
12964887Schin 			ppfsm(FSM_PLUSPLUS, NiL);
12974887Schin 		break;
12984887Schin 	case PP_POOL:
12994887Schin 		if (pp.initialized)
13004887Schin 			goto before;
13014887Schin 		if (va_arg(ap, int))
13024887Schin 		{
13034887Schin #if POOL
13044887Schin 			pp.pool.input = dup(0);
13054887Schin 			pp.pool.output = dup(1);
13064887Schin 			p = "/dev/null";
13074887Schin 			if (!identical(p, 0))
13084887Schin 			{
13094887Schin 				if (!identical(p, 1))
13104887Schin 					ppop(PP_OUTPUT, p);
13114887Schin 				ppop(PP_INPUT, p);
13124887Schin 			}
13134887Schin #else
13144887Schin 			error(3, "preprocessor not compiled with input pool enabled [POOL]");
13154887Schin #endif
13164887Schin 		}
13174887Schin 		break;
13184887Schin 	case PP_PRAGMA:
13194887Schin 		pp.pragma = va_arg(ap, PPPRAGMA);
13204887Schin 		break;
13214887Schin 	case PP_PRAGMAFLAGS:
13224887Schin 		if (p = va_arg(ap, char*))
13234887Schin 		{
13244887Schin 			n = OPT_GLOBAL;
13254887Schin 			if (*p == '-')
13264887Schin 				p++;
13274887Schin 			else
13284887Schin 				n |= OPT_PASS;
13294887Schin 			if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
13304887Schin 				pp.optflags[c] = n;
13314887Schin 		}
13324887Schin 		break;
13334887Schin 	case PP_PROBE:
13344887Schin 		pp.probe = va_arg(ap, char*);
13354887Schin 		break;
13364887Schin 	case PP_QUOTE:
13374887Schin 		p = va_arg(ap, char*);
13384887Schin 		c = va_arg(ap, int);
13394887Schin 		if (p)
13404887Schin 			ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
13414887Schin 		break;
13424887Schin 	case PP_REGUARD:
13434887Schin 		set(&pp.option, REGUARD, va_arg(ap, int));
13444887Schin 		break;
13454887Schin 	case PP_RESERVED:
13464887Schin 		if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
13474887Schin 		{
13484887Schin 			if (!(sp = sfstropen()))
13494887Schin 				error(3, "temporary buffer allocation error");
13504887Schin 			sfputr(sp, p, -1);
13514887Schin 			p = sfstruse(sp);
13524887Schin 			if (s = strchr(p, '='))
13534887Schin 				*s++ = 0;
13544887Schin 			else
13554887Schin 				s = p;
13564887Schin 			while (*s == '_')
13574887Schin 				s++;
13584887Schin 			for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
13594887Schin 			if (*t == '_')
13604887Schin 				*t = 0;
13614887Schin 			else
13624887Schin 				t = 0;
13634887Schin 			op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
13644887Schin 			if (pp.test & 0x0400)
13654887Schin 				error(1, "reserved#1 `%s' %d", s, op);
13664887Schin 			if (t)
13674887Schin 				*t = '_';
13684887Schin 			if (!(key = ppkeyget(pp.symtab, p)))
13694887Schin 				key = ppkeyset(pp.symtab, NiL);
13704887Schin 			else if (!(key->sym.flags & SYM_LEX))
13714887Schin 			{
13724887Schin 				struct ppsymbol	tmp;
13734887Schin 
13744887Schin 				tmp = key->sym;
13754887Schin 				hashlook(pp.symtab, p, HASH_DELETE, NiL);
13764887Schin 				key = ppkeyset(pp.symtab, NiL);
13774887Schin 				key->sym.flags = tmp.flags;
13784887Schin 				key->sym.macro = tmp.macro;
13794887Schin 				key->sym.value = tmp.value;
13804887Schin 				key->sym.hidden = tmp.hidden;
13814887Schin 			}
13824887Schin 			if (!(key->sym.flags & SYM_KEYWORD))
13834887Schin 			{
13844887Schin 				key->sym.flags |= SYM_KEYWORD|SYM_LEX;
13854887Schin 				key->lex = op;
13864887Schin 				if (pp.test & 0x0400)
13874887Schin 					error(1, "reserved#2 `%s' %d", p, op);
13884887Schin 			}
13894887Schin 			sfstrclose(sp);
13904887Schin 		}
13914887Schin 		break;
13924887Schin 	case PP_SPACEOUT:
13934887Schin 		set(&pp.state, SPACEOUT, va_arg(ap, int));
13944887Schin 		break;
13954887Schin 	case PP_STANDALONE:
13964887Schin 		if (pp.initialized)
13974887Schin 			goto before;
13984887Schin 		pp.standalone = 1;
13994887Schin 		break;
14004887Schin 	case PP_STANDARD:
14014887Schin 		if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
14024887Schin 			SAVEID(&pp.lastdir->next->id, &st);
14034887Schin 		for (dp = pp.firstdir; dp; dp = dp->next)
14044887Schin 			if (dp->name)
14054887Schin 				for (hp = pp.firstdir; hp != dp; hp = hp->next)
14064887Schin 					if (hp->name && SAMEID(&hp->id, &dp->id))
14074887Schin 					{
14084887Schin 						hp->c = dp->c;
14094887Schin 						if (dp->type & TYPE_HOSTED)
14104887Schin 							hp->type |= TYPE_HOSTED;
14114887Schin 						else
14124887Schin 							hp->type &= ~TYPE_HOSTED;
14134887Schin 					}
14144887Schin 		break;
14154887Schin 	case PP_STRICT:
14164887Schin 		set(&pp.state, TRANSITION, 0);
14174887Schin 		pp.flags &= ~PP_transition;
14184887Schin 		set(&pp.state, STRICT, va_arg(ap, int));
14194887Schin 		if (pp.state & STRICT)
14204887Schin 			pp.flags |= PP_strict;
14214887Schin 		else
14224887Schin 			pp.flags &= ~PP_strict;
14234887Schin 		break;
14244887Schin 	case PP_TEST:
14254887Schin 		if (p = va_arg(ap, char*))
14264887Schin 			for (;;)
14274887Schin 			{
14284887Schin 				while (*p == ' ' || *p == '\t') p++;
14294887Schin 				for (s = p; n = *s; s++)
14304887Schin 					if (n == ',' || n == ' ' || n == '\t')
14314887Schin 					{
14324887Schin 						*s++ = 0;
14334887Schin 						break;
14344887Schin 					}
14354887Schin 				if (!*p)
14364887Schin 					break;
14374887Schin 				n = 0;
14384887Schin 				if (*p == 'n' && *(p + 1) == 'o')
14394887Schin 				{
14404887Schin 					p += 2;
14414887Schin 					op = 0;
14424887Schin 				}
14434887Schin 				else
14444887Schin 					op = 1;
14454887Schin 				if (streq(p, "count"))
14464887Schin 					n = TEST_count;
14474887Schin 				else if (streq(p, "hashcount"))
14484887Schin 					n = TEST_hashcount;
14494887Schin 				else if (streq(p, "hashdump"))
14504887Schin 					n = TEST_hashdump;
14514887Schin 				else if (streq(p, "hit"))
14524887Schin 					n = TEST_hit;
14534887Schin 				else if (streq(p, "init"))
14544887Schin 					n = TEST_noinit|TEST_INVERT;
14554887Schin 				else if (streq(p, "noise"))
14564887Schin 					n = TEST_nonoise|TEST_INVERT;
14574887Schin 				else if (streq(p, "proto"))
14584887Schin 					n = TEST_noproto|TEST_INVERT;
14594887Schin 				else if (*p >= '0' && *p <= '9')
14604887Schin 					n = strtoul(p, NiL, 0);
14614887Schin 				else
14624887Schin 				{
14634887Schin 					error(1, "%s: unknown test", p);
14644887Schin 					break;
14654887Schin 				}
14664887Schin 				if (n & TEST_INVERT)
14674887Schin 				{
14684887Schin 					n &= ~TEST_INVERT;
14694887Schin 					op = !op;
14704887Schin 				}
14714887Schin 				if (op)
14724887Schin 					pp.test |= n;
14734887Schin 				else
14744887Schin 					pp.test &= ~n;
14754887Schin 				p = s;
14764887Schin 				debug((-4, "test = 0%o", pp.test));
14774887Schin 			}
14784887Schin 		break;
14794887Schin 	case PP_TRANSITION:
14804887Schin 		set(&pp.state, STRICT, 0);
14814887Schin 		pp.flags &= ~PP_strict;
14824887Schin 		set(&pp.state, TRANSITION, va_arg(ap, int));
14834887Schin 		if (pp.state & TRANSITION)
14844887Schin 			pp.flags |= PP_transition;
14854887Schin 		else
14864887Schin 			pp.flags &= ~PP_transition;
14874887Schin 		break;
14884887Schin 	case PP_TRUNCATE:
14894887Schin 		if (pp.initialized)
14904887Schin 			goto before;
14914887Schin 		if ((op = va_arg(ap, int)) < 0)
14924887Schin 			op = 0;
14934887Schin 		set(&pp.option, TRUNCATE, op);
14944887Schin 		if (pp.option & TRUNCATE)
14954887Schin 		{
14964887Schin 			Hash_bucket_t*		b;
14974887Schin 			Hash_bucket_t*		p;
14984887Schin 			Hash_position_t*	pos;
14994887Schin 			Hash_table_t*		tab;
15004887Schin 
15014887Schin 			pp.truncate = op;
15024887Schin 			tab = pp.symtab;
15034887Schin 			pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
15044887Schin 			if (tab && (pos = hashscan(tab, 0)))
15054887Schin 			{
15064887Schin 				if (p = hashnext(pos))
15074887Schin 					do
15084887Schin 					{
15094887Schin 						b = hashnext(pos);
15104887Schin 						hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
15114887Schin 					} while (p = b);
15124887Schin 				hashdone(pos);
15134887Schin 			}
15144887Schin 		}
15154887Schin 		else
15164887Schin 			pp.truncate = 0;
15174887Schin 		break;
15184887Schin 	case PP_VENDOR:
15194887Schin 		p = va_arg(ap, char*);
15204887Schin 		c = va_arg(ap, int) != 0;
15214887Schin 		if (!p || !*p)
15224887Schin 			for (dp = pp.firstdir; dp; dp = dp->next)
15234887Schin 				dp->type &= ~TYPE_VENDOR;
15244887Schin 		else if (streq(p, "-"))
15254887Schin 		{
15264887Schin 			for (dp = pp.firstdir; dp; dp = dp->next)
15274887Schin 				if (c)
15284887Schin 					dp->type |= TYPE_VENDOR;
15294887Schin 				else
15304887Schin 					dp->type &= ~TYPE_VENDOR;
15314887Schin 		}
15324887Schin 		else if (!stat((pathcanon(p, 0), p), &st))
15334887Schin 		{
15344887Schin 			c = 0;
15354887Schin 			for (dp = pp.firstdir; dp; dp = dp->next)
15364887Schin 			{
15374887Schin 				if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
15384887Schin 					c = 1;
15394887Schin 				if (c)
15404887Schin 					dp->type |= TYPE_VENDOR;
15414887Schin 				else
15424887Schin 					dp->type &= ~TYPE_VENDOR;
15434887Schin 			}
15444887Schin 		}
15454887Schin 		break;
15464887Schin 	case PP_WARN:
15474887Schin 		set(&pp.state, WARN, va_arg(ap, int));
15484887Schin 		break;
15494887Schin 	before:
15504887Schin 		error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
15514887Schin 		break;
15524887Schin 	default:
15534887Schin 		error(3, "ppop(%d): invalid preprocessor operation", op);
15544887Schin 		break;
15554887Schin 	}
15564887Schin 	va_end(ap);
15574887Schin }
1558