/[ascend]/trunk/base/generic/utilities/ascDynaLoad.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/ascDynaLoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 862 - (show annotations) (download) (as text)
Tue Sep 26 13:47:27 2006 UTC (13 years, 10 months ago) by johnpye
File MIME type: text/x-csrc
File size: 17470 byte(s)
Some work on the IMPORT handler functionality. Mostly just placeholders at this stage.
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_ERR,"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, 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("ENV VAR NOT FOUND, FALLING BACK TO DEFAULT SEARCH PATH = '%s'",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 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22