/[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 543 - (show annotations) (download) (as text)
Thu Apr 27 00:04:13 2006 UTC (14 years, 1 month ago) by johnpye
File MIME type: text/x-csrc
File size: 14701 byte(s)
Fix windows behaviour for 'IMPORT "johnpye/extfn/extfntest";'
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 /*
20 This file *should* support unix/linux-style systems (dlfcn.h)
21 and Windows.
22
23 Note that under many systems, profiling does not work
24 with dynamic libraries!
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include "ascConfig.h"
31 #include "error.h"
32 #include "ascPrint.h"
33 #include "ascPanic.h"
34 #include "ascMalloc.h"
35 #include "ascDynaLoad.h"
36
37 #include <compiler/instance_enum.h>
38 #include <general/list.h>
39 #include <compiler/compiler.h>
40 #include <compiler/extfunc.h>
41
42 typedef int (*ExternalLibraryRegister_fptr_t)(void);
43
44 /*--------------------------------------
45 GENERIC STUFF
46 */
47
48 struct ascend_dlrecord {
49 char *path; /* library name */
50 void *dlreturn; /* return from dlopen */
51 struct ascend_dlrecord *next;
52 };
53
54 /* Linked list of library names & dlopen() return values. */
55 static
56 struct ascend_dlrecord *g_ascend_dllist = NULL;
57
58 /*
59 * Adds a record of the path and handle to the list.
60 * If it fails to do this, returns 1, else 0.
61 */
62 static
63 int AscAddRecord(void *dlreturn, CONST char *path)
64 {
65 struct ascend_dlrecord *new;
66 char *keeppath;
67 if (dlreturn == NULL || path == NULL) {
68 return 1;
69 }
70 keeppath = ascstrdup((char *)path);
71 if (keeppath==NULL) return 1;
72 new = (struct ascend_dlrecord *)ascmalloc(sizeof(struct ascend_dlrecord));
73 if (new==NULL) {
74 ascfree(keeppath);
75 return 1;
76 }
77 new->next = g_ascend_dllist; /* insert at head */
78 g_ascend_dllist = new;
79 new->path = keeppath;
80 new->dlreturn = dlreturn;
81 return 0;
82 }
83
84 /*
85 * Finds a record of the path given and returns the associated handle.
86 * If it fails to do this, returns NULL.
87 */
88 static
89 void *AscFindDLRecord(CONST char *path)
90 {
91 struct ascend_dlrecord *new;
92 if (path == NULL) {
93 return NULL;
94 }
95 new = g_ascend_dllist;
96 while (new != NULL && strcmp(new->path,path) != 0) {
97 /* advance new until no more new or new with path found */
98 new = new->next;
99 }
100 return (new != NULL) ? new->dlreturn : NULL;
101 }
102
103 /*
104 * Finds and returns the handle to path, if one matches, and
105 * deletes the record from the list. Returns NULL if not found.
106 */
107 static
108 void *AscDeleteRecord(CONST char *path)
109 {
110 struct ascend_dlrecord *nextptr, *lastptr, *old;
111 void *dlreturn = NULL;
112
113 if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL;
114
115 if (strcmp(path,g_ascend_dllist->path)==0) {
116 /* head case */
117 old = g_ascend_dllist;
118 g_ascend_dllist = old->next;
119 dlreturn = old->dlreturn;
120 ascfree(old->path);
121 ascfree(old);
122 } else {
123 lastptr = g_ascend_dllist;
124 nextptr = lastptr->next;
125 while (nextptr != NULL && strcmp(nextptr->path,path) != 0) {
126 lastptr = nextptr;
127 nextptr = nextptr->next;
128 }
129 /* so either nextptr is NULL and not in list, or nextptr is
130 * what we want to delete and lastptr is the link to it.
131 */
132 if (nextptr != NULL) {
133 old = nextptr;
134 lastptr->next = nextptr->next;
135 dlreturn = old->dlreturn;
136 ascfree(old->path);
137 ascfree(old);
138 }
139 }
140 return dlreturn;
141 }
142
143 /*
144 * Checks the list for a conflicting handle so we can issue
145 * a more helpful warning, if need be, than the standard message.
146 */
147 static
148 void AscCheckDuplicateLoad(CONST char *path)
149 {
150 struct ascend_dlrecord *r;
151
152 if (NULL == path) {
153 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Null path in AscCheckDuplicateLoad.");
154 return;
155 }
156
157 r = g_ascend_dllist;
158 while (r != NULL) {
159 if (strcmp(path,r->path)==0) {
160 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Attempt to load already loaded '%s'.",path);
161 return;
162 }
163 r = r->next;
164 }
165 }
166
167 /*-----------------------------------------------
168 WINDOWS
169 */
170 #if defined(__WIN32__)
171 # include <windows.h>
172
173 int Asc_DynamicLoad(CONST char *path, CONST char *initFun){
174 HINSTANCE xlib;
175 ExternalLibraryRegister_fptr_t install = NULL;
176
177 if (NULL == path) {
178 FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
179 return 1;
180 }
181
182 AscCheckDuplicateLoad(path); /* whine if we've see it before */
183 /*
184 * If the named library does not exist, if it's not loadable or if
185 * it does not define the named install proc, report an error
186 */
187
188 xlib = LoadLibrary(path);
189 if (xlib == NULL) {
190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: LoadLibrary failed\n'%s'",path);
191 return 1;
192 }
193 ERROR_REPORTER_NOLINE(ASC_PROG_NOTE,"Asc_DynamicLoad: LoadLibrary succeeded, '%s'\n",path);
194
195 if (NULL != initFun) {
196 install = (int (*)(void))GetProcAddress(xlib,initFun);
197 if (install == NULL) {
198 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: Required function %s not found\n", initFun);
199 (void)FreeLibrary(xlib);
200 return 1;
201 }else{
202 FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install);
203 }
204 }
205 if (0 != AscAddRecord(xlib,path)) {
206 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
207 }
208 return (install == NULL) ? 0 : (*install)();
209 }
210 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
211
212 # define UNLOAD FreeLibrary
213 # define DLLSYM GetProcAddress
214 # define DLL_CAST (HINSTANCE)
215 # define ASC_DLERRSTRING "unknown"
216 # define UNLOAD_SUCCESS TRUE
217
218 #endif /* __WIN32__ */
219
220 /*-----------------------------------------------
221 UNIX/LINUX
222 */
223 /*
224 SOLARIS and LINUX
225 */
226 /* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */
227 /*
228 From a quick Google, it appears that AIX 5.1 now provides dlfcn.h,
229 so I'll remove the code that was emulating it here. -- johnpye
230 */
231 #if (defined(sun) || defined(linux) || defined(__unix__) || defined(solaris) || defined(_AIX) || defined(_SGI_SOURCE))
232 # ifndef MACH
233 # include <dlfcn.h>
234 # else
235 # error "MACH unsupported"
236 # endif /* mach */
237
238 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
239 {
240 void *xlib;
241 ExternalLibraryRegister_fptr_t install = NULL;
242
243 if (NULL == path) {
244 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
245 return 1;
246 }
247
248 AscCheckDuplicateLoad(path); /* whine if we've see it before */
249
250 /*
251 * If the named library does not exist, if it's not loadable or if
252 * it does not define the named install proc, report an error
253 */
254 xlib = dlopen(path, 1);
255 if (xlib == NULL) {
256 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
257 return 1;
258 }
259 if (NULL != initFun) {
260 install = (int (*)())dlsym(xlib, initFun);
261 if (install == NULL) {
262 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
263 dlclose(xlib);
264 return 1;
265 }
266 }
267
268 if (0 != AscAddRecord(xlib,path)) {
269 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
270 }
271 return (install == NULL) ? 0 : (*install)();
272 }
273 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
274
275 # define UNLOAD dlclose
276 # define DLLSYM dlsym
277 # define DLL_CAST (void *)
278 # define ASC_DLERRSTRING dlerror()
279 # define UNLOAD_SUCCESS 0
280
281 #endif /* posix: linux, unix, solaris,sgi */
282
283 /*-----------------------------------------------
284 HPUX
285 */
286 #ifdef __hpux
287 /*
288 Kirk Abbott last fiddled with the following, which was
289 originally put in place my Michael Moore for an
290 HP/UX 9.X Operating Sys back in 1993. Arrr. No idea if
291 it still works.
292 */
293
294 # include <dl.h>
295 # include <errno.h>
296
297 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
298 {
299 shl_t xlib;
300 ExternalLibraryRegister_fptr_t install = NULL;
301 int i;
302
303 if (NULL == path) {
304 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
305 return 1;
306 }
307
308 AscCheckDuplicateLoad(path); /* whine if we've see it before */
309
310 /*
311 * If the named library does not exist, if it's not loadable or if
312 * it does not define the named install proc, report an error
313 */
314 xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
315 if (xlib == (shl_t) NULL) {
316 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to load shared library : %s\n",strerror(errno));
317 return 1;
318 }
319 if (NULL != initFun) {
320 i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
321 if (i == -1) {
322 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to find needed symbol %s %s\n",
323 initFun, strerror(errno));
324 shl_unload(xlib); /* baa */
325 return 1;
326 }
327 if (install == NULL) {
328 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to find needed symbol %s\n",initFun);
329 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type unknown\n");
330 shl_unload(xlib); /* baa */
331 return 1;
332 }
333 }
334 if (0 != AscAddRecord(xlib,path)) {
335 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
336 }
337 return (install == NULL) ? 0 : (*install)();
338 }
339 # define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
340
341 # define UNLOAD shl_unload
342 # define DLL_CAST (shl_t)
343 # define ASC_DLERRSTRING "NULL definition"
344 # define UNLOAD_SUCCESS 0
345
346 #endif /* __hpux */
347
348 /*-----------------------------------------------
349 Did we get something from the above?
350 */
351
352 #ifndef ASCDL_OK
353 # error "Unable to define an Asc_DynamicLoad function. Check your compiler options and installed system libraries."
354 #endif
355
356 /**-----------------------------------------------
357 DYNAMIC UNLOADING
358 */
359
360 int Asc_DynamicUnLoad(CONST char *path)
361 {
362 void *dlreturn;
363 int retval;
364
365 if (NULL == path) {
366 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad failed: Null path\n");
367 return -3;
368 }
369
370 dlreturn = AscDeleteRecord(path);
371 if (dlreturn == NULL) {
372 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad: unable to remember or unload %s\n", path);
373 return -3;
374 }
375 CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s \n", path);
376 /*
377 * dlclose() returns 0 on success, FreeLibrary() returns TRUE.
378 * A uniform convention is preferable, so trap and return 0 on success.
379 */
380 retval = UNLOAD(DLL_CAST dlreturn);
381 return (retval == UNLOAD_SUCCESS) ? 0 : retval;
382 }
383
384 /**-----------------------------------------------
385 DYNAMIC VARIABLE LINKING
386 */
387 void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol)
388 {
389 void *dlreturn;
390 void *symreturn;
391 #ifdef __hpux
392 int i;
393 #endif
394
395 if (libname == NULL) {
396 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null libname\n");
397 return NULL;
398 }
399 if (symbol == NULL) {
400 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null symbol\n");
401 return NULL;
402 }
403
404 dlreturn = AscFindDLRecord(libname);
405 if (dlreturn == NULL) {
406 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested library %s\n", libname);
407 return NULL;
408 }
409 #ifdef __hpux
410 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
411 if (i == -1) {
412 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested symbol %s in %s (%s)\n",
413 symbol, libname, strerror(errno));
414 symreturn = NULL;
415 }
416 #elif defined(__WIN32__)
417 /*
418 * Here's a bit of possibly-misdirected casting horror.
419 * ISO C forbids casting between function and data pointers, so, naturally,
420 * we cast between function and data pointers. Well, we don't have much
421 * choice. GetProcAddress() returns a function pointer for both functions
422 * and variables so we have to do the cast for variables. This is ok on
423 * 32 bit Windows since the pointers are compatible. Then, to avoid
424 * being reminded by the compiler that we're doing something illegal,
425 * we apply convoluted casting to shut it up.
426 * Oh, the crap you can find on the internet... JDS
427 */
428 *(FARPROC*)(&symreturn) = GetProcAddress((HINSTANCE)dlreturn, symbol);
429 #else
430 /* no problem on POSIX systems - dlsym() returns a void *. */
431 symreturn = dlsym(dlreturn, symbol);
432 #endif
433 if (symreturn == NULL) {
434 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested symbol %s in %s\n",symbol,libname);
435 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type %s\n",ASC_DLERRSTRING);
436 }
437 return symreturn;
438 }
439
440 /**-----------------------------------------------
441 DYNAMIC FUNCTION LINKING
442 */
443 DynamicF Asc_DynamicFunction(CONST char *libname, CONST char *symbol)
444 {
445 void *dlreturn;
446 DynamicF symreturn;
447 #ifdef __hpux
448 int i;
449 #endif
450
451 if (libname == NULL) {
452 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null library name\n");
453 return NULL;
454 }
455 if (symbol == NULL) {
456 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null function name\n");
457 return NULL;
458 }
459
460 dlreturn = AscFindDLRecord(libname);
461 if (dlreturn == NULL) {
462 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested library %s\n", libname);
463 return NULL;
464 }
465 #ifdef __hpux
466 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
467 if (i == -1) {
468 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested function %s in %s (%s)\n",
469 symbol, libname, strerror(errno));
470 symreturn = NULL;
471 }
472 #elif defined(__WIN32__)
473 /* no problem on Windows - GetProcAddress() returns a function pointer. */
474 symreturn = (DynamicF)GetProcAddress((HINSTANCE)dlreturn, symbol);
475 #else
476 /*
477 * Here's the corresponding bit of possibly-misdirected casting horror.
478 * ISO C forbids casting between function and data pointers, so, naturally,
479 * we cast between function and data pointers. Well, we don't have much
480 * choice. dlsym() returns a void* for both variables and functions so we
481 * have to do the cast for functions. This is ok on POSIX systems since the
482 * pointer types are compatible. Then, to avoid being reminded by the
483 * compiler that we're doing something illegal, we apply convoluted casting
484 * to shut it up. Oh, the crap you can find on the internet... JDS
485 */
486 *(void**)(&symreturn) = dlsym(dlreturn, symbol);
487 #endif
488 if (symreturn == NULL) {
489 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested function %s in %s\n",symbol,libname);
490 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type %s\n",ASC_DLERRSTRING);
491 }
492 return symreturn;
493 }
494

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