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

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