1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1997-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
19 ***********************************************************************/
26 #define _DLLINFO_PRIVATE_ \
31 #define _DLLSCAN_PRIVATE_ \
54 #define DLL_MATCH_DONE 0x8000
55 #define DLL_MATCH_NAME 0x4000
56 #define DLL_MATCH_VERSION 0x2000
73 static char bin
[] = "bin";
74 static char lib
[] = "lib";
77 * we need a sibling dir in PATH to search for dlls
78 * the confstr LIBPATH provides the local info
80 * <sibling-dir>[:<env-var>[:<host-pattern>]][,...]
82 * if <host-pattern> is present then it must match confstr HOSTTYPE
98 static Dllinfo_t info
;
102 info
.sibling
= info
.sib
;
103 if (*(s
= astconf("LIBPATH", NiL
, NiL
)))
105 while (*s
== ':' || *s
== ',')
112 for (d
= s
; *s
&& *s
!= ':' && *s
!= ','; s
++);
117 for (v
= ++s
; *s
&& *s
!= ':' && *s
!= ','; s
++);
122 for (p
= ++s
; *s
&& *s
!= ':' && *s
!= ','; s
++);
134 while (*s
&& *s
++ != ',');
135 if (!*s
|| !p
|| !h
&& !*(h
= astconf("HOSTTYPE", NiL
, NiL
)))
137 if (pn
>= sizeof(pat
))
138 pn
= sizeof(pat
) - 1;
141 if (strmatch(h
, pat
))
144 if (d
&& dn
< sizeof(info
.sibbuf
))
146 memcpy(info
.sibbuf
, d
, dn
);
147 info
.sibling
[0] = info
.sibbuf
;
149 if (v
&& vn
< sizeof(info
.envbuf
))
151 memcpy(info
.envbuf
, v
, vn
);
152 info
.env
= info
.envbuf
;
156 if (!info
.sibling
[0] || streq(info
.sibling
[0], bin
))
157 info
.sibling
[0] = bin
;
158 if (!streq(info
.sibling
[0], lib
))
159 info
.sibling
[1] = lib
;
161 info
.env
= "LD_LIBRARY_PATH";
162 info
.prefix
= astconf("LIBPREFIX", NiL
, NiL
);
163 info
.suffix
= astconf("LIBSUFFIX", NiL
, NiL
);
164 if (streq(info
.suffix
, ".dll"))
165 info
.flags
|= DLL_INFO_PREVER
;
167 info
.flags
|= DLL_INFO_DOTVER
;
173 * fts version sort order
174 * higher versions appear first
178 vercmp(FTSENT
* const* ap
, FTSENT
* const* bp
)
180 register unsigned char* a
= (unsigned char*)(*ap
)->fts_name
;
181 register unsigned char* b
= (unsigned char*)(*bp
)->fts_name
;
188 if (isdigit(*a
) && isdigit(*b
))
190 m
= strtol((char*)a
, &e
, 10);
191 a
= (unsigned char*)e
;
192 n
= strtol((char*)b
, &e
, 10);
193 b
= (unsigned char*)e
;
212 dllsopen(const char* lib
, const char* name
, const char* version
)
222 if (!(vm
= vmopen(Vmdcheap
, Vmlast
, 0)))
224 if (lib
&& *lib
&& (*lib
!= '-' || *(lib
+ 1)))
227 * grab the local part of the library id
230 if (s
= strrchr(lib
, ':'))
231 lib
= (const char*)(s
+ 1);
232 i
= 2 * sizeof(char**) + strlen(lib
) + 5;
239 if (version
&& *version
&& (*version
!= '-' || *(version
+ 1)))
241 if (!(scan
= vmnewof(vm
, 0, Dllscan_t
, 1, i
)) || !(scan
->tmp
= sfstropen()))
248 scan
->flags
= info
->flags
;
251 scan
->lib
= (char**)(scan
+ 1);
252 s
= *scan
->lib
= (char*)(scan
->lib
+ 2);
253 sfsprintf(s
, i
, "lib/%s", lib
);
254 if (!version
&& streq(info
->suffix
, ".dylib"))
257 if (!name
|| !*name
|| *name
== '-' && !*(name
+ 1))
259 name
= (const char*)"?*";
260 scan
->flags
|= DLL_MATCH_NAME
;
262 else if (t
= strrchr(name
, '/'))
264 if (!(scan
->pb
= vmnewof(vm
, 0, char, t
- (char*)name
, 2)))
266 memcpy(scan
->pb
, name
, t
- (char*)name
);
267 name
= (const char*)(t
+ 1);
269 if (name
&& !version
)
270 for (t
= (char*)name
; *t
; t
++)
271 if ((*t
== '-' || *t
== '.' || *t
== '?') && isdigit(*(t
+ 1)))
274 scan
->flags
|= DLL_MATCH_VERSION
;
276 if (!(s
= vmnewof(vm
, 0, char, t
- (char*)name
, 1)))
278 memcpy(s
, name
, t
- (char*)name
);
279 name
= (const char*)s
;
284 scan
->flags
|= DLL_MATCH_VERSION
;
285 sfsprintf(scan
->nam
, sizeof(scan
->nam
), "%s%s%s", info
->prefix
, name
, info
->suffix
);
287 else if (scan
->flags
& DLL_INFO_PREVER
)
289 sfprintf(scan
->tmp
, "%s%s", info
->prefix
, name
);
290 for (s
= (char*)version
; *s
; s
++)
292 sfputc(scan
->tmp
, *s
);
293 sfprintf(scan
->tmp
, "%s", info
->suffix
);
294 if (!(s
= sfstruse(scan
->tmp
)))
296 sfsprintf(scan
->nam
, sizeof(scan
->nam
), "%s", s
);
299 sfsprintf(scan
->nam
, sizeof(scan
->nam
), "%s%s%s.%s", info
->prefix
, name
, info
->suffix
, version
);
300 if (scan
->flags
& (DLL_MATCH_NAME
|DLL_MATCH_VERSION
))
302 if (scan
->flags
& DLL_INFO_PREVER
)
305 version
= "*([0-9_])";
309 for (s
= (char*)version
; *s
; s
++)
310 if (isdigit(*s
) && t
< &buf
[sizeof(buf
)-1])
313 version
= (const char*)buf
;
315 sfsprintf(scan
->pat
, sizeof(scan
->pat
), "%s%s%s%s", info
->prefix
, name
, version
, info
->suffix
);
318 sfsprintf(scan
->pat
, sizeof(scan
->pat
), "%s%s@(%s([-.])%s%s|%s.%s)", info
->prefix
, name
, strchr(version
, '.') ? "@" : "?", version
, info
->suffix
, info
->suffix
, version
);
321 version
= "*([0-9.])";
322 sfsprintf(scan
->pat
, sizeof(scan
->pat
), "%s%s@(?([-.])%s%s|%s%s)", info
->prefix
, name
, version
, info
->suffix
, info
->suffix
, version
);
325 scan
->sp
= scan
->sb
= (scan
->lib
? scan
->lib
: info
->sibling
);
326 scan
->prelen
= strlen(info
->prefix
);
327 scan
->suflen
= strlen(info
->suffix
);
335 * close a scan stream
339 dllsclose(Dllscan_t
* scan
)
344 fts_close(scan
->fts
);
355 * return the next scan stream entry
359 dllsread(register Dllscan_t
* scan
)
368 if (scan
->flags
& DLL_MATCH_DONE
)
373 while (!scan
->ent
|| !(scan
->ent
= scan
->ent
->fts_link
))
377 fts_close(scan
->fts
);
381 scan
->pb
= pathbin();
389 for (p
= scan
->pp
= scan
->pb
; *p
&& *p
!= ':'; p
++)
393 if (*scan
->sp
== bin
)
394 scan
->off
= sfprintf(scan
->tmp
, "%-.*s", scan
->pe
- scan
->pb
, scan
->pb
);
396 scan
->off
= sfprintf(scan
->tmp
, "%-.*s/%s", scan
->pp
- scan
->pb
, scan
->pb
, *scan
->sp
);
398 if (!(scan
->flags
& DLL_MATCH_NAME
))
400 sfprintf(scan
->tmp
, "/%s", scan
->nam
);
401 if (!(p
= sfstruse(scan
->tmp
)))
403 if (!eaccess(p
, R_OK
))
411 if (scan
->flags
& (DLL_MATCH_NAME
|DLL_MATCH_VERSION
))
413 sfstrseek(scan
->tmp
, scan
->off
, SEEK_SET
);
414 if (!(t
= sfstruse(scan
->tmp
)))
416 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
)))
420 } while (!strmatch(scan
->ent
->fts_name
, scan
->pat
));
421 b
= scan
->ent
->fts_name
;
422 sfstrseek(scan
->tmp
, scan
->off
, SEEK_SET
);
423 sfprintf(scan
->tmp
, "/%s", b
);
424 if (!(p
= sfstruse(scan
->tmp
)))
427 b
= scan
->buf
+ sfsprintf(scan
->buf
, sizeof(scan
->buf
), "%s", b
+ scan
->prelen
);
428 if (!(scan
->flags
& DLL_INFO_PREVER
))
429 while (b
> scan
->buf
)
431 if (!isdigit(*(b
- 1)) && *(b
- 1) != '.')
436 if (b
> (scan
->buf
+ 2) && (*(b
- 1) == 'g' || *(b
- 1) == 'O') && *(b
- 2) == '-')
439 for (t
= b
; t
> scan
->buf
; t
--)
440 if (isdigit(*(t
- 1)))
442 else if (*(t
- 1) != m
)
444 if (*(t
- 1) == '.' || *(t
- 1) == '-' || *(t
- 1) == '_')
460 if (isdigit(t
[0]) && isdigit(t
[1]) && !isdigit(t
[2]))
461 n
= (t
[0] - '0') * 10 + (t
[1] - '0');
462 else if (isdigit(t
[1]) && isdigit(t
[2]) && !isdigit(t
[3]))
463 n
= (t
[1] - '0') * 10 + (t
[2] - '0');
466 if (n
&& !(n
& (n
- 1)))
472 if (m
|| (scan
->flags
& DLL_INFO_PREVER
))
476 if (!*(b
= scan
->buf
))
482 scan
->disc
.key
= offsetof(Uniq_t
, name
);
484 scan
->disc
.link
= offsetof(Uniq_t
, link
);
485 if (!(scan
->dict
= dtopen(&scan
->disc
, Dthash
)))
487 dtinsert(scan
->dict
, scan
->uniq
);
489 if (dtmatch(scan
->dict
, b
))
491 if (!(u
= vmnewof(scan
->vm
, 0, Uniq_t
, 1, strlen(b
))))
494 dtinsert(scan
->dict
, u
);
496 else if (!(scan
->flags
& DLL_MATCH_NAME
))
497 scan
->flags
|= DLL_MATCH_DONE
;
498 else if (!(scan
->uniq
= vmnewof(scan
->vm
, 0, Uniq_t
, 1, strlen(b
))))
501 strcpy(scan
->uniq
->name
, b
);
502 scan
->entry
.name
= b
;
503 scan
->entry
.path
= p
;