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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 466 - (hide annotations) (download) (as text)
Sun Apr 16 15:07:48 2006 UTC (19 years, 7 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 johnpye 158 /* What is the source of this file ?? -- johnpye */
2 aw0a 1 /*
3     * -----------------------------------------------------------------
4     * Copyright 1993 D.I.S. - Universita` di Pavia - Italy
5     * -----------------------------------------------------------------
6     *
7     * Permission to use, copy, modify, distribute this software
8 johnpye 158 * and its documentation for any purpose is hereby granted without
9 aw0a 1 * 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 johnpye 427 This file *should* support unix/linux-style systems (dlfcn.h)
29     and Windows.
30 aw0a 1
31 johnpye 427 Note that under many systems, profiling does not work
32     with dynamic libraries!
33 johnpye 158 */
34    
35 johnpye 427
36    
37    
38     #ifdef DYNAMIC_PACKAGES
39    
40    
41    
42    
43 aw0a 1 #include <stdio.h>
44     #include <stdlib.h>
45 ben.allan 45 #include <stdarg.h>
46 johnpye 399 #include "ascConfig.h"
47     #include "error.h"
48     #include "ascPrint.h"
49     #include "ascPanic.h"
50     #include "ascMalloc.h"
51     #include "ascDynaLoad.h"
52 jds 59
53 johnpye 399 #include <compiler/instance_enum.h>
54     #include <general/list.h>
55     #include <compiler/compiler.h>
56     #include <compiler/extfunc.h>
57 johnpye 380
58 johnpye 466 typedef int (*ExternalLibraryRegister_fptr_t)(void);
59 johnpye 380
60 johnpye 158 /*--------------------------------------
61     GENERIC STUFF
62     */
63    
64 aw0a 1 struct ascend_dlrecord {
65 jds 59 char *path; /* library name */
66 aw0a 1 void *dlreturn; /* return from dlopen */
67     struct ascend_dlrecord *next;
68     };
69    
70 jds 59 /* Linked list of library names & dlopen() return values. */
71 aw0a 1 static
72     struct ascend_dlrecord *g_ascend_dllist = NULL;
73    
74     /*
75 jds 59 * Adds a record of the path and handle to the list.
76     * If it fails to do this, returns 1, else 0.
77 aw0a 1 */
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 jds 103 keeppath = ascstrdup((char *)path);
87 aw0a 1 if (keeppath==NULL) return 1;
88 jds 103 new = (struct ascend_dlrecord *)ascmalloc(sizeof(struct ascend_dlrecord));
89 aw0a 1 if (new==NULL) {
90 jds 103 ascfree(keeppath);
91 aw0a 1 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 jds 59 * deletes the record from the list. Returns NULL if not found.
122 aw0a 1 */
123     static
124 jds 103 void *AscDeleteRecord(CONST char *path)
125 aw0a 1 {
126     struct ascend_dlrecord *nextptr, *lastptr, *old;
127     void *dlreturn = NULL;
128 jds 59
129 jds 61 if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL;
130 jds 59
131 aw0a 1 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 jds 103 ascfree(old->path);
137     ascfree(old);
138 aw0a 1 } 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 jds 103 ascfree(old->path);
153     ascfree(old);
154 aw0a 1 }
155     }
156     return dlreturn;
157     }
158    
159     /*
160 jds 59 * Checks the list for a conflicting handle so we can issue
161 aw0a 1 * a more helpful warning, if need be, than the standard message.
162     */
163 jds 59 static
164 aw0a 1 void AscCheckDuplicateLoad(CONST char *path)
165     {
166     struct ascend_dlrecord *r;
167 jds 59
168     if (NULL == path) {
169 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Null path in AscCheckDuplicateLoad.");
170 jds 59 return;
171     }
172    
173 aw0a 1 r = g_ascend_dllist;
174     while (r != NULL) {
175     if (strcmp(path,r->path)==0) {
176 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Attempt to load already loaded '%s'.",path);
177 aw0a 1 return;
178     }
179     r = r->next;
180     }
181     }
182    
183 johnpye 427 /*-----------------------------------------------
184     WINDOWS
185 johnpye 158 */
186 johnpye 427 #if defined(__WIN32__)
187     # include <windows.h>
188 johnpye 158
189 aw0a 1 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 johnpye 380 ExternalLibraryRegister_fptr_t install = NULL;
194 aw0a 1
195 jds 59 if (NULL == path) {
196     FPRINTF(stderr,"Asc_DynamicLoad failed: Null path\n");
197     return 1;
198     }
199    
200 aw0a 1 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 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: LoadLibrary failed\n");
209 aw0a 1 return 1;
210     }
211 jds 59 if (NULL != initFun) {
212     install = (int (*)())GetProcAddress(xlib,initFun);
213     if (install == NULL) {
214 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad: Required function %s not found\n", initFun);
215 jds 59 (void)FreeLibrary(xlib);
216     return 1;
217 johnpye 62 }else{
218 johnpye 66 FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install);
219 johnpye 62 }
220 aw0a 1 }
221 jds 59 if (0 != AscAddRecord(xlib,path)) {
222 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
223 aw0a 1 }
224 johnpye 466 return (install == NULL) ? 0 : (*install)();
225 aw0a 1 }
226 johnpye 427
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 aw0a 1 #endif /* __WIN32__ */
234 jds 61
235 johnpye 427 /*-----------------------------------------------
236     UNIX/LINUX
237     */
238 johnpye 62 /*
239     SOLARIS and LINUX
240     */
241 johnpye 158 /* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */
242 johnpye 62 /*
243 johnpye 190 From a quick Google, it appears that AIX 5.1 now provides dlfcn.h,
244 johnpye 158 so I'll remove the code that was emulating it here. -- johnpye
245 johnpye 62 */
246 johnpye 427 #if defined(sun) || defined(linux) || defined(__unix__) \
247     || defined(solaris) || defined(_AIX) || defined(_SGI_SOURCE)
248 johnpye 158 # ifndef MACH
249     # include <dlfcn.h>
250     # else
251     # error "MACH unsupported"
252     # endif
253 jds 59
254 aw0a 1 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 johnpye 380 ExternalLibraryRegister_fptr_t install = NULL;
259 jds 59
260     if (NULL == path) {
261 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
262 jds 59 return 1;
263     }
264    
265 aw0a 1 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 jds 61 if (xlib == NULL) {
273 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
274 aw0a 1 return 1;
275     }
276 jds 61 if (NULL != initFun) {
277     install = (int (*)())dlsym(xlib, initFun);
278     if (install == NULL) {
279 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
280 jds 61 dlclose(xlib);
281     return 1;
282     }
283     }
284 johnpye 190
285 jds 59 if (0 != AscAddRecord(xlib,path)) {
286 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
287 aw0a 1 }
288 johnpye 466 return (install == NULL) ? 0 : (*install)();
289 aw0a 1 }
290    
291 johnpye 427 # define UNLOAD dlclose
292     # define DLLSYM dlsym
293     # define DLL_CAST (void *)
294     # define ASC_DLERRSTRING dlerror()
295     # define UNLOAD_SUCCESS 0
296    
297 johnpye 158 #endif /* posix: linux, unix, solaris,sgi */
298 aw0a 1
299 johnpye 427 /*-----------------------------------------------
300     HPUX
301     */
302 aw0a 1 #ifdef __hpux
303     /*
304 johnpye 427 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 aw0a 1
310 johnpye 158 # include <dl.h>
311     # include <errno.h>
312 aw0a 1
313     int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
314     {
315 johnpye 158 # define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
316 aw0a 1 shl_t xlib;
317 johnpye 380 ExternalLibraryRegister_fptr_t install = NULL;
318 aw0a 1 int i;
319 jds 59
320     if (NULL == path) {
321 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed: Null path\n");
322 jds 59 return 1;
323     }
324    
325 aw0a 1 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 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to load shared library : %s\n",strerror(errno));
334 aw0a 1 return 1;
335     }
336 jds 59 if (NULL != initFun) {
337     i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
338     if (i == -1) {
339 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Unable to find needed symbol %s %s\n",
340 jds 59 initFun, strerror(errno));
341     shl_unload(xlib); /* baa */
342     return 1;
343 aw0a 1 }
344 jds 59 if (install == NULL) {
345 johnpye 190 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 jds 59 shl_unload(xlib); /* baa */
348     return 1;
349     }
350 aw0a 1 }
351 jds 59 if (0 != AscAddRecord(xlib,path)) {
352 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicLoad failed to record library (%s)\n",path);
353 aw0a 1 }
354 johnpye 466 return (install == NULL) ? 0 : (*install)();
355 aw0a 1 }
356    
357 johnpye 158 # define UNLOAD shl_unload
358     # define DLL_CAST (shl_t)
359     # define ASC_DLERRSTRING "NULL definition"
360     # define UNLOAD_SUCCESS 0
361 johnpye 427
362 aw0a 1 #endif /* __hpux */
363    
364 johnpye 427 /*-----------------------------------------------
365     Did we get something from the above?
366 johnpye 158 */
367    
368 johnpye 427 #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 jds 103 int Asc_DynamicUnLoad(CONST char *path)
377 aw0a 1 {
378     void *dlreturn;
379 jds 61 int retval;
380 johnpye 190
381 jds 59 if (NULL == path) {
382 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad failed: Null path\n");
383 jds 59 return -3;
384     }
385    
386 aw0a 1 dlreturn = AscDeleteRecord(path);
387     if (dlreturn == NULL) {
388 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR, "Asc_DynamicUnLoad: unable to remember or unload %s\n", path);
389 aw0a 1 return -3;
390     }
391 johnpye 163 CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s \n", path);
392 johnpye 190 /*
393 jds 61 * 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 aw0a 1 }
399    
400 johnpye 427 /**-----------------------------------------------
401     DYNAMIC VARIABLE LINKING
402     */
403 jds 103 void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol)
404 aw0a 1 {
405     void *dlreturn;
406     void *symreturn;
407     #ifdef __hpux
408     int i;
409     #endif
410    
411 jds 59 if (libname == NULL) {
412 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null libname\n");
413 aw0a 1 return NULL;
414     }
415 jds 59 if (symbol == NULL) {
416 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol failed: Null symbol\n");
417 jds 59 return NULL;
418     }
419    
420 aw0a 1 dlreturn = AscFindDLRecord(libname);
421     if (dlreturn == NULL) {
422 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested library %s\n", libname);
423 aw0a 1 return NULL;
424     }
425     #ifdef __hpux
426     i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
427     if (i == -1) {
428 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicSymbol: Unable to find requested symbol %s in %s (%s)\n",
429 aw0a 1 symbol, libname, strerror(errno));
430     symreturn = NULL;
431     }
432 jds 103 #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 johnpye 190 * 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 jds 103 * 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 aw0a 1 #else
446 jds 103 /* no problem on POSIX systems - dlsym() returns a void *. */
447     symreturn = dlsym(dlreturn, symbol);
448 aw0a 1 #endif
449     if (symreturn == NULL) {
450 johnpye 190 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 aw0a 1 }
453     return symreturn;
454     }
455 jds 103
456 johnpye 427 /**-----------------------------------------------
457     DYNAMIC FUNCTION LINKING
458     */
459 jds 103 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 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null library name\n");
469 jds 103 return NULL;
470     }
471     if (symbol == NULL) {
472 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction failed: Null function name\n");
473 jds 103 return NULL;
474     }
475    
476     dlreturn = AscFindDLRecord(libname);
477     if (dlreturn == NULL) {
478 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested library %s\n", libname);
479 jds 103 return NULL;
480     }
481     #ifdef __hpux
482     i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
483     if (i == -1) {
484 johnpye 190 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Asc_DynamicFunction: Unable to find requested function %s in %s (%s)\n",
485 jds 103 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 johnpye 190 * we cast between function and data pointers. Well, we don't have much
496 jds 103 * choice. dlsym() returns a void* for both variables and functions so we
497 johnpye 190 * 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 jds 103 * 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 johnpye 190 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 jds 103 }
508     return symreturn;
509     }
510 johnpye 427
511    
512    
513     #endif
514    
515    

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