1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1997-2012 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 
26da2e3ebdSchin #define _DLLINFO_PRIVATE_ \
27da2e3ebdSchin 	char*	sib[3]; \
28da2e3ebdSchin 	char	sibbuf[64]; \
29da2e3ebdSchin 	char	envbuf[64];
30da2e3ebdSchin 
31da2e3ebdSchin #define _DLLSCAN_PRIVATE_ \
32da2e3ebdSchin 	Dllent_t	entry; \
33da2e3ebdSchin 	Uniq_t*		uniq; \
34da2e3ebdSchin 	int		flags; \
35da2e3ebdSchin 	Vmalloc_t*	vm; \
36da2e3ebdSchin 	Dt_t*		dict; \
37da2e3ebdSchin 	Dtdisc_t	disc; \
38da2e3ebdSchin 	FTS*		fts; \
39da2e3ebdSchin 	FTSENT*		ent; \
40da2e3ebdSchin 	Sfio_t*		tmp; \
41da2e3ebdSchin 	char**		sb; \
42da2e3ebdSchin 	char**		sp; \
43da2e3ebdSchin 	char*		pb; \
44da2e3ebdSchin 	char*		pp; \
45da2e3ebdSchin 	char*		pe; \
46da2e3ebdSchin 	int		off; \
47da2e3ebdSchin 	int		prelen; \
48da2e3ebdSchin 	int		suflen; \
49da2e3ebdSchin 	char**		lib; \
50da2e3ebdSchin 	char		nam[64]; \
51da2e3ebdSchin 	char		pat[64]; \
52da2e3ebdSchin 	char		buf[64];
53da2e3ebdSchin 
54da2e3ebdSchin #define DLL_MATCH_DONE		0x8000
55da2e3ebdSchin #define DLL_MATCH_NAME		0x4000
56da2e3ebdSchin #define DLL_MATCH_VERSION	0x2000
57da2e3ebdSchin 
58da2e3ebdSchin #include <ast.h>
59da2e3ebdSchin #include <cdt.h>
60da2e3ebdSchin #include <ctype.h>
61da2e3ebdSchin #include <error.h>
62da2e3ebdSchin #include <fts.h>
63da2e3ebdSchin #include <vmalloc.h>
64da2e3ebdSchin 
65da2e3ebdSchin typedef struct Uniq_s
66da2e3ebdSchin {
67da2e3ebdSchin 	Dtlink_t	link;
68da2e3ebdSchin 	char		name[1];
69da2e3ebdSchin } Uniq_t;
70da2e3ebdSchin 
71da2e3ebdSchin #include <dlldefs.h>
72da2e3ebdSchin 
73da2e3ebdSchin static char		bin[] = "bin";
74da2e3ebdSchin static char		lib[] = "lib";
75da2e3ebdSchin 
76da2e3ebdSchin /*
77da2e3ebdSchin  * we need a sibling dir in PATH to search for dlls
78da2e3ebdSchin  * the confstr LIBPATH provides the local info
79da2e3ebdSchin  *
80da2e3ebdSchin  *	<sibling-dir>[:<env-var>[:<host-pattern>]][,...]
81da2e3ebdSchin  *
82da2e3ebdSchin  * if <host-pattern> is present then it must match confstr HOSTTYPE
83da2e3ebdSchin  */
84da2e3ebdSchin 
85da2e3ebdSchin Dllinfo_t*
dllinfo(void)86da2e3ebdSchin dllinfo(void)
87da2e3ebdSchin {
88da2e3ebdSchin 	register char*		s;
89da2e3ebdSchin 	register char*		h;
90da2e3ebdSchin 	char*			d;
91da2e3ebdSchin 	char*			v;
92da2e3ebdSchin 	char*			p;
93da2e3ebdSchin 	int			dn;
94da2e3ebdSchin 	int			vn;
95da2e3ebdSchin 	int			pn;
96da2e3ebdSchin 	char			pat[256];
97da2e3ebdSchin 
98da2e3ebdSchin 	static Dllinfo_t	info;
99da2e3ebdSchin 
100da2e3ebdSchin 	if (!info.sibling)
101da2e3ebdSchin 	{
102da2e3ebdSchin 		info.sibling = info.sib;
103da2e3ebdSchin 		if (*(s = astconf("LIBPATH", NiL, NiL)))
104da2e3ebdSchin 		{
105da2e3ebdSchin 			while (*s == ':' || *s == ',')
106da2e3ebdSchin 				s++;
107da2e3ebdSchin 			if (*s)
108da2e3ebdSchin 			{
109da2e3ebdSchin 				h = 0;
110da2e3ebdSchin 				for (;;)
111da2e3ebdSchin 				{
112da2e3ebdSchin 					for (d = s; *s && *s != ':' && *s != ','; s++);
113da2e3ebdSchin 					if (!(dn = s - d))
114da2e3ebdSchin 						d = 0;
115da2e3ebdSchin 					if (*s == ':')
116da2e3ebdSchin 					{
117da2e3ebdSchin 						for (v = ++s; *s && *s != ':' && *s != ','; s++);
118da2e3ebdSchin 						if (!(vn = s - v))
119da2e3ebdSchin 							v = 0;
120da2e3ebdSchin 						if (*s == ':')
121da2e3ebdSchin 						{
122da2e3ebdSchin 							for (p = ++s; *s && *s != ':' && *s != ','; s++);
123da2e3ebdSchin 							if (!(pn = s - p))
124da2e3ebdSchin 								p = 0;
125da2e3ebdSchin 						}
126da2e3ebdSchin 						else
127da2e3ebdSchin 							p = 0;
128da2e3ebdSchin 					}
129da2e3ebdSchin 					else
130da2e3ebdSchin 					{
131da2e3ebdSchin 						v = 0;
132da2e3ebdSchin 						p = 0;
133da2e3ebdSchin 					}
134da2e3ebdSchin 					while (*s && *s++ != ',');
135da2e3ebdSchin 					if (!*s || !p || !h && !*(h = astconf("HOSTTYPE", NiL, NiL)))
136da2e3ebdSchin 						break;
137da2e3ebdSchin 					if (pn >= sizeof(pat))
138da2e3ebdSchin 						pn = sizeof(pat) - 1;
139da2e3ebdSchin 					memcpy(pat, p, pn);
140da2e3ebdSchin 					pat[pn] = 0;
141da2e3ebdSchin 					if (strmatch(h, pat))
142da2e3ebdSchin 						break;
143da2e3ebdSchin 				}
144da2e3ebdSchin 				if (d && dn < sizeof(info.sibbuf))
145da2e3ebdSchin 				{
146da2e3ebdSchin 					memcpy(info.sibbuf, d, dn);
147da2e3ebdSchin 					info.sibling[0] = info.sibbuf;
148da2e3ebdSchin 				}
149da2e3ebdSchin 				if (v && vn < sizeof(info.envbuf))
150da2e3ebdSchin 				{
151da2e3ebdSchin 					memcpy(info.envbuf, v, vn);
152da2e3ebdSchin 					info.env = info.envbuf;
153da2e3ebdSchin 				}
154da2e3ebdSchin 			}
155da2e3ebdSchin 		}
156da2e3ebdSchin 		if (!info.sibling[0] || streq(info.sibling[0], bin))
157da2e3ebdSchin 			info.sibling[0] = bin;
158da2e3ebdSchin 		if (!streq(info.sibling[0], lib))
159da2e3ebdSchin 			info.sibling[1] = lib;
160da2e3ebdSchin 		if (!info.env)
161da2e3ebdSchin 			info.env = "LD_LIBRARY_PATH";
162da2e3ebdSchin 		info.prefix = astconf("LIBPREFIX", NiL, NiL);
163da2e3ebdSchin 		info.suffix = astconf("LIBSUFFIX", NiL, NiL);
164da2e3ebdSchin 		if (streq(info.suffix, ".dll"))
165da2e3ebdSchin 			info.flags |= DLL_INFO_PREVER;
166da2e3ebdSchin 		else
167da2e3ebdSchin 			info.flags |= DLL_INFO_DOTVER;
168da2e3ebdSchin 	}
169da2e3ebdSchin 	return &info;
170da2e3ebdSchin }
171da2e3ebdSchin 
172da2e3ebdSchin /*
173da2e3ebdSchin  * fts version sort order
174da2e3ebdSchin  * higher versions appear first
175da2e3ebdSchin  */
176da2e3ebdSchin 
177da2e3ebdSchin static int
vercmp(FTSENT * const * ap,FTSENT * const * bp)178da2e3ebdSchin vercmp(FTSENT* const* ap, FTSENT* const* bp)
179da2e3ebdSchin {
180da2e3ebdSchin 	register unsigned char*	a = (unsigned char*)(*ap)->fts_name;
181da2e3ebdSchin 	register unsigned char*	b = (unsigned char*)(*bp)->fts_name;
182da2e3ebdSchin 	register int		n;
183da2e3ebdSchin 	register int		m;
184da2e3ebdSchin 	char*			e;
185da2e3ebdSchin 
186da2e3ebdSchin 	for (;;)
187da2e3ebdSchin 	{
188da2e3ebdSchin 		if (isdigit(*a) && isdigit(*b))
189da2e3ebdSchin 		{
190da2e3ebdSchin 			m = strtol((char*)a, &e, 10);
191da2e3ebdSchin 			a = (unsigned char*)e;
192da2e3ebdSchin 			n = strtol((char*)b, &e, 10);
193da2e3ebdSchin 			b = (unsigned char*)e;
194da2e3ebdSchin 			if (n -= m)
195da2e3ebdSchin 				return n;
196da2e3ebdSchin 		}
197da2e3ebdSchin 		if (n = *a - *b)
198da2e3ebdSchin 			return n;
199da2e3ebdSchin 		if (!*a++)
200da2e3ebdSchin 			return *b ? 0 : -1;
201da2e3ebdSchin 		if (!*b++)
202da2e3ebdSchin 			return 1;
203da2e3ebdSchin 	}
204da2e3ebdSchin 	/*NOTREACHED*/
205da2e3ebdSchin }
206da2e3ebdSchin 
207da2e3ebdSchin /*
208da2e3ebdSchin  * open a scan stream
209da2e3ebdSchin  */
210da2e3ebdSchin 
211da2e3ebdSchin Dllscan_t*
dllsopen(const char * lib,const char * name,const char * version)212da2e3ebdSchin dllsopen(const char* lib, const char* name, const char* version)
213da2e3ebdSchin {
214da2e3ebdSchin 	register char*	s;
215da2e3ebdSchin 	register char*	t;
216da2e3ebdSchin 	Dllscan_t*	scan;
217da2e3ebdSchin 	Dllinfo_t*	info;
218da2e3ebdSchin 	Vmalloc_t*	vm;
219da2e3ebdSchin 	int		i;
220*b30d1939SAndy Fiddaman 	int		j;
221*b30d1939SAndy Fiddaman 	int		k;
222da2e3ebdSchin 	char		buf[32];
223da2e3ebdSchin 
224da2e3ebdSchin 	if (!(vm = vmopen(Vmdcheap, Vmlast, 0)))
225da2e3ebdSchin 		return 0;
226da2e3ebdSchin 	if (lib && *lib && (*lib != '-' || *(lib + 1)))
227da2e3ebdSchin 	{
228da2e3ebdSchin 		/*
229da2e3ebdSchin 		 * grab the local part of the library id
230da2e3ebdSchin 		 */
231da2e3ebdSchin 
232da2e3ebdSchin 		if (s = strrchr(lib, ':'))
233da2e3ebdSchin 			lib = (const char*)(s + 1);
234da2e3ebdSchin 		i = 2 * sizeof(char**) + strlen(lib) + 5;
235da2e3ebdSchin 	}
236da2e3ebdSchin 	else
237da2e3ebdSchin 	{
238da2e3ebdSchin 		lib = 0;
239da2e3ebdSchin 		i = 0;
240da2e3ebdSchin 	}
241*b30d1939SAndy Fiddaman 	if (version && (!*version || *version == '-' && !*(version + 1)))
2427c2fbfb3SApril Chin 		version = 0;
243da2e3ebdSchin 	if (!(scan = vmnewof(vm, 0, Dllscan_t, 1, i)) || !(scan->tmp = sfstropen()))
244da2e3ebdSchin 	{
245da2e3ebdSchin 		vmclose(vm);
246da2e3ebdSchin 		return 0;
247da2e3ebdSchin 	}
2487c2fbfb3SApril Chin 	scan->vm = vm;
2497c2fbfb3SApril Chin 	info = dllinfo();
2507c2fbfb3SApril Chin 	scan->flags = info->flags;
251da2e3ebdSchin 	if (lib)
252da2e3ebdSchin 	{
253da2e3ebdSchin 		scan->lib = (char**)(scan + 1);
254da2e3ebdSchin 		s = *scan->lib = (char*)(scan->lib + 2);
255da2e3ebdSchin 		sfsprintf(s, i, "lib/%s", lib);
2567c2fbfb3SApril Chin 		if (!version && streq(info->suffix, ".dylib"))
2577c2fbfb3SApril Chin 			version = "0.0";
258da2e3ebdSchin 	}
259da2e3ebdSchin 	if (!name || !*name || *name == '-' && !*(name + 1))
260da2e3ebdSchin 	{
261da2e3ebdSchin 		name = (const char*)"?*";
262da2e3ebdSchin 		scan->flags |= DLL_MATCH_NAME;
263da2e3ebdSchin 	}
264da2e3ebdSchin 	else if (t = strrchr(name, '/'))
265da2e3ebdSchin 	{
266da2e3ebdSchin 		if (!(scan->pb = vmnewof(vm, 0, char, t - (char*)name, 2)))
267da2e3ebdSchin 			goto bad;
268da2e3ebdSchin 		memcpy(scan->pb, name, t - (char*)name);
269da2e3ebdSchin 		name = (const char*)(t + 1);
270da2e3ebdSchin 	}
271*b30d1939SAndy Fiddaman 	if (name)
272*b30d1939SAndy Fiddaman 	{
273*b30d1939SAndy Fiddaman 		i = strlen(name);
274*b30d1939SAndy Fiddaman 		j = strlen(info->prefix);
275*b30d1939SAndy Fiddaman 		if (!j || i > j && strneq(name, info->prefix, j))
276*b30d1939SAndy Fiddaman 		{
277*b30d1939SAndy Fiddaman 			k = strlen(info->suffix);
278*b30d1939SAndy Fiddaman 			if (i > k && streq(name + i - k, info->suffix))
2793e14f97fSRoger A. Faulkner 			{
280*b30d1939SAndy Fiddaman 				i -= j + k;
281*b30d1939SAndy Fiddaman 				if (!(t = vmnewof(vm, 0, char, i, 1)))
2823e14f97fSRoger A. Faulkner 					goto bad;
283*b30d1939SAndy Fiddaman 				memcpy(t, name + j, i);
284*b30d1939SAndy Fiddaman 				t[i] = 0;
285*b30d1939SAndy Fiddaman 				name = (const char*)t;
2863e14f97fSRoger A. Faulkner 			}
287*b30d1939SAndy Fiddaman 		}
288*b30d1939SAndy Fiddaman 		if (!version)
289*b30d1939SAndy Fiddaman 			for (t = (char*)name; *t; t++)
290*b30d1939SAndy Fiddaman 				if ((*t == '-' || *t == '.' || *t == '?') && isdigit(*(t + 1)))
291*b30d1939SAndy Fiddaman 				{
292*b30d1939SAndy Fiddaman 					if (*t != '-')
293*b30d1939SAndy Fiddaman 						scan->flags |= DLL_MATCH_VERSION;
294*b30d1939SAndy Fiddaman 					version = t + 1;
295*b30d1939SAndy Fiddaman 					if (!(s = vmnewof(vm, 0, char, t - (char*)name, 1)))
296*b30d1939SAndy Fiddaman 						goto bad;
297*b30d1939SAndy Fiddaman 					memcpy(s, name, t - (char*)name);
298*b30d1939SAndy Fiddaman 					name = (const char*)s;
299*b30d1939SAndy Fiddaman 					break;
300*b30d1939SAndy Fiddaman 				}
301*b30d1939SAndy Fiddaman 	}
3027c2fbfb3SApril Chin 	if (!version)
303da2e3ebdSchin 	{
304da2e3ebdSchin 		scan->flags |= DLL_MATCH_VERSION;
305da2e3ebdSchin 		sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s", info->prefix, name, info->suffix);
306da2e3ebdSchin 	}
307da2e3ebdSchin 	else if (scan->flags & DLL_INFO_PREVER)
308da2e3ebdSchin 	{
309da2e3ebdSchin 		sfprintf(scan->tmp, "%s%s", info->prefix, name);
310da2e3ebdSchin 		for (s = (char*)version; *s; s++)
311da2e3ebdSchin 			if (isdigit(*s))
312da2e3ebdSchin 				sfputc(scan->tmp, *s);
313da2e3ebdSchin 		sfprintf(scan->tmp, "%s", info->suffix);
314da2e3ebdSchin 		if (!(s = sfstruse(scan->tmp)))
315da2e3ebdSchin 			goto bad;
316da2e3ebdSchin 		sfsprintf(scan->nam, sizeof(scan->nam), "%s", s);
317da2e3ebdSchin 	}
318da2e3ebdSchin 	else
319da2e3ebdSchin 		sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s.%s", info->prefix, name, info->suffix, version);
320da2e3ebdSchin 	if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
321da2e3ebdSchin 	{
322da2e3ebdSchin 		if (scan->flags & DLL_INFO_PREVER)
323da2e3ebdSchin 		{
324da2e3ebdSchin 			if (!version)
325da2e3ebdSchin 				version = "*([0-9_])";
326da2e3ebdSchin 			else
327da2e3ebdSchin 			{
328da2e3ebdSchin 				t = buf;
329da2e3ebdSchin 				for (s = (char*)version; *s; s++)
330da2e3ebdSchin 					if (isdigit(*s) && t < &buf[sizeof(buf)-1])
331da2e3ebdSchin 						*t++ = *s;
332da2e3ebdSchin 				*t = 0;
333da2e3ebdSchin 				version = (const char*)buf;
334da2e3ebdSchin 			}
335da2e3ebdSchin 			sfsprintf(scan->pat, sizeof(scan->pat), "%s%s%s%s", info->prefix, name, version, info->suffix);
336da2e3ebdSchin 		}
337da2e3ebdSchin 		else if (version)
338da2e3ebdSchin 			sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(%s([-.])%s%s|%s.%s)", info->prefix, name, strchr(version, '.') ? "@" : "?", version, info->suffix, info->suffix, version);
339da2e3ebdSchin 		else
340da2e3ebdSchin 		{
341da2e3ebdSchin 			version = "*([0-9.])";
342da2e3ebdSchin 			sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(?([-.])%s%s|%s%s)", info->prefix, name, version, info->suffix, info->suffix, version);
343da2e3ebdSchin 		}
344da2e3ebdSchin 	}
345da2e3ebdSchin 	scan->sp = scan->sb = (scan->lib ? scan->lib : info->sibling);
346da2e3ebdSchin 	scan->prelen = strlen(info->prefix);
347da2e3ebdSchin 	scan->suflen = strlen(info->suffix);
348da2e3ebdSchin 	return scan;
349da2e3ebdSchin  bad:
350da2e3ebdSchin 	dllsclose(scan);
351da2e3ebdSchin 	return 0;
352da2e3ebdSchin }
353da2e3ebdSchin 
354da2e3ebdSchin /*
355da2e3ebdSchin  * close a scan stream
356da2e3ebdSchin  */
357da2e3ebdSchin 
358da2e3ebdSchin int
dllsclose(Dllscan_t * scan)359da2e3ebdSchin dllsclose(Dllscan_t* scan)
360da2e3ebdSchin {
361da2e3ebdSchin 	if (!scan)
362da2e3ebdSchin 		return -1;
363da2e3ebdSchin 	if (scan->fts)
364da2e3ebdSchin 		fts_close(scan->fts);
365da2e3ebdSchin 	if (scan->dict)
366da2e3ebdSchin 		dtclose(scan->dict);
367da2e3ebdSchin 	if (scan->tmp)
368da2e3ebdSchin 		sfclose(scan->tmp);
369da2e3ebdSchin 	if (scan->vm)
370da2e3ebdSchin 		vmclose(scan->vm);
371da2e3ebdSchin 	return 0;
372da2e3ebdSchin }
373da2e3ebdSchin 
374da2e3ebdSchin /*
375da2e3ebdSchin  * return the next scan stream entry
376da2e3ebdSchin  */
377da2e3ebdSchin 
378da2e3ebdSchin Dllent_t*
dllsread(register Dllscan_t * scan)379da2e3ebdSchin dllsread(register Dllscan_t* scan)
380da2e3ebdSchin {
381da2e3ebdSchin 	register char*		p;
382da2e3ebdSchin 	register char*		b;
383da2e3ebdSchin 	register char*		t;
384da2e3ebdSchin 	register Uniq_t*	u;
385da2e3ebdSchin 	register int		n;
386da2e3ebdSchin 	register int		m;
387da2e3ebdSchin 
388da2e3ebdSchin 	if (scan->flags & DLL_MATCH_DONE)
389da2e3ebdSchin 		return 0;
390da2e3ebdSchin  again:
391da2e3ebdSchin 	do
392da2e3ebdSchin 	{
393da2e3ebdSchin 		while (!scan->ent || !(scan->ent = scan->ent->fts_link))
394da2e3ebdSchin 		{
395da2e3ebdSchin 			if (scan->fts)
396da2e3ebdSchin 			{
397da2e3ebdSchin 				fts_close(scan->fts);
398da2e3ebdSchin 				scan->fts = 0;
399da2e3ebdSchin 			}
400da2e3ebdSchin 			if (!scan->pb)
401da2e3ebdSchin 				scan->pb = pathbin();
402da2e3ebdSchin 			else if (!*scan->sp)
403da2e3ebdSchin 			{
404da2e3ebdSchin 				scan->sp = scan->sb;
405da2e3ebdSchin 				if (!*scan->pe++)
406da2e3ebdSchin 					return 0;
407da2e3ebdSchin 				scan->pb = scan->pe;
408da2e3ebdSchin 			}
409da2e3ebdSchin 			for (p = scan->pp = scan->pb; *p && *p != ':'; p++)
410da2e3ebdSchin 				if (*p == '/')
411da2e3ebdSchin 					scan->pp = p;
412da2e3ebdSchin 			scan->pe = p;
413da2e3ebdSchin 			if (*scan->sp == bin)
414da2e3ebdSchin 				scan->off = sfprintf(scan->tmp, "%-.*s", scan->pe - scan->pb, scan->pb);
415da2e3ebdSchin 			else
416da2e3ebdSchin 				scan->off = sfprintf(scan->tmp, "%-.*s/%s", scan->pp - scan->pb, scan->pb, *scan->sp);
417da2e3ebdSchin 			scan->sp++;
418da2e3ebdSchin 			if (!(scan->flags & DLL_MATCH_NAME))
419da2e3ebdSchin 			{
420da2e3ebdSchin 				sfprintf(scan->tmp, "/%s", scan->nam);
421da2e3ebdSchin 				if (!(p = sfstruse(scan->tmp)))
422da2e3ebdSchin 					return 0;
423da2e3ebdSchin 				if (!eaccess(p, R_OK))
424da2e3ebdSchin 				{
425da2e3ebdSchin 					b = scan->nam;
426da2e3ebdSchin 					goto found;
427da2e3ebdSchin 				}
428da2e3ebdSchin 				if (errno != ENOENT)
429da2e3ebdSchin 					continue;
430da2e3ebdSchin 			}
431da2e3ebdSchin 			if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
432da2e3ebdSchin 			{
433da2e3ebdSchin 				sfstrseek(scan->tmp, scan->off, SEEK_SET);
434da2e3ebdSchin 				if (!(t = sfstruse(scan->tmp)))
435da2e3ebdSchin 					return 0;
436da2e3ebdSchin 				if ((scan->fts = fts_open((char**)t, FTS_LOGICAL|FTS_NOPOSTORDER|FTS_ONEPATH, vercmp)) && (scan->ent = fts_read(scan->fts)) && (scan->ent = fts_children(scan->fts, FTS_NOSTAT)))
437da2e3ebdSchin 					break;
438da2e3ebdSchin 			}
439da2e3ebdSchin 		}
440da2e3ebdSchin 	} while (!strmatch(scan->ent->fts_name, scan->pat));
441da2e3ebdSchin 	b = scan->ent->fts_name;
442da2e3ebdSchin 	sfstrseek(scan->tmp, scan->off, SEEK_SET);
443da2e3ebdSchin 	sfprintf(scan->tmp, "/%s", b);
444da2e3ebdSchin 	if (!(p = sfstruse(scan->tmp)))
445da2e3ebdSchin 		return 0;
446da2e3ebdSchin  found:
447da2e3ebdSchin 	b = scan->buf + sfsprintf(scan->buf, sizeof(scan->buf), "%s", b + scan->prelen);
448da2e3ebdSchin 	if (!(scan->flags & DLL_INFO_PREVER))
449da2e3ebdSchin 		while (b > scan->buf)
450da2e3ebdSchin 		{
451da2e3ebdSchin 			if (!isdigit(*(b - 1)) && *(b - 1) != '.')
452da2e3ebdSchin 				break;
453da2e3ebdSchin 			b--;
454da2e3ebdSchin 		}
455da2e3ebdSchin 	b -= scan->suflen;
456da2e3ebdSchin 	if (b > (scan->buf + 2) && (*(b - 1) == 'g' || *(b - 1) == 'O') && *(b - 2) == '-')
457da2e3ebdSchin 		b -= 2;
458da2e3ebdSchin 	n = m = 0;
459da2e3ebdSchin 	for (t = b; t > scan->buf; t--)
460da2e3ebdSchin 		if (isdigit(*(t - 1)))
461da2e3ebdSchin 			n = 1;
462da2e3ebdSchin 		else if (*(t - 1) != m)
463da2e3ebdSchin 		{
464da2e3ebdSchin 			if (*(t - 1) == '.' || *(t - 1) == '-' || *(t - 1) == '_')
465da2e3ebdSchin 			{
466da2e3ebdSchin 				n = 1;
467da2e3ebdSchin 				if (m)
468da2e3ebdSchin 				{
469da2e3ebdSchin 					m = -1;
470da2e3ebdSchin 					t--;
471da2e3ebdSchin 					break;
472da2e3ebdSchin 				}
473da2e3ebdSchin 				m = *(t - 1);
474da2e3ebdSchin 			}
475da2e3ebdSchin 			else
476da2e3ebdSchin 				break;
477da2e3ebdSchin 		}
478da2e3ebdSchin 	if (n)
479da2e3ebdSchin 	{
480da2e3ebdSchin 		if (isdigit(t[0]) && isdigit(t[1]) && !isdigit(t[2]))
481da2e3ebdSchin 			n = (t[0] - '0') * 10 + (t[1] - '0');
482da2e3ebdSchin 		else if (isdigit(t[1]) && isdigit(t[2]) && !isdigit(t[3]))
483da2e3ebdSchin 			n = (t[1] - '0') * 10 + (t[2] - '0');
484da2e3ebdSchin 		else
485da2e3ebdSchin 			n = 0;
486da2e3ebdSchin 		if (n && !(n & (n - 1)))
487da2e3ebdSchin 		{
488da2e3ebdSchin 			if (!isdigit(t[0]))
489da2e3ebdSchin 				t++;
490da2e3ebdSchin 			m = *(t += 2);
491da2e3ebdSchin 		}
492da2e3ebdSchin 		if (m || (scan->flags & DLL_INFO_PREVER))
493da2e3ebdSchin 			b = t;
494da2e3ebdSchin 	}
495da2e3ebdSchin 	*b = 0;
496da2e3ebdSchin 	if (!*(b = scan->buf))
497da2e3ebdSchin 		goto again;
498da2e3ebdSchin 	if (scan->uniq)
499da2e3ebdSchin 	{
500da2e3ebdSchin 		if (!scan->dict)
501da2e3ebdSchin 		{
502da2e3ebdSchin 			scan->disc.key = offsetof(Uniq_t, name);
503da2e3ebdSchin 			scan->disc.size = 0;
504da2e3ebdSchin 			scan->disc.link = offsetof(Uniq_t, link);
505*b30d1939SAndy Fiddaman 			if (!(scan->dict = dtopen(&scan->disc, Dtset)))
506da2e3ebdSchin 				return 0;
507da2e3ebdSchin 			dtinsert(scan->dict, scan->uniq);
508da2e3ebdSchin 		}
509da2e3ebdSchin 		if (dtmatch(scan->dict, b))
510da2e3ebdSchin 			goto again;
511da2e3ebdSchin 		if (!(u = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
512da2e3ebdSchin 			return 0;
513da2e3ebdSchin 		strcpy(u->name, b);
514da2e3ebdSchin 		dtinsert(scan->dict, u);
515da2e3ebdSchin 	}
516da2e3ebdSchin 	else if (!(scan->flags & DLL_MATCH_NAME))
517da2e3ebdSchin 		scan->flags |= DLL_MATCH_DONE;
518da2e3ebdSchin 	else if (!(scan->uniq = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
519da2e3ebdSchin 		return 0;
520da2e3ebdSchin 	else
521da2e3ebdSchin 		strcpy(scan->uniq->name, b);
522da2e3ebdSchin 	scan->entry.name = b;
523da2e3ebdSchin 	scan->entry.path = p;
524*b30d1939SAndy Fiddaman 	errorf("dll", NiL, -1, "dllsread: %s bound to %s", b, p);
525da2e3ebdSchin 	return &scan->entry;
526da2e3ebdSchin }
527