1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1997-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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;
220da2e3ebdSchin char buf[32];
221da2e3ebdSchin
222da2e3ebdSchin if (!(vm = vmopen(Vmdcheap, Vmlast, 0)))
223da2e3ebdSchin return 0;
224da2e3ebdSchin if (lib && *lib && (*lib != '-' || *(lib + 1)))
225da2e3ebdSchin {
226da2e3ebdSchin /*
227da2e3ebdSchin * grab the local part of the library id
228da2e3ebdSchin */
229da2e3ebdSchin
230da2e3ebdSchin if (s = strrchr(lib, ':'))
231da2e3ebdSchin lib = (const char*)(s + 1);
232da2e3ebdSchin i = 2 * sizeof(char**) + strlen(lib) + 5;
233da2e3ebdSchin }
234da2e3ebdSchin else
235da2e3ebdSchin {
236da2e3ebdSchin lib = 0;
237da2e3ebdSchin i = 0;
238da2e3ebdSchin }
2397c2fbfb3SApril Chin if (version && *version && (*version != '-' || *(version + 1)))
2407c2fbfb3SApril Chin version = 0;
241da2e3ebdSchin if (!(scan = vmnewof(vm, 0, Dllscan_t, 1, i)) || !(scan->tmp = sfstropen()))
242da2e3ebdSchin {
243da2e3ebdSchin vmclose(vm);
244da2e3ebdSchin return 0;
245da2e3ebdSchin }
2467c2fbfb3SApril Chin scan->vm = vm;
2477c2fbfb3SApril Chin info = dllinfo();
2487c2fbfb3SApril Chin scan->flags = info->flags;
249da2e3ebdSchin if (lib)
250da2e3ebdSchin {
251da2e3ebdSchin scan->lib = (char**)(scan + 1);
252da2e3ebdSchin s = *scan->lib = (char*)(scan->lib + 2);
253da2e3ebdSchin sfsprintf(s, i, "lib/%s", lib);
2547c2fbfb3SApril Chin if (!version && streq(info->suffix, ".dylib"))
2557c2fbfb3SApril Chin version = "0.0";
256da2e3ebdSchin }
257da2e3ebdSchin if (!name || !*name || *name == '-' && !*(name + 1))
258da2e3ebdSchin {
259da2e3ebdSchin name = (const char*)"?*";
260da2e3ebdSchin scan->flags |= DLL_MATCH_NAME;
261da2e3ebdSchin }
262da2e3ebdSchin else if (t = strrchr(name, '/'))
263da2e3ebdSchin {
264da2e3ebdSchin if (!(scan->pb = vmnewof(vm, 0, char, t - (char*)name, 2)))
265da2e3ebdSchin goto bad;
266da2e3ebdSchin memcpy(scan->pb, name, t - (char*)name);
267da2e3ebdSchin name = (const char*)(t + 1);
268da2e3ebdSchin }
269*3e14f97fSRoger A. Faulkner if (name && !version)
270*3e14f97fSRoger A. Faulkner for (t = (char*)name; *t; t++)
271*3e14f97fSRoger A. Faulkner if ((*t == '-' || *t == '.' || *t == '?') && isdigit(*(t + 1)))
272*3e14f97fSRoger A. Faulkner {
273*3e14f97fSRoger A. Faulkner if (*t != '-')
274*3e14f97fSRoger A. Faulkner scan->flags |= DLL_MATCH_VERSION;
275*3e14f97fSRoger A. Faulkner version = t + 1;
276*3e14f97fSRoger A. Faulkner if (!(s = vmnewof(vm, 0, char, t - (char*)name, 1)))
277*3e14f97fSRoger A. Faulkner goto bad;
278*3e14f97fSRoger A. Faulkner memcpy(s, name, t - (char*)name);
279*3e14f97fSRoger A. Faulkner name = (const char*)s;
280*3e14f97fSRoger A. Faulkner break;
281*3e14f97fSRoger A. Faulkner }
2827c2fbfb3SApril Chin if (!version)
283da2e3ebdSchin {
284da2e3ebdSchin scan->flags |= DLL_MATCH_VERSION;
285da2e3ebdSchin sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s", info->prefix, name, info->suffix);
286da2e3ebdSchin }
287da2e3ebdSchin else if (scan->flags & DLL_INFO_PREVER)
288da2e3ebdSchin {
289da2e3ebdSchin sfprintf(scan->tmp, "%s%s", info->prefix, name);
290da2e3ebdSchin for (s = (char*)version; *s; s++)
291da2e3ebdSchin if (isdigit(*s))
292da2e3ebdSchin sfputc(scan->tmp, *s);
293da2e3ebdSchin sfprintf(scan->tmp, "%s", info->suffix);
294da2e3ebdSchin if (!(s = sfstruse(scan->tmp)))
295da2e3ebdSchin goto bad;
296da2e3ebdSchin sfsprintf(scan->nam, sizeof(scan->nam), "%s", s);
297da2e3ebdSchin }
298da2e3ebdSchin else
299da2e3ebdSchin sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s.%s", info->prefix, name, info->suffix, version);
300da2e3ebdSchin if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
301da2e3ebdSchin {
302da2e3ebdSchin if (scan->flags & DLL_INFO_PREVER)
303da2e3ebdSchin {
304da2e3ebdSchin if (!version)
305da2e3ebdSchin version = "*([0-9_])";
306da2e3ebdSchin else
307da2e3ebdSchin {
308da2e3ebdSchin t = buf;
309da2e3ebdSchin for (s = (char*)version; *s; s++)
310da2e3ebdSchin if (isdigit(*s) && t < &buf[sizeof(buf)-1])
311da2e3ebdSchin *t++ = *s;
312da2e3ebdSchin *t = 0;
313da2e3ebdSchin version = (const char*)buf;
314da2e3ebdSchin }
315da2e3ebdSchin sfsprintf(scan->pat, sizeof(scan->pat), "%s%s%s%s", info->prefix, name, version, info->suffix);
316da2e3ebdSchin }
317da2e3ebdSchin else if (version)
318da2e3ebdSchin sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(%s([-.])%s%s|%s.%s)", info->prefix, name, strchr(version, '.') ? "@" : "?", version, info->suffix, info->suffix, version);
319da2e3ebdSchin else
320da2e3ebdSchin {
321da2e3ebdSchin version = "*([0-9.])";
322da2e3ebdSchin sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(?([-.])%s%s|%s%s)", info->prefix, name, version, info->suffix, info->suffix, version);
323da2e3ebdSchin }
324da2e3ebdSchin }
325da2e3ebdSchin scan->sp = scan->sb = (scan->lib ? scan->lib : info->sibling);
326da2e3ebdSchin scan->prelen = strlen(info->prefix);
327da2e3ebdSchin scan->suflen = strlen(info->suffix);
328da2e3ebdSchin return scan;
329da2e3ebdSchin bad:
330da2e3ebdSchin dllsclose(scan);
331da2e3ebdSchin return 0;
332da2e3ebdSchin }
333da2e3ebdSchin
334da2e3ebdSchin /*
335da2e3ebdSchin * close a scan stream
336da2e3ebdSchin */
337da2e3ebdSchin
338da2e3ebdSchin int
dllsclose(Dllscan_t * scan)339da2e3ebdSchin dllsclose(Dllscan_t* scan)
340da2e3ebdSchin {
341da2e3ebdSchin if (!scan)
342da2e3ebdSchin return -1;
343da2e3ebdSchin if (scan->fts)
344da2e3ebdSchin fts_close(scan->fts);
345da2e3ebdSchin if (scan->dict)
346da2e3ebdSchin dtclose(scan->dict);
347da2e3ebdSchin if (scan->tmp)
348da2e3ebdSchin sfclose(scan->tmp);
349da2e3ebdSchin if (scan->vm)
350da2e3ebdSchin vmclose(scan->vm);
351da2e3ebdSchin return 0;
352da2e3ebdSchin }
353da2e3ebdSchin
354da2e3ebdSchin /*
355da2e3ebdSchin * return the next scan stream entry
356da2e3ebdSchin */
357da2e3ebdSchin
358da2e3ebdSchin Dllent_t*
dllsread(register Dllscan_t * scan)359da2e3ebdSchin dllsread(register Dllscan_t* scan)
360da2e3ebdSchin {
361da2e3ebdSchin register char* p;
362da2e3ebdSchin register char* b;
363da2e3ebdSchin register char* t;
364da2e3ebdSchin register Uniq_t* u;
365da2e3ebdSchin register int n;
366da2e3ebdSchin register int m;
367da2e3ebdSchin
368da2e3ebdSchin if (scan->flags & DLL_MATCH_DONE)
369da2e3ebdSchin return 0;
370da2e3ebdSchin again:
371da2e3ebdSchin do
372da2e3ebdSchin {
373da2e3ebdSchin while (!scan->ent || !(scan->ent = scan->ent->fts_link))
374da2e3ebdSchin {
375da2e3ebdSchin if (scan->fts)
376da2e3ebdSchin {
377da2e3ebdSchin fts_close(scan->fts);
378da2e3ebdSchin scan->fts = 0;
379da2e3ebdSchin }
380da2e3ebdSchin if (!scan->pb)
381da2e3ebdSchin scan->pb = pathbin();
382da2e3ebdSchin else if (!*scan->sp)
383da2e3ebdSchin {
384da2e3ebdSchin scan->sp = scan->sb;
385da2e3ebdSchin if (!*scan->pe++)
386da2e3ebdSchin return 0;
387da2e3ebdSchin scan->pb = scan->pe;
388da2e3ebdSchin }
389da2e3ebdSchin for (p = scan->pp = scan->pb; *p && *p != ':'; p++)
390da2e3ebdSchin if (*p == '/')
391da2e3ebdSchin scan->pp = p;
392da2e3ebdSchin scan->pe = p;
393da2e3ebdSchin if (*scan->sp == bin)
394da2e3ebdSchin scan->off = sfprintf(scan->tmp, "%-.*s", scan->pe - scan->pb, scan->pb);
395da2e3ebdSchin else
396da2e3ebdSchin scan->off = sfprintf(scan->tmp, "%-.*s/%s", scan->pp - scan->pb, scan->pb, *scan->sp);
397da2e3ebdSchin scan->sp++;
398da2e3ebdSchin if (!(scan->flags & DLL_MATCH_NAME))
399da2e3ebdSchin {
400da2e3ebdSchin sfprintf(scan->tmp, "/%s", scan->nam);
401da2e3ebdSchin if (!(p = sfstruse(scan->tmp)))
402da2e3ebdSchin return 0;
403da2e3ebdSchin if (!eaccess(p, R_OK))
404da2e3ebdSchin {
405da2e3ebdSchin b = scan->nam;
406da2e3ebdSchin goto found;
407da2e3ebdSchin }
408da2e3ebdSchin if (errno != ENOENT)
409da2e3ebdSchin continue;
410da2e3ebdSchin }
411da2e3ebdSchin if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
412da2e3ebdSchin {
413da2e3ebdSchin sfstrseek(scan->tmp, scan->off, SEEK_SET);
414da2e3ebdSchin if (!(t = sfstruse(scan->tmp)))
415da2e3ebdSchin return 0;
416da2e3ebdSchin 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)))
417da2e3ebdSchin break;
418da2e3ebdSchin }
419da2e3ebdSchin }
420da2e3ebdSchin } while (!strmatch(scan->ent->fts_name, scan->pat));
421da2e3ebdSchin b = scan->ent->fts_name;
422da2e3ebdSchin sfstrseek(scan->tmp, scan->off, SEEK_SET);
423da2e3ebdSchin sfprintf(scan->tmp, "/%s", b);
424da2e3ebdSchin if (!(p = sfstruse(scan->tmp)))
425da2e3ebdSchin return 0;
426da2e3ebdSchin found:
427da2e3ebdSchin b = scan->buf + sfsprintf(scan->buf, sizeof(scan->buf), "%s", b + scan->prelen);
428da2e3ebdSchin if (!(scan->flags & DLL_INFO_PREVER))
429da2e3ebdSchin while (b > scan->buf)
430da2e3ebdSchin {
431da2e3ebdSchin if (!isdigit(*(b - 1)) && *(b - 1) != '.')
432da2e3ebdSchin break;
433da2e3ebdSchin b--;
434da2e3ebdSchin }
435da2e3ebdSchin b -= scan->suflen;
436da2e3ebdSchin if (b > (scan->buf + 2) && (*(b - 1) == 'g' || *(b - 1) == 'O') && *(b - 2) == '-')
437da2e3ebdSchin b -= 2;
438da2e3ebdSchin n = m = 0;
439da2e3ebdSchin for (t = b; t > scan->buf; t--)
440da2e3ebdSchin if (isdigit(*(t - 1)))
441da2e3ebdSchin n = 1;
442da2e3ebdSchin else if (*(t - 1) != m)
443da2e3ebdSchin {
444da2e3ebdSchin if (*(t - 1) == '.' || *(t - 1) == '-' || *(t - 1) == '_')
445da2e3ebdSchin {
446da2e3ebdSchin n = 1;
447da2e3ebdSchin if (m)
448da2e3ebdSchin {
449da2e3ebdSchin m = -1;
450da2e3ebdSchin t--;
451da2e3ebdSchin break;
452da2e3ebdSchin }
453da2e3ebdSchin m = *(t - 1);
454da2e3ebdSchin }
455da2e3ebdSchin else
456da2e3ebdSchin break;
457da2e3ebdSchin }
458da2e3ebdSchin if (n)
459da2e3ebdSchin {
460da2e3ebdSchin if (isdigit(t[0]) && isdigit(t[1]) && !isdigit(t[2]))
461da2e3ebdSchin n = (t[0] - '0') * 10 + (t[1] - '0');
462da2e3ebdSchin else if (isdigit(t[1]) && isdigit(t[2]) && !isdigit(t[3]))
463da2e3ebdSchin n = (t[1] - '0') * 10 + (t[2] - '0');
464da2e3ebdSchin else
465da2e3ebdSchin n = 0;
466da2e3ebdSchin if (n && !(n & (n - 1)))
467da2e3ebdSchin {
468da2e3ebdSchin if (!isdigit(t[0]))
469da2e3ebdSchin t++;
470da2e3ebdSchin m = *(t += 2);
471da2e3ebdSchin }
472da2e3ebdSchin if (m || (scan->flags & DLL_INFO_PREVER))
473da2e3ebdSchin b = t;
474da2e3ebdSchin }
475da2e3ebdSchin *b = 0;
476da2e3ebdSchin if (!*(b = scan->buf))
477da2e3ebdSchin goto again;
478da2e3ebdSchin if (scan->uniq)
479da2e3ebdSchin {
480da2e3ebdSchin if (!scan->dict)
481da2e3ebdSchin {
482da2e3ebdSchin scan->disc.key = offsetof(Uniq_t, name);
483da2e3ebdSchin scan->disc.size = 0;
484da2e3ebdSchin scan->disc.link = offsetof(Uniq_t, link);
485da2e3ebdSchin if (!(scan->dict = dtopen(&scan->disc, Dthash)))
486da2e3ebdSchin return 0;
487da2e3ebdSchin dtinsert(scan->dict, scan->uniq);
488da2e3ebdSchin }
489da2e3ebdSchin if (dtmatch(scan->dict, b))
490da2e3ebdSchin goto again;
491da2e3ebdSchin if (!(u = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
492da2e3ebdSchin return 0;
493da2e3ebdSchin strcpy(u->name, b);
494da2e3ebdSchin dtinsert(scan->dict, u);
495da2e3ebdSchin }
496da2e3ebdSchin else if (!(scan->flags & DLL_MATCH_NAME))
497da2e3ebdSchin scan->flags |= DLL_MATCH_DONE;
498da2e3ebdSchin else if (!(scan->uniq = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
499da2e3ebdSchin return 0;
500da2e3ebdSchin else
501da2e3ebdSchin strcpy(scan->uniq->name, b);
502da2e3ebdSchin scan->entry.name = b;
503da2e3ebdSchin scan->entry.path = p;
504da2e3ebdSchin return &scan->entry;
505da2e3ebdSchin }
506