1 |
/* ASCEND modelling environment |
2 |
Copyright (C) 2006 Carnegie Mellon University |
3 |
|
4 |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2, or (at your option) |
7 |
any later version. |
8 |
|
9 |
This program is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
13 |
|
14 |
You should have received a copy of the GNU General Public License |
15 |
along with this program; if not, write to the Free Software |
16 |
Foundation, Inc., 59 Temple Place - Suite 330, |
17 |
Boston, MA 02111-1307, USA. |
18 |
*//** |
19 |
@file |
20 |
|
21 |
This file *should* support unix/linux-style systems (dlfcn.h) |
22 |
and Windows. |
23 |
|
24 |
Note that under many systems, profiling does not work |
25 |
with dynamic libraries! |
26 |
*/ |
27 |
|
28 |
#include <stdio.h> |
29 |
#include <stdlib.h> |
30 |
#include <stdarg.h> |
31 |
#include "ascConfig.h" |
32 |
#include "error.h" |
33 |
#include "ascPrint.h" |
34 |
#include "ascPanic.h" |
35 |
#include "ascMalloc.h" |
36 |
#include "ascDynaLoad.h" |
37 |
#include "ascEnvVar.h" |
38 |
|
39 |
#include <general/env.h> |
40 |
#include <general/ospath.h> |
41 |
#include <compiler/instance_enum.h> |
42 |
#include <general/list.h> |
43 |
#include <compiler/extfunc.h> |
44 |
#include <compiler/importhandler.h> |
45 |
|
46 |
typedef int (*ExternalLibraryRegister_fptr_t)(void); |
47 |
|
48 |
/*-------------------------------------- |
49 |
GENERIC STUFF |
50 |
*/ |
51 |
|
52 |
struct ascend_dlrecord { |
53 |
char *path; /* library name */ |
54 |
void *dlreturn; /* return from dlopen */ |
55 |
struct ascend_dlrecord *next; |
56 |
}; |
57 |
|
58 |
/* Linked list of library names & dlopen() return values. */ |
59 |
static struct ascend_dlrecord *g_ascend_dllist = NULL; |
60 |
|
61 |
/* |
62 |
* Adds a record of the path and handle to the list. |
63 |
* If it fails to do this, returns 1, else 0. |
64 |
*/ |
65 |
static int AscAddRecord(void *dlreturn, CONST char *path){ |
66 |
struct ascend_dlrecord *new; |
67 |
char *keeppath; |
68 |
if (dlreturn == NULL || path == NULL) { |
69 |
return 1; |
70 |
} |
71 |
keeppath = ASC_STRDUP((char *)path); |
72 |
if (keeppath==NULL) return 1; |
73 |
new = ASC_NEW(struct ascend_dlrecord); |
74 |
if (new==NULL) { |
75 |
ascfree(keeppath); |
76 |
return 1; |
77 |
} |
78 |
new->next = g_ascend_dllist; /* insert at head */ |
79 |
g_ascend_dllist = new; |
80 |
new->path = keeppath; |
81 |
new->dlreturn = dlreturn; |
82 |
return 0; |
83 |
} |
84 |
|
85 |
/* |
86 |
* Finds a record of the path given and returns the associated handle. |
87 |
* If it fails to do this, returns NULL. |
88 |
*/ |
89 |
static |
90 |
void *AscFindDLRecord(CONST char *path) |
91 |
{ |
92 |
struct ascend_dlrecord *new; |
93 |
if (path == NULL) { |
94 |
return NULL; |
95 |
} |
96 |
new = g_ascend_dllist; |
97 |
while (new != NULL && strcmp(new->path,path) != 0) { |
98 |
/* advance new until no more new or new with path found */ |
99 |
new = new->next; |
100 |
} |
101 |
return (new != NULL) ? new->dlreturn : NULL; |
102 |
} |
103 |
|
104 |
/* |
105 |
* Finds and returns the handle to path, if one matches, and |
106 |
* deletes the record from the list. Returns NULL if not found. |
107 |
*/ |
108 |
static |
109 |
void *AscDeleteRecord(CONST char *path) |
110 |
{ |
111 |
struct ascend_dlrecord *nextptr, *lastptr, *old; |
112 |
void *dlreturn = NULL; |
113 |
|
114 |
if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL; |
115 |
|
116 |
if (strcmp(path,g_ascend_dllist->path)==0) { |
117 |
/* head case */ |
118 |
old = g_ascend_dllist; |
119 |
g_ascend_dllist = old->next; |
120 |
dlreturn = old->dlreturn; |
121 |
ascfree(old->path); |
122 |
ascfree(old); |
123 |
} else { |
124 |
lastptr = g_ascend_dllist; |
125 |
nextptr = lastptr->next; |
126 |
while (nextptr != NULL && strcmp(nextptr->path,path) != 0) { |
127 |
lastptr = nextptr; |
128 |
nextptr = nextptr->next; |
129 |
} |
130 |
/* so either nextptr is NULL and not in list, or nextptr is |
131 |
* what we want to delete and lastptr is the link to it. |
132 |
*/ |
133 |
if (nextptr != NULL) { |
134 |
old = nextptr; |
135 |
lastptr->next = nextptr->next; |
136 |
dlreturn = old->dlreturn; |
137 |
ascfree(old->path); |
138 |
ascfree(old); |
139 |
} |
140 |
} |
141 |
return dlreturn; |
142 |
} |
143 |
|
144 |
/* |
145 |
* Checks the list for a conflicting handle so we can issue |
146 |
* a more helpful warning, if need be, than the standard message. |
147 |
*/ |
148 |
static |
149 |
void AscCheckDuplicateLoad(CONST char *path) |
150 |
{ |
151 |
struct ascend_dlrecord *r; |
152 |
|
153 |
if (NULL == path) { |
154 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Null path"); |
155 |
return; |
156 |
} |
157 |
|
158 |
r = g_ascend_dllist; |
159 |
while (r != NULL) { |
160 |
if (strcmp(path,r->path)==0) { |
161 |
ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Attempt to load already loaded '%s'.",path); |
162 |
return; |
163 |
} |
164 |
r = r->next; |
165 |
} |
166 |
} |
167 |
|
168 |
|
169 |
/*----------------------------------------------- |
170 |
WINDOWS |
171 |
*/ |
172 |
#if defined(__WIN32__) |
173 |
# include <windows.h> |
174 |
|
175 |
int Asc_DynamicLoad(CONST char *path, CONST char *initFun){ |
176 |
HINSTANCE xlib; |
177 |
ExternalLibraryRegister_fptr_t install = NULL; |
178 |
|
179 |
if (NULL == path) { |
180 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path\n"); |
181 |
return 1; |
182 |
} |
183 |
|
184 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
185 |
/* |
186 |
* If the named library does not exist, if it's not loadable or if |
187 |
* it does not define the named install proc, report an error |
188 |
*/ |
189 |
|
190 |
xlib = LoadLibrary(path); |
191 |
if (xlib == NULL) { |
192 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"LoadLibrary failed\n'%s'",path); |
193 |
return 1; |
194 |
} |
195 |
#if 0 |
196 |
ERROR_REPORTER_HERE(ASC_PROG_NOTE,"LoadLibrary succeeded, '%s'\n",path); |
197 |
#endif |
198 |
|
199 |
if (NULL != initFun) { |
200 |
install = (int (*)(void))GetProcAddress(xlib,initFun); |
201 |
if (install == NULL) { |
202 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Required function '%s' not found", initFun); |
203 |
(void)FreeLibrary(xlib); |
204 |
return 1; |
205 |
#if 0 |
206 |
}else{ |
207 |
FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install); |
208 |
#endif |
209 |
} |
210 |
} |
211 |
if (0 != AscAddRecord(xlib,path)) { |
212 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)\n",path); |
213 |
} |
214 |
return (install == NULL) ? 0 : (*install)(); |
215 |
} |
216 |
#define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
217 |
|
218 |
# define UNLOAD FreeLibrary |
219 |
# define DLLSYM GetProcAddress |
220 |
# define DLL_CAST (HINSTANCE) |
221 |
# define ASC_DLERRSTRING "unknown" |
222 |
# define UNLOAD_SUCCESS TRUE |
223 |
|
224 |
#endif /* __WIN32__ */ |
225 |
|
226 |
/*----------------------------------------------- |
227 |
UNIX/LINUX |
228 |
*/ |
229 |
/* |
230 |
SOLARIS and LINUX |
231 |
*/ |
232 |
/* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */ |
233 |
/* |
234 |
From a quick Google, it appears that AIX 5.1 now provides dlfcn.h, |
235 |
so I'll remove the code that was emulating it here. -- johnpye |
236 |
*/ |
237 |
#if (defined(sun) || defined(linux) || defined(__unix__) || defined(solaris) \ |
238 |
|| defined(_AIX) || defined(_SGI_SOURCE) || defined(__APPLE__)) |
239 |
# ifndef MACH |
240 |
# include <dlfcn.h> |
241 |
# else |
242 |
# error "MACH unsupported" |
243 |
# endif /* mach */ |
244 |
|
245 |
int Asc_DynamicLoad(CONST char *path, CONST char *initFun) |
246 |
{ |
247 |
void *xlib; |
248 |
ExternalLibraryRegister_fptr_t install = NULL; |
249 |
|
250 |
if (NULL == path) { |
251 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null path"); |
252 |
return 1; |
253 |
} |
254 |
|
255 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
256 |
|
257 |
/* |
258 |
* If the named library does not exist, if it's not loadable or if |
259 |
* it does not define the named install proc, report an error |
260 |
*/ |
261 |
xlib = dlopen(path, 1); |
262 |
if (xlib == NULL) { |
263 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"%s",(char *)dlerror()); |
264 |
|
265 |
#ifdef linux |
266 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"LD_LIBRARY_PATH = \"%s\"",getenv("LD_LIBRARY_PATH")); |
267 |
#endif |
268 |
|
269 |
return 1; |
270 |
} |
271 |
if (NULL != initFun) { |
272 |
/* https://www.opengroup.org/sophocles/show_mail.tpl?source=L&listname=austin-review-l&id=2252 */ |
273 |
*(void**)(&install) = dlsym(xlib, initFun); |
274 |
if (install == NULL) { |
275 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"While attempting to run '%s' in '%s': %s",initFun, path, (char *)dlerror()); |
276 |
dlclose(xlib); |
277 |
return 1; |
278 |
} |
279 |
} |
280 |
|
281 |
if (0 != AscAddRecord(xlib,path)) { |
282 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path); |
283 |
} |
284 |
return (install == NULL) ? 0 : (*install)(); |
285 |
} |
286 |
#define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
287 |
|
288 |
# define UNLOAD dlclose |
289 |
# define DLLSYM dlsym |
290 |
# define DLL_CAST (void *) |
291 |
# define ASC_DLERRSTRING dlerror() |
292 |
# define UNLOAD_SUCCESS 0 |
293 |
|
294 |
#endif /* posix: linux, unix, solaris,sgi */ |
295 |
|
296 |
/*----------------------------------------------- |
297 |
HPUX |
298 |
*/ |
299 |
#ifdef __hpux |
300 |
/* |
301 |
Kirk Abbott last fiddled with the following, which was |
302 |
originally put in place my Michael Moore for an |
303 |
HP/UX 9.X Operating Sys back in 1993. Arrr. No idea if |
304 |
it still works. |
305 |
*/ |
306 |
|
307 |
# include <dl.h> |
308 |
# include <errno.h> |
309 |
|
310 |
int Asc_DynamicLoad(CONST char *path, CONST char *initFun) |
311 |
{ |
312 |
shl_t xlib; |
313 |
ExternalLibraryRegister_fptr_t install = NULL; |
314 |
int i; |
315 |
|
316 |
if (NULL == path) { |
317 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path"); |
318 |
return 1; |
319 |
} |
320 |
|
321 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
322 |
|
323 |
/* |
324 |
* If the named library does not exist, if it's not loadable or if |
325 |
* it does not define the named install proc, report an error |
326 |
*/ |
327 |
xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L); |
328 |
if (xlib == (shl_t) NULL) { |
329 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to load shared library: %s",strerror(errno)); |
330 |
return 1; |
331 |
} |
332 |
if (NULL != initFun) { |
333 |
i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install); |
334 |
if (i == -1) { |
335 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s': %s", |
336 |
initFun, strerror(errno)); |
337 |
shl_unload(xlib); /* baa */ |
338 |
return 1; |
339 |
} |
340 |
if(install == NULL) { |
341 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s'. Error type unknown",initFun); |
342 |
shl_unload(xlib); /* baa */ |
343 |
return 1; |
344 |
} |
345 |
} |
346 |
if (0 != AscAddRecord(xlib,path)) { |
347 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path); |
348 |
} |
349 |
return (install == NULL) ? 0 : (*install)(); |
350 |
} |
351 |
# define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
352 |
|
353 |
# define UNLOAD shl_unload |
354 |
# define DLL_CAST (shl_t) |
355 |
# define ASC_DLERRSTRING "NULL definition" |
356 |
# define UNLOAD_SUCCESS 0 |
357 |
|
358 |
#endif /* __hpux */ |
359 |
|
360 |
/*----------------------------------------------- |
361 |
Did we get something from the above? |
362 |
*/ |
363 |
|
364 |
#ifndef ASCDL_OK |
365 |
# error "Unable to define an Asc_DynamicLoad function. Check your compiler options and installed system libraries." |
366 |
#endif |
367 |
|
368 |
/**----------------------------------------------- |
369 |
DYNAMIC UNLOADING |
370 |
*/ |
371 |
|
372 |
int Asc_DynamicUnLoad(CONST char *path) |
373 |
{ |
374 |
void *dlreturn; |
375 |
int retval; |
376 |
|
377 |
if (NULL == path) { |
378 |
ERROR_REPORTER_HERE(ASC_PROG_ERR, "Failed: Null path"); |
379 |
return -3; |
380 |
} |
381 |
|
382 |
dlreturn = AscDeleteRecord(path); |
383 |
if (dlreturn == NULL) { |
384 |
ERROR_REPORTER_HERE(ASC_PROG_ERR, "Unable to remember or unload %s", path); |
385 |
return -3; |
386 |
} |
387 |
CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s", path); |
388 |
/* |
389 |
* dlclose() returns 0 on success, FreeLibrary() returns TRUE. |
390 |
* A uniform convention is preferable, so trap and return 0 on success. |
391 |
*/ |
392 |
retval = UNLOAD(DLL_CAST dlreturn); |
393 |
return (retval == UNLOAD_SUCCESS) ? 0 : retval; |
394 |
} |
395 |
|
396 |
/**----------------------------------------------- |
397 |
DYNAMIC VARIABLE LINKING |
398 |
*/ |
399 |
void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol) |
400 |
{ |
401 |
void *dlreturn; |
402 |
void *symreturn; |
403 |
#ifdef __hpux |
404 |
int i; |
405 |
#endif |
406 |
|
407 |
if (libname == NULL) { |
408 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null libname"); |
409 |
return NULL; |
410 |
} |
411 |
if (symbol == NULL) { |
412 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null symbol"); |
413 |
return NULL; |
414 |
} |
415 |
|
416 |
dlreturn = AscFindDLRecord(libname); |
417 |
if (dlreturn == NULL) { |
418 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname); |
419 |
return NULL; |
420 |
} |
421 |
#ifdef __hpux |
422 |
i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn); |
423 |
if (i == -1) { |
424 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s (%s)", |
425 |
symbol, libname, strerror(errno)); |
426 |
symreturn = NULL; |
427 |
} |
428 |
#elif defined(__WIN32__) |
429 |
/* |
430 |
* Here's a bit of possibly-misdirected casting horror. |
431 |
* ISO C forbids casting between function and data pointers, so, naturally, |
432 |
* we cast between function and data pointers. Well, we don't have much |
433 |
* choice. GetProcAddress() returns a function pointer for both functions |
434 |
* and variables so we have to do the cast for variables. This is ok on |
435 |
* 32 bit Windows since the pointers are compatible. Then, to avoid |
436 |
* being reminded by the compiler that we're doing something illegal, |
437 |
* we apply convoluted casting to shut it up. |
438 |
* Oh, the crap you can find on the internet... JDS |
439 |
*/ |
440 |
*(FARPROC*)(&symreturn) = GetProcAddress((HINSTANCE)dlreturn, symbol); |
441 |
#else |
442 |
/* no problem on POSIX systems - dlsym() returns a void *. */ |
443 |
symreturn = dlsym(dlreturn, symbol); |
444 |
#endif |
445 |
if (symreturn == NULL) { |
446 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s",symbol,libname); |
447 |
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING); |
448 |
} |
449 |
return symreturn; |
450 |
} |
451 |
|
452 |
/**----------------------------------------------- |
453 |
DYNAMIC FUNCTION LINKING |
454 |
*/ |
455 |
DynamicF Asc_DynamicFunction(CONST char *libname, CONST char *symbol) |
456 |
{ |
457 |
void *dlreturn; |
458 |
DynamicF symreturn; |
459 |
#ifdef __hpux |
460 |
int i; |
461 |
#endif |
462 |
|
463 |
if (libname == NULL) { |
464 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null library name"); |
465 |
return NULL; |
466 |
} |
467 |
if (symbol == NULL) { |
468 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null function name"); |
469 |
return NULL; |
470 |
} |
471 |
|
472 |
dlreturn = AscFindDLRecord(libname); |
473 |
if (dlreturn == NULL) { |
474 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname); |
475 |
return NULL; |
476 |
} |
477 |
#ifdef __hpux |
478 |
i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn); |
479 |
if (i == -1) { |
480 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s (%s)", |
481 |
symbol, libname, strerror(errno)); |
482 |
symreturn = NULL; |
483 |
} |
484 |
#elif defined(__WIN32__) |
485 |
/* no problem on Windows - GetProcAddress() returns a function pointer. */ |
486 |
symreturn = (DynamicF)GetProcAddress((HINSTANCE)dlreturn, symbol); |
487 |
#else |
488 |
/* |
489 |
* Here's the corresponding bit of possibly-misdirected casting horror. |
490 |
* ISO C forbids casting between function and data pointers, so, naturally, |
491 |
* we cast between function and data pointers. Well, we don't have much |
492 |
* choice. dlsym() returns a void* for both variables and functions so we |
493 |
* have to do the cast for functions. This is ok on POSIX systems since the |
494 |
* pointer types are compatible. Then, to avoid being reminded by the |
495 |
* compiler that we're doing something illegal, we apply convoluted casting |
496 |
* to shut it up. Oh, the crap you can find on the internet... JDS |
497 |
*/ |
498 |
*(void**)(&symreturn) = dlsym(dlreturn, symbol); |
499 |
#endif |
500 |
if (symreturn == NULL) { |
501 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s",symbol,libname); |
502 |
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING); |
503 |
} |
504 |
return symreturn; |
505 |
} |
506 |
|
507 |
|
508 |
/*----------------------------------------------------------------------------- |
509 |
SEARCHING FOR LIBRARIES |
510 |
*/ |
511 |
|
512 |
|
513 |
/** |
514 |
Create a library filename according to platform standard naming. |
515 |
|
516 |
@param partialname The partial filename (eg 'mylib') |
517 |
@return Complete filename (eg 'libmylib.so' or 'mylib.dlll', etc) |
518 |
|
519 |
Basically just adds ASC_SHLIBPREFIX to start and ASC_SHLIBSUFFIX to end. |
520 |
|
521 |
No allowance made for 'soname' suffixes eg 'libsomething.so.1' etc. But |
522 |
that's probably OK as those methods aren't really applicable to dlopened |
523 |
libraries (eg the soname symlink mechanism breaks down). |
524 |
*/ |
525 |
char *dynaload_lib_filename(const char *partialname){ |
526 |
char *buffer; |
527 |
buffer = ASC_NEW_ARRAY(char,PATH_MAX); |
528 |
#if !defined(ASC_SHLIBSUFFIX) || !defined(ASC_SHLIBPREFIX) |
529 |
# error "ASC_SHLIBSUFFIX and ASC_SHLIBPREFIX are not defined" |
530 |
#endif |
531 |
snprintf(buffer,PATH_MAX,"%s%s%s",ASC_SHLIBPREFIX,partialname,ASC_SHLIBSUFFIX); |
532 |
return buffer; |
533 |
} |
534 |
|
535 |
|
536 |
/** |
537 |
A little structure to help with searching for libraries |
538 |
|
539 |
@see test_librarysearch |
540 |
*/ |
541 |
struct LibrarySearch{ |
542 |
struct FilePath *partialpath; |
543 |
char fullpath[PATH_MAX]; |
544 |
}; |
545 |
|
546 |
FilePathTestFn test_librarysearch; |
547 |
|
548 |
/** |
549 |
A 'test' function for passing to the ospath_searchpath_iterate function. |
550 |
This test function will return a match when a library having the required |
551 |
name is present in the fully resolved path. |
552 |
*/ |
553 |
int test_librarysearch(struct FilePath *path, void *userdata){ |
554 |
/* user data = the relative path, plus a place |
555 |
to store the full path when found */ |
556 |
FILE *f; |
557 |
struct LibrarySearch *ls; |
558 |
struct FilePath *fp; |
559 |
|
560 |
ls = (struct LibrarySearch *)userdata; |
561 |
fp = ospath_concat(path,ls->partialpath); |
562 |
if(fp==NULL){ |
563 |
char *tmp; |
564 |
tmp = ospath_str(path); |
565 |
CONSOLE_DEBUG("Unable to concatenate '%s'...",tmp); |
566 |
ospath_free_str(tmp); |
567 |
tmp = ospath_str(ls->partialpath); |
568 |
CONSOLE_DEBUG("... and '%s'...",tmp); |
569 |
ospath_free_str(tmp); |
570 |
return 0; |
571 |
} |
572 |
|
573 |
ospath_strncpy(fp,ls->fullpath,PATH_MAX); |
574 |
/* CONSOLE_DEBUG("SEARCHING FOR %s",ls->fullpath); */ |
575 |
|
576 |
f = ospath_fopen(fp,"r"); |
577 |
if(f==NULL){ |
578 |
ospath_free(fp); |
579 |
return 0; |
580 |
} |
581 |
fclose(f); |
582 |
|
583 |
/* ERROR_REPORTER_HERE(ASC_PROG_NOTE,"FOUND! %s\n",ls->fullpath); */ |
584 |
ospath_free(fp); |
585 |
return 1; |
586 |
} |
587 |
|
588 |
/** |
589 |
@DEPRECATED this function needs to be rewritten to use 'ImportHandler' |
590 |
functionality. |
591 |
*/ |
592 |
char *SearchArchiveLibraryPath(CONST char *name, char *dpath, const char *envv){ |
593 |
struct FilePath *fp1, *fp2, *fp3; /* relative path */ |
594 |
char *s1; |
595 |
char *buffer; |
596 |
|
597 |
struct LibrarySearch ls; |
598 |
struct FilePath **sp; |
599 |
char *path, *foundpath; |
600 |
ospath_stat_t buf; |
601 |
FILE *f; |
602 |
|
603 |
fp1 = ospath_new_noclean(name); |
604 |
if(fp1==NULL){ |
605 |
ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",name); |
606 |
ospath_free(fp1); |
607 |
return NULL; |
608 |
} |
609 |
|
610 |
s1 = ospath_getfilestem(fp1); |
611 |
if(s1==NULL){ |
612 |
/* not a file, so fail... */ |
613 |
return NULL; |
614 |
} |
615 |
|
616 |
fp2 = ospath_getdir(fp1); |
617 |
if(fp2==NULL){ |
618 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"unable to retrieve file dir"); |
619 |
return NULL; |
620 |
} |
621 |
|
622 |
buffer = dynaload_lib_filename(s1); |
623 |
|
624 |
fp3 = ospath_new(buffer); |
625 |
ASC_FREE(buffer); |
626 |
ospath_free(fp1); |
627 |
fp1 = ospath_concat(fp2,fp3); |
628 |
ospath_free(fp2); |
629 |
ospath_free(fp3); |
630 |
ospath_free_str(s1); |
631 |
|
632 |
/* attempt to open "name" directly */ |
633 |
if(0==ospath_stat(fp1,&buf) && NULL!=(f = ospath_fopen(fp1,"r")) ){ |
634 |
char *tmp; |
635 |
tmp = ospath_str(fp1); |
636 |
CONSOLE_DEBUG("Library '%s' opened directly, without path search",tmp); |
637 |
ospath_free_str(tmp); |
638 |
fp2 = ospath_getabs(fp1); |
639 |
foundpath = ospath_str(fp2); |
640 |
ospath_free(fp2); |
641 |
fclose(f); |
642 |
}else{ |
643 |
|
644 |
ls.partialpath = fp1; |
645 |
|
646 |
path=Asc_GetEnv(envv); |
647 |
if(path==NULL){ |
648 |
/* CONSOLE_DEBUG("Library search path env var '%s' not found, using default path '%s'",envv,dpath); */ |
649 |
path=dpath; |
650 |
} |
651 |
|
652 |
/* CONSOLE_DEBUG("SEARCHPATH IS %s",path); */ |
653 |
sp = ospath_searchpath_new(path); |
654 |
|
655 |
if(NULL==ospath_searchpath_iterate(sp,&test_librarysearch,&ls)){ |
656 |
ospath_free(fp1); |
657 |
ospath_searchpath_free(sp); |
658 |
return NULL; |
659 |
} |
660 |
|
661 |
foundpath = ASC_NEW_ARRAY(char,strlen(ls.fullpath)+1); |
662 |
strcpy(foundpath,ls.fullpath); |
663 |
ospath_searchpath_free(sp); |
664 |
} |
665 |
|
666 |
ospath_free(fp1); |
667 |
return foundpath; |
668 |
} |