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

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