xref: /onnv-gate/usr/src/lib/libpp/common/ppsearch.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  * include file search support
264887Schin  */
274887Schin 
284887Schin #include "pplib.h"
294887Schin 
304887Schin #define SEARCH_NEXT	(SEARCH_USER<<1)/* search for next (uncover)	*/
314887Schin #define SEARCH_SKIP	(SEARCH_USER<<2)/* current binding skipped	*/
324887Schin #define SEARCH_TEST	(SEARCH_USER<<3)/* test for binding		*/
334887Schin #define SEARCH_FOUND	(SEARCH_USER<<4)/* current binding found	*/
344887Schin 
354887Schin #define COLUMN_TAB	7
364887Schin #define COLUMN_MAX	72
374887Schin 
384887Schin #if ARCHIVE
394887Schin 
404887Schin #include <vdb.h>
414887Schin #include <ls.h>
424887Schin 
434887Schin #endif
444887Schin 
454887Schin /*
464887Schin  * multiple include test
474887Schin  * fp is a canonicalized ppfile pointer
484887Schin  *
494887Schin  * test
504887Schin  *
514887Schin  *	INC_CLEAR	can be included again
524887Schin  *	INC_TEST	test if include required
534887Schin  *	<symbol>	ifndef guard symbol
544887Schin  *
554887Schin  * test!=INC_CLEAR returns 1 if file can be included again
564887Schin  *
574887Schin  * NOTE:
584887Schin  *
594887Schin  *  (1)	different hard links to the same file are treated as
604887Schin  *	different files
614887Schin  *
624887Schin  *  (2)	symbolic links in combination with .. may cause two
634887Schin  *	different files to be treated as the same file:
644887Schin  *
654887Schin  *	"../h/<file>" == "/usr/include/sys/../h/<file>" -> "/usr/include/h/<file>"
664887Schin  *	"h/<file>" -> "/usr/include/h/<file>"
674887Schin  */
684887Schin 
694887Schin int
ppmultiple(register struct ppfile * fp,register struct ppsymbol * test)704887Schin ppmultiple(register struct ppfile* fp, register struct ppsymbol* test)
714887Schin {
724887Schin 	register struct ppsymbol*	status;
734887Schin 
744887Schin 	status = fp->guard;
754887Schin 	message((-3, "search: %s: status=%s%s test=%s", fp->name, status == INC_CLEAR ? "[CLEAR]" : status == INC_TEST ? "[ONCE]" : status == INC_IGNORE ? "[IGNORE]" : status->name, (pp.mode & HOSTED) ? "[HOSTED]" : "", test == INC_CLEAR ? "[CLEAR]" : test == INC_TEST ? "[TEST]" : test->name));
764887Schin 	if (status == INC_IGNORE)
774887Schin 	{
784887Schin 		message((-2, "%s: ignored [%s]", fp->name, pp.ignore));
794887Schin 		return 0;
804887Schin 	}
814887Schin 	if (test == INC_TEST)
824887Schin 	{
834887Schin 		if (status != INC_CLEAR)
844887Schin 		{
85*10898Sroland.mainz@nrubsig.org 			if (status == INC_TEST || status->macro)
864887Schin 			{
874887Schin 				if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING)
884887Schin 					fp->guard = INC_IGNORE;
898462SApril.Chin@Sun.COM 				if ((pp.state & WARN) && (pp.mode & (HOSTED|MARKHOSTED|RELAX|PEDANTIC)) == PEDANTIC)
904887Schin 					error(1, "%s: ignored -- already included", fp->name);
914887Schin 				else
924887Schin 					message((-3, "%s: ignored -- already included", fp->name));
934887Schin 				return 0;
944887Schin 			}
954887Schin 			return 1;
964887Schin 		}
974887Schin 		if ((pp.mode & (ALLMULTIPLE|LOADING)) == LOADING)
984887Schin 			test = INC_IGNORE;
99*10898Sroland.mainz@nrubsig.org 		else
100*10898Sroland.mainz@nrubsig.org 			return 1;
1014887Schin 	}
1024887Schin 	fp->guard = test;
1034887Schin 	return 1;
1044887Schin }
1054887Schin 
1064887Schin /*
1074887Schin  * search for file using directories in dp
1084887Schin  */
1094887Schin 
1104887Schin static int
search(register struct ppfile * fp,register struct ppdirs * dp,int type,int flags)1114887Schin search(register struct ppfile* fp, register struct ppdirs* dp, int type, int flags)
1124887Schin {
1134887Schin 	register char*		prefix;
1144887Schin 	register struct ppdirs*	up;
1154887Schin 	register struct ppfile*	xp;
1164887Schin 	struct ppfile*		mp;
1174887Schin 	int			fd;
1184887Schin 	int			index;
1194887Schin 	int			need;
1204887Schin 	int			markhosted;
1214887Schin 	char*			t;
1224887Schin 
1234887Schin 	if (!(pp.option & PREFIX))
1244887Schin 		prefix = 0;
1254887Schin 	else if ((prefix = strrchr(fp->name, '/')) && prefix > fp->name)
1264887Schin 	{
1274887Schin 		*prefix = 0;
1284887Schin 		t = ppsetfile(fp->name)->name;
1294887Schin 		*prefix = '/';
1304887Schin 		prefix = t;
1314887Schin 	}
1324887Schin 	message((-3, "search: %s %s%s%s%s%s%s type=%s prefix=%s flags=|%s%s%s%s%s%s start=%s=\"%s\" pre=%s lcl=%s vnd=%s std=%s cur=%s",
1334887Schin 		fp->name,
1344887Schin 		(flags & SEARCH_INCLUDE) ? "include" : "exists",
1354887Schin 		(flags & SEARCH_VENDOR) ? " vendor" : "",
1364887Schin 		(flags & SEARCH_HOSTED) ? " hosted" : "",
1374887Schin 		(flags & SEARCH_NEXT) ? " next" : "",
1384887Schin 		(flags & SEARCH_SKIP) ? " skip" : "",
1394887Schin 		(flags & SEARCH_TEST) ? " test" : "",
1404887Schin 		type == T_HEADER ? "<*>" : "\"*\"", prefix,
1414887Schin 		(fp->flags & INC_SELF) ? "SELF|" : "",
1424887Schin 		(fp->flags & INC_EXISTS) ? "EXISTS|" : "",
1434887Schin 		(fp->flags & INC_BOUND(INC_PREFIX)) ? "PREFIX|" : "",
1444887Schin 		(fp->flags & INC_BOUND(INC_LOCAL)) ? "LOCAL|" : "",
1454887Schin 		(fp->flags & INC_BOUND(INC_VENDOR)) ? "VENDOR|" : "",
1464887Schin 		(fp->flags & INC_BOUND(INC_STANDARD)) ? "STANDARD|" : "",
1474887Schin 		dp ? (dp->index == INC_PREFIX ? "pre" : dp->index == INC_LOCAL ? "lcl" : dp->index == INC_VENDOR ? "vnd" : "std") : NiL,
1484887Schin 		dp ? dp->name : NiL,
1494887Schin 		!(fp->flags & INC_MEMBER(INC_PREFIX)) && (xp = fp->bound[INC_PREFIX]) ? xp->name : NiL,
1504887Schin 		!(fp->flags & INC_MEMBER(INC_LOCAL)) && (xp = fp->bound[INC_LOCAL]) ? xp->name : NiL,
1514887Schin 		!(fp->flags & INC_MEMBER(INC_VENDOR)) && (xp = fp->bound[INC_VENDOR]) ? xp->name : NiL,
1524887Schin 		!(fp->flags & INC_MEMBER(INC_STANDARD)) && (xp = fp->bound[INC_STANDARD]) ? xp->name : NiL,
1534887Schin 		error_info.file
1544887Schin 		));
1554887Schin 	if (flags & SEARCH_HOSTED)
1564887Schin 		need = TYPE_HOSTED;
1574887Schin 	else if (flags & SEARCH_VENDOR)
1584887Schin 		need = TYPE_VENDOR;
1594887Schin 	else
1604887Schin 		need = TYPE_INCLUDE;
1614887Schin 	for (index = -1; dp; dp = dp->next)
1624887Schin 		if (dp->type & need)
1634887Schin 	{
1644887Schin 		message((-3, "search: fp=%s need=%02x index=%d dp=%s type=%02x index=%d", fp->name, need, index, dp->name, dp->type, dp->index));
1654887Schin #if ARCHIVE
1664887Schin 		if (!(dp->type & (TYPE_ARCHIVE|TYPE_DIRECTORY)))
1674887Schin 		{
1684887Schin 			struct stat	st;
1694887Schin 
1704887Schin 			if (stat(dp->name, &st))
1714887Schin 			{
1724887Schin 				message((-3, "search: omit %s", dp->name));
1734887Schin 				dp->type = 0;
1744887Schin 				continue;
1754887Schin 			}
1764887Schin 			if (S_ISREG(st.st_mode))
1774887Schin 			{
1784887Schin 				register char*		s;
1794887Schin 				char*			e;
1804887Schin 				int			delimiter;
1814887Schin 				int			variant;
1824887Schin 				unsigned long		siz;
1834887Schin 				unsigned long		off;
1844887Schin 				struct ppmember*	ap;
1854887Schin 				Sfio_t*			sp;
1864887Schin 
1874887Schin 				/*
1884887Schin 				 * check for vdb header archive
1894887Schin 				 */
1904887Schin 
1914887Schin 				if (!(sp = sfopen(NiL, dp->name, "r")))
1924887Schin 				{
1934887Schin 					error(ERROR_SYSTEM|1, "%s: ignored -- cannot open", dp->name);
1944887Schin 					dp->type = 0;
1954887Schin 					continue;
1964887Schin 				}
1974887Schin 				variant = sfsprintf(pp.tmpbuf, MAXTOKEN, "%c%s%c%s:archive", VDB_DELIMITER, VDB_MAGIC, VDB_DELIMITER, pp.pass);
1984887Schin 				if (!(s = sfgetr(sp, '\n', 1)) || !strneq(s, pp.tmpbuf, variant))
1994887Schin 				{
2004887Schin 					sfclose(sp);
2014887Schin 					error(1, "%s: ignored -- not a directory or archive", dp->name);
2024887Schin 					dp->type = 0;
2034887Schin 					continue;
2044887Schin 				}
2054887Schin 
2064887Schin 				/*
2074887Schin 				 * parse the options
2084887Schin 				 */
2094887Schin 
2104887Schin 				dp->type |= TYPE_ARCHIVE;
2114887Schin 				for (s += variant;;)
2124887Schin 				{
2134887Schin 					while (*s == ' ') s++;
2144887Schin 					e = s;
2154887Schin 					for (t = 0; *s && *s != ' '; s++)
2164887Schin 						if (*s == '=')
2174887Schin 						{
2184887Schin 							*s = 0;
2194887Schin 							t = s + 1;
2204887Schin 						}
2214887Schin 					if (*s)
2224887Schin 						*s++ = 0;
2234887Schin 					if (!*e)
2244887Schin 						break;
2254887Schin 					switch ((int)hashref(pp.strtab, e))
2264887Schin 					{
2274887Schin 					case X_CHECKPOINT:
2284887Schin #if CHECKPOINT
2294887Schin 						dp->type |= TYPE_CHECKPOINT;
2304887Schin 						break;
2314887Schin #else
2324887Schin 						error(1, "preprocessor not compiled with checkpoint enabled");
2334887Schin 						goto notvdb;
2344887Schin #endif
2354887Schin 					case X_HIDE:
2364887Schin 
2374887Schin 						if (t)
2384887Schin 							error(1, "%s: %s: archive option value ignored", e);
2394887Schin 						if (e = strrchr(dp->name, '/'))
2404887Schin 							*e = 0;
2414887Schin 						else
2424887Schin 							dp->name = ".";
2434887Schin 						break;
2444887Schin 					case X_MAP:
2454887Schin 						if (!t)
2464887Schin 							error(1, "%s: archive option value expected", e);
2474887Schin 						else
2484887Schin 							dp->name = strdup(t);
2494887Schin 						break;
2504887Schin 					default:
2514887Schin 						error(1, "%s: unknown archive option", e);
2524887Schin 						break;
2534887Schin 					}
2544887Schin 				}
2554887Schin 				if (sfseek(sp, -(VDB_LENGTH + 1), SEEK_END) <= 0 || !(s = sfgetr(sp, '\n', 1)))
2564887Schin 				{
2574887Schin 				notvdb:
2584887Schin 					sfclose(sp);
2594887Schin 					error(1, "%s: ignored -- cannot load archive", dp->name);
2604887Schin 					dp->type = 0;
2614887Schin 					continue;
2624887Schin 				}
2634887Schin 				if (variant = *s != 0)
2644887Schin 					s++;
2654887Schin 				else if (!(s = sfgetr(sp, '\n', 1)))
2664887Schin 					goto notvdb;
2674887Schin 				if (sfvalue(sp) != (VDB_LENGTH + variant))
2684887Schin 					goto notvdb;
2694887Schin 				if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY) - 1))
2704887Schin 					goto notvdb;
2714887Schin 				delimiter = s[VDB_OFFSET - 1];
2724887Schin 				off = strtol(s + VDB_OFFSET, NiL, 10) - sizeof(VDB_DIRECTORY);
2734887Schin 				siz = strtol(s + VDB_SIZE, NiL, 10);
2744887Schin 				if (sfseek(sp, off, SEEK_SET) != off)
2754887Schin 					goto notvdb;
2764887Schin 				if (!(s = sfreserve(sp, siz + 1, 0)))
2774887Schin 					goto notvdb;
2784887Schin 				s[siz] = 0;
2794887Schin 				if (!strneq(s, VDB_DIRECTORY, sizeof(VDB_DIRECTORY)) - 1)
2804887Schin 					goto notvdb;
2814887Schin 				if (!(s = strchr(s, '\n')))
2824887Schin 					goto notvdb;
2834887Schin 				s++;
2844887Schin 				while (e = strchr(s, '\n'))
2854887Schin 				{
2864887Schin 					delimiter = variant ? *s++ : delimiter;
2874887Schin 					if (!(t = strchr(s, delimiter)))
2884887Schin 						break;
2894887Schin 					*t = 0;
2904887Schin 					if (!streq(s, VDB_DIRECTORY))
2914887Schin 					{
2924887Schin 						pathcanon(s, 0);
2934887Schin 						ap = newof(0, struct ppmember, 1, 0);
2944887Schin 						ap->archive = dp;
2954887Schin 						ap->offset = strtol(t + 1, &t, 10);
2964887Schin 						ap->size = strtol(t + 1, NiL, 10);
2974887Schin 						xp = ppsetfile(s);
2984887Schin 						xp->flags |= INC_MEMBER(dp->index);
2994887Schin 						xp->bound[dp->index] = (struct ppfile*)ap;
3004887Schin if (pp.test & 0x0020) error(1, "VDB#%d %s %s index=%d data=<%lu,%lu>", __LINE__, dp->name, xp->name, index, ap->offset, ap->size);
3014887Schin 					}
3024887Schin 					s = e + 1;
3034887Schin 				}
3044887Schin 				if (sfseek(sp, 0L, SEEK_SET))
3054887Schin 					goto notvdb;
3064887Schin 				if (!(pp.test & 0x4000) &&
3074887Schin #if POOL
3084887Schin 					(pp.pool.input || !(dp->type & TYPE_CHECKPOINT))
3094887Schin #else
3104887Schin 					!(dp->type & TYPE_CHECKPOINT)
3114887Schin #endif
3124887Schin 					&& (dp->info.buffer = sfreserve(sp, off, 0)))
3134887Schin 					dp->type |= TYPE_BUFFER;
3144887Schin 				else
3154887Schin 				{
3164887Schin 					dp->info.sp = sp;
3174887Schin #if POOL
3184887Schin 					if (pp.pool.input)
3194887Schin 						sfset(sp, SF_SHARE, 1);
3204887Schin #endif
3214887Schin 				}
3224887Schin 			}
3234887Schin 			else
3244887Schin 				dp->type |= TYPE_DIRECTORY;
3254887Schin 		}
3264887Schin #endif
3274887Schin 		if (streq(fp->name, "."))
3284887Schin 			continue;
3294887Schin 		if (prefix && *fp->name != '/' && dp->index != INC_PREFIX)
3304887Schin #if ARCHIVE
3314887Schin 		if (dp->type & TYPE_DIRECTORY)
3324887Schin #endif
3334887Schin 		{
3344887Schin 			for (up = dp->info.subdir; up; up = up->next)
3354887Schin 				if (up->name == prefix)
3364887Schin 					break;
3374887Schin 			if (!up)
3384887Schin 			{
3394887Schin 				up = newof(0, struct ppdirs, 1, 0);
3404887Schin 				up->name = prefix;
3414887Schin 				up->type = dp->type;
3424887Schin 				up->next = dp->info.subdir;
3434887Schin 				dp->info.subdir = up;
3444887Schin 				if (!*dp->name)
3454887Schin 					t = prefix;
3464887Schin 				else
3474887Schin 					sfsprintf(t = pp.path, PATH_MAX - 1, "%s/%s", dp->name, prefix);
3484887Schin 				if (eaccess(t, X_OK))
3494887Schin 				{
3504887Schin 					message((-3, "search: omit %s", t));
3514887Schin 					continue;
3524887Schin 				}
3534887Schin 				up->type |= TYPE_HOSTED;
3544887Schin 			}
3554887Schin 			else if (!(up->type & TYPE_HOSTED))
3564887Schin 				continue;
3574887Schin 		}
3584887Schin 		mp = xp = 0;
3594887Schin 		if (!(flags & SEARCH_NEXT) && index != dp->index && (!(need & TYPE_HOSTED) || dp->index == INC_STANDARD) && (!(need & TYPE_VENDOR) || dp->index == INC_VENDOR))
3604887Schin 		{
3614887Schin 			if (index >= 0 && !(fp->flags & INC_MEMBER(index)))
3624887Schin 				fp->flags |= INC_BOUND(index);
3634887Schin 			index = dp->index;
3644887Schin 			if (fp->flags & INC_BOUND(index))
3654887Schin 			{
3664887Schin 				xp = fp->bound[index];
3674887Schin 				if (index == INC_PREFIX)
3684887Schin 				{
3694887Schin 					if (*fp->name == '/' || !*dp->name)
3704887Schin 						strcpy(pp.path, fp->name);
3714887Schin 					else
3724887Schin 						sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name);
3734887Schin 					pathcanon(pp.path, 0);
3744887Schin 					if (!xp || !streq(xp->name, pp.path))
3754887Schin 					{
3764887Schin 						fp->bound[index] = xp = ppsetfile(pp.path);
3774887Schin 						if (dp->type & TYPE_HOSTED)
3784887Schin 							xp->flags |= INC_HOSTED;
3794887Schin 						if ((flags & SEARCH_INCLUDE) || (xp->flags & INC_EXISTS))
3804887Schin 						{
3814887Schin 							if (!(flags & SEARCH_INCLUDE))
3824887Schin 								return 0;
3834887Schin 							if (!ppmultiple(xp, INC_TEST))
3844887Schin 							{
3854887Schin 								if (flags & SEARCH_TEST)
3864887Schin 									pp.include = xp->name;
3874887Schin 								return 0;
3884887Schin 							}
3894887Schin 							mp = xp;
3904887Schin 						}
3914887Schin 					}
3924887Schin 				}
3934887Schin 				else if (!xp)
3944887Schin 				{
3954887Schin 					while (dp->next && dp->next->index == index)
3964887Schin 						dp = dp->next;
3974887Schin 					message((-3, "search: omit %s/%s", dp->name, fp->name));
3984887Schin 					continue;
3994887Schin 				}
4004887Schin 				else
4014887Schin 				{
4024887Schin 					strcpy(pp.path, xp->name);
4034887Schin 					if (!(flags & SEARCH_INCLUDE))
4044887Schin 						return 0;
4054887Schin 					if (!ppmultiple(xp, INC_TEST))
4064887Schin 					{
4074887Schin 						if (flags & SEARCH_TEST)
4084887Schin 							pp.include = xp->name;
4094887Schin 						return 0;
4104887Schin 					}
4114887Schin 					mp = xp;
4124887Schin 				}
4134887Schin 			}
4144887Schin 		}
4154887Schin 		if (!(fp->flags & INC_BOUND(index)) || (flags & SEARCH_NEXT))
4164887Schin 		{
4174887Schin 			if (*fp->name == '/' || !*dp->name)
4184887Schin 				strcpy(pp.path, fp->name);
4194887Schin 			else
4204887Schin 				sfsprintf(pp.path, PATH_MAX - 1, "%s/%s", dp->name, fp->name);
4214887Schin 			pathcanon(pp.path, 0);
4224887Schin 			if (!(flags & SEARCH_SKIP))
4234887Schin 			{
4244887Schin 				int		found;
4254887Schin 				struct ppinstk*	in;
4264887Schin 
4274887Schin 				if (streq(error_info.file, pp.path))
4284887Schin 					found = 1;
4294887Schin 				else
4304887Schin 				{
4314887Schin 					found = 0;
4324887Schin 					for (in = pp.in; in; in = in->prev)
4334887Schin 						if (in->type == IN_FILE && in->file && streq(in->file, pp.path))
4344887Schin 						{
4354887Schin 							found = 1;
4364887Schin 							break;
4374887Schin 						}
4384887Schin 				}
4394887Schin 				if (found)
4404887Schin 				{
4414887Schin 					flags |= SEARCH_FOUND;
4424887Schin 					continue;
4434887Schin 				}
4444887Schin 				if (!(flags & SEARCH_FOUND))
4454887Schin 					continue;
4464887Schin 			}
4474887Schin 		}
4484887Schin 		if ((xp || (xp = ppgetfile(pp.path))) && (xp->flags & INC_SELF))
4494887Schin 		{
4504887Schin 			if (xp->flags & INC_EXISTS)
4514887Schin 			{
4524887Schin 				if (!(flags & SEARCH_INCLUDE))
4534887Schin 					return 0;
4544887Schin 				if (!(flags & SEARCH_NEXT) && mp != xp && (mp = xp) && !ppmultiple(xp, INC_TEST))
4554887Schin 				{
4564887Schin 					if (flags & SEARCH_TEST)
4574887Schin 						pp.include = xp->name;
4584887Schin 					return 0;
4594887Schin 				}
4604887Schin 			}
4614887Schin 			else if (*fp->name == '/')
4624887Schin 				break;
4634887Schin 			else
4644887Schin 				continue;
4654887Schin 		}
4664887Schin 		message((-3, "search: file=%s path=%s", fp->name, pp.path));
4674887Schin #if ARCHIVE
4684887Schin if (pp.test & 0x0040) error(1, "SEARCH#%d dir=%s%s%s%s%s file=%s%s path=%s index=%d", __LINE__, dp->name, (dp->type & TYPE_ARCHIVE) ? " ARCHIVE" : "",  (dp->type & TYPE_BUFFER) ? " BUFFER" : "", (dp->type & TYPE_CHECKPOINT) ? " CHECKPOINT" : "", (dp->type & TYPE_DIRECTORY) ? " DIRECTORY" : "", fp->name, (fp->flags & INC_MEMBER(index)) ? " MEMBER" : "", pp.path, index);
4694887Schin 		if ((fp->flags & INC_MEMBER(index)) && ((struct ppmember*)fp->bound[index])->archive == dp)
4704887Schin 		{
4714887Schin 			fd = 0;
4724887Schin 			pp.member = (struct ppmember*)fp->bound[index];
4734887Schin if (pp.test & 0x0010) error(1, "SEARCH#%d file=%s path=%s index=%d data=<%lu,%lu>", __LINE__, fp->name, pp.path, index, pp.member->offset, pp.member->size);
4744887Schin 		}
4754887Schin 		else if (!(dp->type & TYPE_DIRECTORY))
4764887Schin 			continue;
4774887Schin 		else
4784887Schin #endif
4794887Schin 		{
4804887Schin 			pp.member = 0;
4814887Schin 			fd = (flags & SEARCH_INCLUDE) ? open(pp.path, O_RDONLY) : eaccess(pp.path, R_OK);
4824887Schin 		}
4834887Schin 		if (fd >= 0)
4844887Schin 		{
4854887Schin 			pp.found = dp;
4864887Schin 			if ((pp.option & (PLUSPLUS|NOPROTO)) == PLUSPLUS && !(pp.test & TEST_noproto))
4874887Schin 			{
4884887Schin 				if (dp->c)
4894887Schin 					pp.mode |= MARKC;
4904887Schin 				else
4914887Schin 					pp.mode &= ~MARKC;
4924887Schin 			}
4934887Schin 			if (xp)
4944887Schin 				markhosted = xp->flags & INC_HOSTED;
4954887Schin 			else if (!(markhosted = (dp->type & TYPE_HOSTED)) && dp->index == INC_PREFIX && (pp.mode & (FILEDEPS|HEADERDEPS|INIT)) == FILEDEPS)
4964887Schin 			{
4974887Schin 				up = dp;
4984887Schin 				while ((up = up->next) && !streq(up->name, dp->name));
4994887Schin 				if (up && (up->type & TYPE_HOSTED))
5004887Schin 					markhosted = 1;
5014887Schin 			}
5024887Schin 			if (markhosted)
5034887Schin 				pp.mode |= MARKHOSTED;
5044887Schin 			else
5054887Schin 				pp.mode &= ~MARKHOSTED;
5064887Schin 			xp = ppsetfile(pp.path);
5074887Schin 			if (markhosted)
5084887Schin 				xp->flags |= INC_HOSTED;
5094887Schin 			message((-2, "search: %s -> %s%s%s", fp->name, pp.path, (pp.mode & MARKC) ? " [C]" : "", (pp.mode & MARKHOSTED) ? " [hosted]" : ""));
5104887Schin #if ARCHIVE
5114887Schin 			if (!pp.member)
5124887Schin 			{
5134887Schin #endif
5144887Schin 				fp->flags |= INC_BOUND(index);
5154887Schin 				fp->bound[index] = xp;
5164887Schin 				if ((index == INC_STANDARD || index == INC_VENDOR) && type != T_HEADER && !(fp->flags & INC_BOUND(INC_LOCAL)))
5174887Schin 				{
5184887Schin 					fp->flags |= INC_BOUND(INC_LOCAL);
5194887Schin 					fp->bound[INC_LOCAL] = xp;
5204887Schin 				}
5214887Schin #if ARCHIVE
5224887Schin 			}
5234887Schin #endif
5244887Schin 			xp->flags |= INC_SELF|INC_EXISTS;
5254887Schin 			if (flags & SEARCH_INCLUDE)
5264887Schin 			{
5274887Schin 				if ((pp.prefix = prefix) || (pp.prefix = pp.in->prefix))
5284887Schin 					message((-2, "search: %s: prefix=%s", xp->name, pp.prefix));
5294887Schin 				if (!(pp.mode & ALLMULTIPLE))
5304887Schin 				{
5314887Schin 					if (xp->guard == INC_CLEAR || xp == mp)
5324887Schin 						xp->guard = INC_TEST;
5334887Schin 					else
5344887Schin 					{
5358462SApril.Chin@Sun.COM 						if ((pp.state & WARN) && (pp.mode & (HOSTED|MARKHOSTED|RELAX|PEDANTIC)) == PEDANTIC)
5364887Schin 							error(1, "%s: ignored -- already included", xp->name);
5374887Schin 						else
5384887Schin 							message((-3, "%s: ignored -- already included", xp->name));
5394887Schin 						xp->guard = fp->guard = INC_IGNORE;
5404887Schin #if ARCHIVE
5414887Schin 						if (!pp.member)
5424887Schin #endif
5434887Schin 						if (fd > 0)
5444887Schin 							close(fd);
5454887Schin 						if (flags & SEARCH_TEST)
5464887Schin 							pp.include = xp->name;
5474887Schin 						return 0;
5484887Schin 					}
5494887Schin 				}
5504887Schin 				pp.include = xp->name;
5514887Schin 				if ((pp.mode & (FILEDEPS|INIT)) == FILEDEPS && ((pp.mode & HEADERDEPS) || !(pp.mode & MARKHOSTED)) && !(xp->flags & INC_LISTED))
5524887Schin 				{
5534887Schin 					xp->flags |= INC_LISTED;
5544887Schin 					if ((pp.column + strlen(xp->name)) >= COLUMN_MAX)
5554887Schin 					{
5564887Schin 						sfprintf(pp.filedeps.sp, " \\\n");
5574887Schin 						pp.column = COLUMN_TAB;
5584887Schin 						index = '\t';
5594887Schin 					}
5604887Schin 					else
5614887Schin 						index = ' ';
5624887Schin 					pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, xp->name);
5634887Schin 				}
5644887Schin 			}
5654887Schin 			return fd;
5664887Schin 		}
5674887Schin 		if (xp)
5684887Schin 			xp->flags |= INC_SELF;
5694887Schin 		if (errno == EMFILE)
5704887Schin 			error(3, "%s: too many open files", fp->name);
5714887Schin 		else if (errno != ENOENT && errno != ENOTDIR)
5724887Schin 			error(ERROR_SYSTEM|1, "%s: cannot open file for reading", pp.path);
5734887Schin 		if (*fp->name == '/')
5744887Schin 			break;
5754887Schin 	}
5764887Schin 	strcpy(pp.path, fp->name);
5774887Schin 	message((-2, "search: %s%s not found", (flags & SEARCH_NEXT) ? "next " : "", fp->name));
5784887Schin 	return -1;
5794887Schin }
5804887Schin 
5814887Schin /*
5824887Schin  * search for an include file
5834887Schin  * if (flags&SEARCH_INCLUDE) then
5844887Schin  *	if file found then open read file descriptor returned
5854887Schin  *		with pp.path set to the full path and
5864887Schin  *		pp.prefix set to the directory prefix
5874887Schin  *	otherwise 0 returned if file found but ignored
5884887Schin  *	otherwise -1 returned
5894887Schin  * otherwise
5904887Schin  *	if file found then 0 returned
5914887Schin  *	otherwise -1 returned
5924887Schin  */
5934887Schin 
5944887Schin int
ppsearch(char * file,int type,int flags)5954887Schin ppsearch(char* file, int type, int flags)
5964887Schin {
5974887Schin 	register struct ppfile*	fp;
5984887Schin 	register char*		s;
5994887Schin 	register struct ppdirs*	dp;
6004887Schin 	struct oplist*		cp;
6014887Schin 	struct ppfile*		xp;
6024887Schin 	int			dospath;
6038462SApril.Chin@Sun.COM 	int			chop;
6044887Schin 	int			fd;
6054887Schin 	int			index;
6064887Schin 	char			name[MAXTOKEN + 1];
6074887Schin 
6084887Schin 	pp.include = 0;
6094887Schin 	fd = -1;
6108462SApril.Chin@Sun.COM 	chop = 0;
611*10898Sroland.mainz@nrubsig.org 	if (s = strchr(file, '\\'))
612*10898Sroland.mainz@nrubsig.org 	{
613*10898Sroland.mainz@nrubsig.org 		do *s++ = '/'; while (s = strchr(s, '\\'));
614*10898Sroland.mainz@nrubsig.org 		dospath = 1;
615*10898Sroland.mainz@nrubsig.org 	}
616*10898Sroland.mainz@nrubsig.org 	else
617*10898Sroland.mainz@nrubsig.org 		dospath = 0;
6184887Schin  again:
6194887Schin 	pathcanon(file, 0);
6208462SApril.Chin@Sun.COM 	if (chop)
6218462SApril.Chin@Sun.COM 		for (cp = pp.chop; cp; cp = cp->next)
6228462SApril.Chin@Sun.COM 			if (strneq(file, cp->value, cp->op))
6234887Schin 			{
6248462SApril.Chin@Sun.COM 				if (cp->value[cp->op + 1])
6258462SApril.Chin@Sun.COM 				{
6268462SApril.Chin@Sun.COM 					sfsprintf(name, sizeof(name) - 1, "%s%s", cp->value + cp->op + 1, file + cp->op);
6278462SApril.Chin@Sun.COM 					message((-2, "search: %s -> %s", file, name));
6288462SApril.Chin@Sun.COM 					file = name;
6298462SApril.Chin@Sun.COM 				}
6308462SApril.Chin@Sun.COM 				else if (strchr(file + cp->op, '/'))
6318462SApril.Chin@Sun.COM 				{
6328462SApril.Chin@Sun.COM 					message((-2, "search: %s -> %s", file, file + cp->op));
6338462SApril.Chin@Sun.COM 					file += cp->op;
6348462SApril.Chin@Sun.COM 				}
6358462SApril.Chin@Sun.COM 				break;
6364887Schin 			}
6374887Schin 	fp = ppsetfile(file);
6384887Schin 	while ((fp->flags & INC_MAPALL) || (fp->flags & INC_MAPHOSTED) && (pp.mode & HOSTED) || (fp->flags & INC_MAPNOHOSTED) && !(pp.mode & HOSTED))
6394887Schin 	{
6404887Schin 		if (!(xp = fp->bound[type == T_HEADER ? INC_STANDARD : INC_LOCAL]) || xp == fp)
6414887Schin 			break;
6424887Schin 		message((-1, "map: %s -> %s", fp->name, xp->name));
6434887Schin 		fp = xp;
6444887Schin 	}
6454887Schin 	if ((fp->flags & INC_MAPNOLOCAL) && (pp.mode & HOSTED))
6464887Schin 		flags |= SEARCH_HOSTED;
6474887Schin 	else if (pp.vendor)
6484887Schin 		flags |= SEARCH_VENDOR;
6494887Schin 	pp.original = fp;
6504887Schin 	if (type == T_HEADER && strneq(fp->name, "...", 3) && (!fp->name[3] || fp->name[3] == '/'))
6514887Schin 	{
6524887Schin 		if (fp->name[3] == '/')
6534887Schin 		{
6544887Schin 			int	n;
6554887Schin 			int	m;
6564887Schin 
6574887Schin 			n = strlen(error_info.file);
6584887Schin 			m = strlen(fp->name + 4);
6594887Schin 			if (n < m || !streq(fp->name + 4, error_info.file + n - m))
6604887Schin 			{
6614887Schin 				if ((fd = ppsearch(fp->name + 4, type, flags|SEARCH_TEST)) < 0)
6624887Schin 					return -1;
6634887Schin 				if (fd > 0)
6644887Schin 					close(fd);
6654887Schin 				s = error_info.file;
6664887Schin 				error_info.file = pp.include;
6674887Schin 				fd = ppsearch(fp->name + 4, type, flags|SEARCH_NEXT);
6684887Schin 				error_info.file = s;
6694887Schin 				return fd;
6704887Schin 			}
6714887Schin 			file = error_info.file + n - m;
6724887Schin 		}
6734887Schin 		else if (file = strrchr(error_info.file, '/'))
6744887Schin 			file++;
6754887Schin 		else
6764887Schin 			file = error_info.file;
6774887Schin 		flags |= SEARCH_NEXT;
6784887Schin #if _HUH_2002_05_28
6794887Schin 		if (pp.in->prefix)
6804887Schin 		{
6814887Schin 			sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, file);
6824887Schin 			fp = ppsetfile(name);
6834887Schin 			if ((fd = ppsearch(fp->name, type, flags)) >= 0)
6844887Schin 				return fd;
6854887Schin 		}
6864887Schin #endif
6874887Schin 		fp = ppsetfile(file);
6884887Schin 		return ppsearch(fp->name, type, flags);
6894887Schin 	}
6904887Schin 	else if ((flags & SEARCH_INCLUDE) && fp->guard == INC_IGNORE)
6914887Schin 	{
6924887Schin 		strcpy(pp.path, fp->name);
6934887Schin 		message((-2, "%s: ignored", fp->name));
6944887Schin 		return 0;
6954887Schin 	}
6964887Schin 	else if (!(flags & SEARCH_NEXT))
6974887Schin 		flags |= SEARCH_SKIP;
6984887Schin 	pp.prefix = 0;
6994887Schin 	if (type == T_HEADER)
7004887Schin 		dp = pp.stddirs->next;
7014887Schin 	else
7024887Schin 	{
7034887Schin 		dp = pp.lcldirs;
7044887Schin 		if (dp == pp.firstdir)
7054887Schin 		{
7064887Schin 			/*
7074887Schin 			 * look in directory of including file first
7084887Schin 			 */
7094887Schin 
7104887Schin 			if (error_info.file && (s = strrchr(error_info.file, '/')))
7114887Schin 			{
7124887Schin 				*s = 0;
7134887Schin 				dp->name = ppsetfile(error_info.file)->name;
7144887Schin 				*s = '/';
7154887Schin 			}
7164887Schin 			else
7174887Schin 				dp->name = "";
7184887Schin 		}
7194887Schin 		else if (pp.in->prefix && pp.lcldirs != pp.firstdir)
7204887Schin 		{
7214887Schin 			/*
7224887Schin 			 * look in prefix directory of including file first
7234887Schin 			 */
7244887Schin 
7254887Schin 			if (*fp->name != '/')
7264887Schin 			{
7274887Schin 				if ((s = strchr(fp->name, '/')) && (fp->name[0]
7284887Schin != '.' || fp->name[1] != '.' || fp->name[2] != '/'))
7294887Schin 				{
7304887Schin 					*s = 0;
7314887Schin 					if (!streq(fp->name, pp.in->prefix))
7324887Schin 						fd = 0;
7334887Schin 					*s = '/';
7344887Schin 				}
7354887Schin 				else
7364887Schin 					fd = 0;
7374887Schin 			}
7384887Schin 			if (fd >= 0)
7394887Schin 			{
7404887Schin 				sfsprintf(name, sizeof(name) - 1, "%s/%s", pp.in->prefix, fp->name);
7414887Schin 				pathcanon(name, 0);
7424887Schin 				xp = ppsetfile(name);
7434887Schin 				if ((fd = search(xp, dp, type, flags)) >= 0)
7444887Schin 					return fd;
7454887Schin 			}
7464887Schin 		}
7474887Schin 	}
7484887Schin 	if ((fd = search(fp, dp, type, flags)) < 0)
7494887Schin 	{
7504887Schin 		if ((pp.option & PLUSPLUS) && file != pp.tmpbuf)
7514887Schin 		{
7524887Schin 			s = file + strlen(file);
7534887Schin 			while (s > file && *--s != '/' && *s != '\\' && *s != '.');
7544887Schin 			if (*s != '.')
7554887Schin 			{
7564887Schin 				sfsprintf(pp.tmpbuf, MAXTOKEN, "%s.h", file);
7574887Schin 				file = pp.tmpbuf;
7584887Schin 				goto again;
7594887Schin 			}
7604887Schin 		}
7614887Schin 
7624887Schin 		/*
7634887Schin 		 * hackery for msdos files viewed through unix
7644887Schin 		 */
7654887Schin 
7664887Schin 		switch (dospath)
7674887Schin 		{
7684887Schin 		case 1:
7694887Schin 			if (ppisid(file[0]) && file[1] == ':' && file[2] == '/')
7704887Schin 			{
7714887Schin 				file[1] = file[0];
7724887Schin 				file[0] = '/';
7734887Schin 				pathcanon(file, 0);
7744887Schin 				dospath = 2;
7754887Schin 				goto again;
7764887Schin 			}
7774887Schin 			break;
7784887Schin 		case 2:
7794887Schin 			file += 2;
7804887Schin 			goto again;
7814887Schin 		}
7824887Schin 		if ((flags & (SEARCH_INCLUDE|SEARCH_NEXT)) == SEARCH_INCLUDE)
7834887Schin 		{
7848462SApril.Chin@Sun.COM 			if (!chop && pp.chop)
7858462SApril.Chin@Sun.COM 			{
7868462SApril.Chin@Sun.COM 				chop = 1;
7878462SApril.Chin@Sun.COM 				type = T_STRING;
7888462SApril.Chin@Sun.COM 				goto again;
7898462SApril.Chin@Sun.COM 			}
7904887Schin 			if (!(pp.mode & GENDEPS))
7914887Schin 			{
7924887Schin 				if (!(pp.option & ALLPOSSIBLE) || pp.in->prev->prev)
7934887Schin 					error(2, "%s: cannot find include file", file);
7944887Schin 			}
7954887Schin 			else if (!(pp.mode & INIT))
7964887Schin 			{
7974887Schin 				xp = ppsetfile(file);
7984887Schin 				if (!(xp->flags & INC_LISTED))
7994887Schin 				{
8004887Schin 					xp->flags |= INC_LISTED;
8014887Schin 					if ((pp.column + strlen(file)) >= COLUMN_MAX)
8024887Schin 					{
8034887Schin 						sfprintf(pp.filedeps.sp, " \\\n");
8044887Schin 						pp.column = COLUMN_TAB;
8054887Schin 						index = '\t';
8064887Schin 					}
8074887Schin 					else
8084887Schin 						index = ' ';
8094887Schin 					pp.column += sfprintf(pp.filedeps.sp, "%c%s", index, file);
8104887Schin 				}
8114887Schin 			}
8124887Schin 		}
8134887Schin 	}
8144887Schin 	return fd;
8154887Schin }
816