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