1 |
johnpye |
478 |
/* ASCEND modelling environment |
2 |
|
|
Copyright (C) 2006 Carnegie Mellon University |
3 |
aw0a |
1 |
|
4 |
johnpye |
478 |
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 |
johnpye |
791 |
*//** |
19 |
|
|
@file |
20 |
|
|
|
21 |
johnpye |
427 |
This file *should* support unix/linux-style systems (dlfcn.h) |
22 |
|
|
and Windows. |
23 |
aw0a |
1 |
|
24 |
johnpye |
427 |
Note that under many systems, profiling does not work |
25 |
|
|
with dynamic libraries! |
26 |
johnpye |
158 |
*/ |
27 |
|
|
|
28 |
aw0a |
1 |
#include <stdio.h> |
29 |
|
|
#include <stdlib.h> |
30 |
ben.allan |
45 |
#include <stdarg.h> |
31 |
johnpye |
399 |
#include "ascConfig.h" |
32 |
|
|
#include "error.h" |
33 |
|
|
#include "ascPrint.h" |
34 |
|
|
#include "ascPanic.h" |
35 |
|
|
#include "ascMalloc.h" |
36 |
|
|
#include "ascDynaLoad.h" |
37 |
johnpye |
862 |
#include "ascEnvVar.h" |
38 |
jds |
59 |
|
39 |
johnpye |
791 |
#include <general/env.h> |
40 |
|
|
#include <general/ospath.h> |
41 |
johnpye |
399 |
#include <compiler/instance_enum.h> |
42 |
|
|
#include <general/list.h> |
43 |
|
|
#include <compiler/extfunc.h> |
44 |
johnpye |
862 |
#include <compiler/importhandler.h> |
45 |
johnpye |
380 |
|
46 |
johnpye |
466 |
typedef int (*ExternalLibraryRegister_fptr_t)(void); |
47 |
johnpye |
380 |
|
48 |
johnpye |
158 |
/*-------------------------------------- |
49 |
|
|
GENERIC STUFF |
50 |
|
|
*/ |
51 |
|
|
|
52 |
aw0a |
1 |
struct ascend_dlrecord { |
53 |
jds |
59 |
char *path; /* library name */ |
54 |
aw0a |
1 |
void *dlreturn; /* return from dlopen */ |
55 |
|
|
struct ascend_dlrecord *next; |
56 |
|
|
}; |
57 |
|
|
|
58 |
jds |
59 |
/* Linked list of library names & dlopen() return values. */ |
59 |
johnpye |
791 |
static struct ascend_dlrecord *g_ascend_dllist = NULL; |
60 |
aw0a |
1 |
|
61 |
|
|
/* |
62 |
jds |
59 |
* Adds a record of the path and handle to the list. |
63 |
|
|
* If it fails to do this, returns 1, else 0. |
64 |
aw0a |
1 |
*/ |
65 |
johnpye |
791 |
static int AscAddRecord(void *dlreturn, CONST char *path){ |
66 |
aw0a |
1 |
struct ascend_dlrecord *new; |
67 |
|
|
char *keeppath; |
68 |
|
|
if (dlreturn == NULL || path == NULL) { |
69 |
|
|
return 1; |
70 |
|
|
} |
71 |
johnpye |
1220 |
keeppath = ASC_STRDUP((char *)path); |
72 |
aw0a |
1 |
if (keeppath==NULL) return 1; |
73 |
johnpye |
709 |
new = ASC_NEW(struct ascend_dlrecord); |
74 |
aw0a |
1 |
if (new==NULL) { |
75 |
jds |
103 |
ascfree(keeppath); |
76 |
aw0a |
1 |
return 1; |
77 |
|
|
} |
78 |
|
|
new->next = g_ascend_dllist; /* insert at head */ |
79 |
|
|
g_ascend_dllist = new; |
80 |
|
|
new->path = keeppath; |
81 |
|
|
new->dlreturn = dlreturn; |
82 |
|
|
return 0; |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
/* |
86 |
|
|
* Finds a record of the path given and returns the associated handle. |
87 |
|
|
* If it fails to do this, returns NULL. |
88 |
|
|
*/ |
89 |
|
|
static |
90 |
|
|
void *AscFindDLRecord(CONST char *path) |
91 |
|
|
{ |
92 |
|
|
struct ascend_dlrecord *new; |
93 |
|
|
if (path == NULL) { |
94 |
|
|
return NULL; |
95 |
|
|
} |
96 |
|
|
new = g_ascend_dllist; |
97 |
|
|
while (new != NULL && strcmp(new->path,path) != 0) { |
98 |
|
|
/* advance new until no more new or new with path found */ |
99 |
|
|
new = new->next; |
100 |
|
|
} |
101 |
|
|
return (new != NULL) ? new->dlreturn : NULL; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
/* |
105 |
|
|
* Finds and returns the handle to path, if one matches, and |
106 |
jds |
59 |
* deletes the record from the list. Returns NULL if not found. |
107 |
aw0a |
1 |
*/ |
108 |
|
|
static |
109 |
jds |
103 |
void *AscDeleteRecord(CONST char *path) |
110 |
aw0a |
1 |
{ |
111 |
|
|
struct ascend_dlrecord *nextptr, *lastptr, *old; |
112 |
|
|
void *dlreturn = NULL; |
113 |
jds |
59 |
|
114 |
jds |
61 |
if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL; |
115 |
jds |
59 |
|
116 |
aw0a |
1 |
if (strcmp(path,g_ascend_dllist->path)==0) { |
117 |
|
|
/* head case */ |
118 |
|
|
old = g_ascend_dllist; |
119 |
|
|
g_ascend_dllist = old->next; |
120 |
|
|
dlreturn = old->dlreturn; |
121 |
jds |
103 |
ascfree(old->path); |
122 |
|
|
ascfree(old); |
123 |
aw0a |
1 |
} else { |
124 |
|
|
lastptr = g_ascend_dllist; |
125 |
|
|
nextptr = lastptr->next; |
126 |
|
|
while (nextptr != NULL && strcmp(nextptr->path,path) != 0) { |
127 |
|
|
lastptr = nextptr; |
128 |
|
|
nextptr = nextptr->next; |
129 |
|
|
} |
130 |
|
|
/* so either nextptr is NULL and not in list, or nextptr is |
131 |
|
|
* what we want to delete and lastptr is the link to it. |
132 |
|
|
*/ |
133 |
|
|
if (nextptr != NULL) { |
134 |
|
|
old = nextptr; |
135 |
|
|
lastptr->next = nextptr->next; |
136 |
|
|
dlreturn = old->dlreturn; |
137 |
jds |
103 |
ascfree(old->path); |
138 |
|
|
ascfree(old); |
139 |
aw0a |
1 |
} |
140 |
|
|
} |
141 |
|
|
return dlreturn; |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
/* |
145 |
jds |
59 |
* Checks the list for a conflicting handle so we can issue |
146 |
aw0a |
1 |
* a more helpful warning, if need be, than the standard message. |
147 |
|
|
*/ |
148 |
jds |
59 |
static |
149 |
aw0a |
1 |
void AscCheckDuplicateLoad(CONST char *path) |
150 |
|
|
{ |
151 |
|
|
struct ascend_dlrecord *r; |
152 |
jds |
59 |
|
153 |
|
|
if (NULL == path) { |
154 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Null path"); |
155 |
jds |
59 |
return; |
156 |
|
|
} |
157 |
|
|
|
158 |
aw0a |
1 |
r = g_ascend_dllist; |
159 |
|
|
while (r != NULL) { |
160 |
|
|
if (strcmp(path,r->path)==0) { |
161 |
johnpye |
972 |
ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Attempt to load already loaded '%s'.",path); |
162 |
aw0a |
1 |
return; |
163 |
|
|
} |
164 |
|
|
r = r->next; |
165 |
|
|
} |
166 |
|
|
} |
167 |
|
|
|
168 |
johnpye |
791 |
|
169 |
johnpye |
427 |
/*----------------------------------------------- |
170 |
|
|
WINDOWS |
171 |
johnpye |
158 |
*/ |
172 |
johnpye |
427 |
#if defined(__WIN32__) |
173 |
|
|
# include <windows.h> |
174 |
johnpye |
158 |
|
175 |
johnpye |
485 |
int Asc_DynamicLoad(CONST char *path, CONST char *initFun){ |
176 |
aw0a |
1 |
HINSTANCE xlib; |
177 |
johnpye |
380 |
ExternalLibraryRegister_fptr_t install = NULL; |
178 |
aw0a |
1 |
|
179 |
jds |
59 |
if (NULL == path) { |
180 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path\n"); |
181 |
jds |
59 |
return 1; |
182 |
|
|
} |
183 |
|
|
|
184 |
aw0a |
1 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
185 |
|
|
/* |
186 |
|
|
* If the named library does not exist, if it's not loadable or if |
187 |
|
|
* it does not define the named install proc, report an error |
188 |
|
|
*/ |
189 |
|
|
|
190 |
|
|
xlib = LoadLibrary(path); |
191 |
|
|
if (xlib == NULL) { |
192 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"LoadLibrary failed\n'%s'",path); |
193 |
aw0a |
1 |
return 1; |
194 |
|
|
} |
195 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_NOTE,"LoadLibrary succeeded, '%s'\n",path); |
196 |
johnpye |
543 |
|
197 |
jds |
59 |
if (NULL != initFun) { |
198 |
wangym |
489 |
install = (int (*)(void))GetProcAddress(xlib,initFun); |
199 |
jds |
59 |
if (install == NULL) { |
200 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Required function '%s' not found", initFun); |
201 |
jds |
59 |
(void)FreeLibrary(xlib); |
202 |
|
|
return 1; |
203 |
jpye |
1597 |
#if 0 |
204 |
|
|
}else{ |
205 |
johnpye |
66 |
FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install); |
206 |
jpye |
1597 |
#endif |
207 |
johnpye |
62 |
} |
208 |
aw0a |
1 |
} |
209 |
jds |
59 |
if (0 != AscAddRecord(xlib,path)) { |
210 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)\n",path); |
211 |
aw0a |
1 |
} |
212 |
johnpye |
466 |
return (install == NULL) ? 0 : (*install)(); |
213 |
aw0a |
1 |
} |
214 |
johnpye |
485 |
#define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
215 |
johnpye |
427 |
|
216 |
|
|
# define UNLOAD FreeLibrary |
217 |
|
|
# define DLLSYM GetProcAddress |
218 |
|
|
# define DLL_CAST (HINSTANCE) |
219 |
|
|
# define ASC_DLERRSTRING "unknown" |
220 |
|
|
# define UNLOAD_SUCCESS TRUE |
221 |
|
|
|
222 |
aw0a |
1 |
#endif /* __WIN32__ */ |
223 |
jds |
61 |
|
224 |
johnpye |
427 |
/*----------------------------------------------- |
225 |
|
|
UNIX/LINUX |
226 |
|
|
*/ |
227 |
johnpye |
62 |
/* |
228 |
|
|
SOLARIS and LINUX |
229 |
|
|
*/ |
230 |
johnpye |
158 |
/* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */ |
231 |
johnpye |
62 |
/* |
232 |
johnpye |
190 |
From a quick Google, it appears that AIX 5.1 now provides dlfcn.h, |
233 |
johnpye |
158 |
so I'll remove the code that was emulating it here. -- johnpye |
234 |
johnpye |
62 |
*/ |
235 |
ben.allan |
467 |
#if (defined(sun) || defined(linux) || defined(__unix__) || defined(solaris) || defined(_AIX) || defined(_SGI_SOURCE)) |
236 |
johnpye |
158 |
# ifndef MACH |
237 |
|
|
# include <dlfcn.h> |
238 |
|
|
# else |
239 |
|
|
# error "MACH unsupported" |
240 |
ben.allan |
467 |
# endif /* mach */ |
241 |
jds |
59 |
|
242 |
aw0a |
1 |
int Asc_DynamicLoad(CONST char *path, CONST char *initFun) |
243 |
|
|
{ |
244 |
|
|
void *xlib; |
245 |
johnpye |
380 |
ExternalLibraryRegister_fptr_t install = NULL; |
246 |
jds |
59 |
|
247 |
|
|
if (NULL == path) { |
248 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null path"); |
249 |
jds |
59 |
return 1; |
250 |
|
|
} |
251 |
|
|
|
252 |
aw0a |
1 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
253 |
|
|
|
254 |
|
|
/* |
255 |
|
|
* If the named library does not exist, if it's not loadable or if |
256 |
|
|
* it does not define the named install proc, report an error |
257 |
|
|
*/ |
258 |
|
|
xlib = dlopen(path, 1); |
259 |
jds |
61 |
if (xlib == NULL) { |
260 |
johnpye |
190 |
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror()); |
261 |
aw0a |
1 |
return 1; |
262 |
|
|
} |
263 |
jds |
61 |
if (NULL != initFun) { |
264 |
johnpye |
1228 |
/* https://www.opengroup.org/sophocles/show_mail.tpl?source=L&listname=austin-review-l&id=2252 */ |
265 |
|
|
*(void**)(&install) = dlsym(xlib, initFun); |
266 |
jds |
61 |
if (install == NULL) { |
267 |
johnpye |
190 |
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror()); |
268 |
jds |
61 |
dlclose(xlib); |
269 |
|
|
return 1; |
270 |
|
|
} |
271 |
|
|
} |
272 |
johnpye |
190 |
|
273 |
jds |
59 |
if (0 != AscAddRecord(xlib,path)) { |
274 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path); |
275 |
aw0a |
1 |
} |
276 |
johnpye |
466 |
return (install == NULL) ? 0 : (*install)(); |
277 |
aw0a |
1 |
} |
278 |
johnpye |
485 |
#define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
279 |
aw0a |
1 |
|
280 |
johnpye |
427 |
# define UNLOAD dlclose |
281 |
|
|
# define DLLSYM dlsym |
282 |
|
|
# define DLL_CAST (void *) |
283 |
|
|
# define ASC_DLERRSTRING dlerror() |
284 |
|
|
# define UNLOAD_SUCCESS 0 |
285 |
|
|
|
286 |
johnpye |
158 |
#endif /* posix: linux, unix, solaris,sgi */ |
287 |
aw0a |
1 |
|
288 |
johnpye |
427 |
/*----------------------------------------------- |
289 |
|
|
HPUX |
290 |
|
|
*/ |
291 |
aw0a |
1 |
#ifdef __hpux |
292 |
|
|
/* |
293 |
johnpye |
427 |
Kirk Abbott last fiddled with the following, which was |
294 |
|
|
originally put in place my Michael Moore for an |
295 |
|
|
HP/UX 9.X Operating Sys back in 1993. Arrr. No idea if |
296 |
|
|
it still works. |
297 |
|
|
*/ |
298 |
aw0a |
1 |
|
299 |
johnpye |
158 |
# include <dl.h> |
300 |
|
|
# include <errno.h> |
301 |
aw0a |
1 |
|
302 |
|
|
int Asc_DynamicLoad(CONST char *path, CONST char *initFun) |
303 |
|
|
{ |
304 |
|
|
shl_t xlib; |
305 |
johnpye |
380 |
ExternalLibraryRegister_fptr_t install = NULL; |
306 |
aw0a |
1 |
int i; |
307 |
jds |
59 |
|
308 |
|
|
if (NULL == path) { |
309 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path"); |
310 |
jds |
59 |
return 1; |
311 |
|
|
} |
312 |
|
|
|
313 |
aw0a |
1 |
AscCheckDuplicateLoad(path); /* whine if we've see it before */ |
314 |
|
|
|
315 |
|
|
/* |
316 |
|
|
* If the named library does not exist, if it's not loadable or if |
317 |
|
|
* it does not define the named install proc, report an error |
318 |
|
|
*/ |
319 |
|
|
xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L); |
320 |
|
|
if (xlib == (shl_t) NULL) { |
321 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to load shared library: %s",strerror(errno)); |
322 |
aw0a |
1 |
return 1; |
323 |
|
|
} |
324 |
jds |
59 |
if (NULL != initFun) { |
325 |
|
|
i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install); |
326 |
|
|
if (i == -1) { |
327 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s': %s", |
328 |
jds |
59 |
initFun, strerror(errno)); |
329 |
|
|
shl_unload(xlib); /* baa */ |
330 |
|
|
return 1; |
331 |
aw0a |
1 |
} |
332 |
johnpye |
790 |
if(install == NULL) { |
333 |
|
|
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s'. Error type unknown",initFun); |
334 |
jds |
59 |
shl_unload(xlib); /* baa */ |
335 |
|
|
return 1; |
336 |
|
|
} |
337 |
aw0a |
1 |
} |
338 |
jds |
59 |
if (0 != AscAddRecord(xlib,path)) { |
339 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path); |
340 |
aw0a |
1 |
} |
341 |
johnpye |
466 |
return (install == NULL) ? 0 : (*install)(); |
342 |
aw0a |
1 |
} |
343 |
johnpye |
485 |
# define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */ |
344 |
aw0a |
1 |
|
345 |
johnpye |
158 |
# define UNLOAD shl_unload |
346 |
|
|
# define DLL_CAST (shl_t) |
347 |
|
|
# define ASC_DLERRSTRING "NULL definition" |
348 |
|
|
# define UNLOAD_SUCCESS 0 |
349 |
johnpye |
427 |
|
350 |
aw0a |
1 |
#endif /* __hpux */ |
351 |
|
|
|
352 |
johnpye |
427 |
/*----------------------------------------------- |
353 |
|
|
Did we get something from the above? |
354 |
johnpye |
158 |
*/ |
355 |
|
|
|
356 |
johnpye |
478 |
#ifndef ASCDL_OK |
357 |
johnpye |
427 |
# error "Unable to define an Asc_DynamicLoad function. Check your compiler options and installed system libraries." |
358 |
|
|
#endif |
359 |
|
|
|
360 |
|
|
/**----------------------------------------------- |
361 |
|
|
DYNAMIC UNLOADING |
362 |
|
|
*/ |
363 |
|
|
|
364 |
jds |
103 |
int Asc_DynamicUnLoad(CONST char *path) |
365 |
aw0a |
1 |
{ |
366 |
|
|
void *dlreturn; |
367 |
jds |
61 |
int retval; |
368 |
johnpye |
190 |
|
369 |
jds |
59 |
if (NULL == path) { |
370 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR, "Failed: Null path"); |
371 |
jds |
59 |
return -3; |
372 |
|
|
} |
373 |
|
|
|
374 |
aw0a |
1 |
dlreturn = AscDeleteRecord(path); |
375 |
|
|
if (dlreturn == NULL) { |
376 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR, "Unable to remember or unload %s", path); |
377 |
aw0a |
1 |
return -3; |
378 |
|
|
} |
379 |
johnpye |
790 |
CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s", path); |
380 |
johnpye |
190 |
/* |
381 |
jds |
61 |
* dlclose() returns 0 on success, FreeLibrary() returns TRUE. |
382 |
|
|
* A uniform convention is preferable, so trap and return 0 on success. |
383 |
|
|
*/ |
384 |
|
|
retval = UNLOAD(DLL_CAST dlreturn); |
385 |
|
|
return (retval == UNLOAD_SUCCESS) ? 0 : retval; |
386 |
aw0a |
1 |
} |
387 |
|
|
|
388 |
johnpye |
427 |
/**----------------------------------------------- |
389 |
|
|
DYNAMIC VARIABLE LINKING |
390 |
|
|
*/ |
391 |
jds |
103 |
void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol) |
392 |
aw0a |
1 |
{ |
393 |
|
|
void *dlreturn; |
394 |
|
|
void *symreturn; |
395 |
|
|
#ifdef __hpux |
396 |
|
|
int i; |
397 |
|
|
#endif |
398 |
|
|
|
399 |
jds |
59 |
if (libname == NULL) { |
400 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null libname"); |
401 |
aw0a |
1 |
return NULL; |
402 |
|
|
} |
403 |
jds |
59 |
if (symbol == NULL) { |
404 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null symbol"); |
405 |
jds |
59 |
return NULL; |
406 |
|
|
} |
407 |
|
|
|
408 |
aw0a |
1 |
dlreturn = AscFindDLRecord(libname); |
409 |
|
|
if (dlreturn == NULL) { |
410 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname); |
411 |
aw0a |
1 |
return NULL; |
412 |
|
|
} |
413 |
|
|
#ifdef __hpux |
414 |
|
|
i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn); |
415 |
|
|
if (i == -1) { |
416 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s (%s)", |
417 |
aw0a |
1 |
symbol, libname, strerror(errno)); |
418 |
|
|
symreturn = NULL; |
419 |
|
|
} |
420 |
jds |
103 |
#elif defined(__WIN32__) |
421 |
|
|
/* |
422 |
|
|
* Here's a bit of possibly-misdirected casting horror. |
423 |
|
|
* ISO C forbids casting between function and data pointers, so, naturally, |
424 |
|
|
* we cast between function and data pointers. Well, we don't have much |
425 |
|
|
* choice. GetProcAddress() returns a function pointer for both functions |
426 |
johnpye |
190 |
* and variables so we have to do the cast for variables. This is ok on |
427 |
|
|
* 32 bit Windows since the pointers are compatible. Then, to avoid |
428 |
|
|
* being reminded by the compiler that we're doing something illegal, |
429 |
jds |
103 |
* we apply convoluted casting to shut it up. |
430 |
|
|
* Oh, the crap you can find on the internet... JDS |
431 |
|
|
*/ |
432 |
|
|
*(FARPROC*)(&symreturn) = GetProcAddress((HINSTANCE)dlreturn, symbol); |
433 |
aw0a |
1 |
#else |
434 |
jds |
103 |
/* no problem on POSIX systems - dlsym() returns a void *. */ |
435 |
|
|
symreturn = dlsym(dlreturn, symbol); |
436 |
aw0a |
1 |
#endif |
437 |
|
|
if (symreturn == NULL) { |
438 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s",symbol,libname); |
439 |
|
|
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING); |
440 |
aw0a |
1 |
} |
441 |
|
|
return symreturn; |
442 |
|
|
} |
443 |
jds |
103 |
|
444 |
johnpye |
427 |
/**----------------------------------------------- |
445 |
|
|
DYNAMIC FUNCTION LINKING |
446 |
|
|
*/ |
447 |
jds |
103 |
DynamicF Asc_DynamicFunction(CONST char *libname, CONST char *symbol) |
448 |
|
|
{ |
449 |
|
|
void *dlreturn; |
450 |
|
|
DynamicF symreturn; |
451 |
|
|
#ifdef __hpux |
452 |
|
|
int i; |
453 |
|
|
#endif |
454 |
|
|
|
455 |
|
|
if (libname == NULL) { |
456 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null library name"); |
457 |
jds |
103 |
return NULL; |
458 |
|
|
} |
459 |
|
|
if (symbol == NULL) { |
460 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null function name"); |
461 |
jds |
103 |
return NULL; |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
dlreturn = AscFindDLRecord(libname); |
465 |
|
|
if (dlreturn == NULL) { |
466 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname); |
467 |
jds |
103 |
return NULL; |
468 |
|
|
} |
469 |
|
|
#ifdef __hpux |
470 |
|
|
i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn); |
471 |
|
|
if (i == -1) { |
472 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s (%s)", |
473 |
jds |
103 |
symbol, libname, strerror(errno)); |
474 |
|
|
symreturn = NULL; |
475 |
|
|
} |
476 |
|
|
#elif defined(__WIN32__) |
477 |
|
|
/* no problem on Windows - GetProcAddress() returns a function pointer. */ |
478 |
|
|
symreturn = (DynamicF)GetProcAddress((HINSTANCE)dlreturn, symbol); |
479 |
|
|
#else |
480 |
|
|
/* |
481 |
|
|
* Here's the corresponding bit of possibly-misdirected casting horror. |
482 |
|
|
* ISO C forbids casting between function and data pointers, so, naturally, |
483 |
johnpye |
190 |
* we cast between function and data pointers. Well, we don't have much |
484 |
jds |
103 |
* choice. dlsym() returns a void* for both variables and functions so we |
485 |
johnpye |
190 |
* have to do the cast for functions. This is ok on POSIX systems since the |
486 |
|
|
* pointer types are compatible. Then, to avoid being reminded by the |
487 |
|
|
* compiler that we're doing something illegal, we apply convoluted casting |
488 |
jds |
103 |
* to shut it up. Oh, the crap you can find on the internet... JDS |
489 |
|
|
*/ |
490 |
|
|
*(void**)(&symreturn) = dlsym(dlreturn, symbol); |
491 |
|
|
#endif |
492 |
|
|
if (symreturn == NULL) { |
493 |
johnpye |
790 |
ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s",symbol,libname); |
494 |
|
|
ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING); |
495 |
jds |
103 |
} |
496 |
|
|
return symreturn; |
497 |
|
|
} |
498 |
johnpye |
427 |
|
499 |
johnpye |
791 |
|
500 |
|
|
/*----------------------------------------------------------------------------- |
501 |
|
|
SEARCHING FOR LIBRARIES |
502 |
|
|
*/ |
503 |
|
|
|
504 |
jpye |
1597 |
|
505 |
johnpye |
791 |
/** |
506 |
jpye |
1597 |
Create a library filename according to platform standard naming. |
507 |
|
|
|
508 |
|
|
@param partialname The partial filename (eg 'mylib') |
509 |
|
|
@return Complete filename (eg 'libmylib.so' or 'mylib.dlll', etc) |
510 |
|
|
|
511 |
|
|
Basically just adds ASC_SHLIBPREFIX to start and ASC_SHLIBSUFFIX to end. |
512 |
|
|
|
513 |
|
|
No allowance made for 'soname' suffixes eg 'libsomething.so.1' etc. But |
514 |
|
|
that's probably OK as those methods aren't really applicable to dlopened |
515 |
|
|
libraries (eg the soname symlink mechanism breaks down). |
516 |
|
|
*/ |
517 |
|
|
char *dynaload_lib_filename(const char *partialname){ |
518 |
|
|
char *buffer; |
519 |
|
|
buffer = ASC_NEW_ARRAY(char,PATH_MAX); |
520 |
|
|
#if !defined(ASC_SHLIBSUFFIX) || !defined(ASC_SHLIBPREFIX) |
521 |
|
|
# error "ASC_SHLIBSUFFIX and ASC_SHLIBPREFIX are not defined" |
522 |
|
|
#endif |
523 |
|
|
snprintf(buffer,PATH_MAX,"%s%s%s",ASC_SHLIBPREFIX,partialname,ASC_SHLIBSUFFIX); |
524 |
|
|
return buffer; |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
|
528 |
|
|
/** |
529 |
johnpye |
791 |
A little structure to help with searching for libraries |
530 |
|
|
|
531 |
|
|
@see test_librarysearch |
532 |
|
|
*/ |
533 |
|
|
struct LibrarySearch{ |
534 |
|
|
struct FilePath *partialpath; |
535 |
|
|
char fullpath[PATH_MAX]; |
536 |
|
|
}; |
537 |
|
|
|
538 |
|
|
FilePathTestFn test_librarysearch; |
539 |
|
|
|
540 |
|
|
/** |
541 |
|
|
A 'test' function for passing to the ospath_searchpath_iterate function. |
542 |
|
|
This test function will return a match when a library having the required |
543 |
|
|
name is present in the fully resolved path. |
544 |
|
|
*/ |
545 |
|
|
int test_librarysearch(struct FilePath *path, void *userdata){ |
546 |
|
|
/* user data = the relative path, plus a place |
547 |
|
|
to store the full path when found */ |
548 |
|
|
FILE *f; |
549 |
|
|
struct LibrarySearch *ls; |
550 |
|
|
struct FilePath *fp; |
551 |
|
|
|
552 |
|
|
ls = (struct LibrarySearch *)userdata; |
553 |
|
|
fp = ospath_concat(path,ls->partialpath); |
554 |
|
|
if(fp==NULL){ |
555 |
|
|
char *tmp; |
556 |
|
|
tmp = ospath_str(path); |
557 |
|
|
CONSOLE_DEBUG("Unable to concatenate '%s'...",tmp); |
558 |
|
|
ospath_free_str(tmp); |
559 |
|
|
tmp = ospath_str(ls->partialpath); |
560 |
|
|
CONSOLE_DEBUG("... and '%s'...",tmp); |
561 |
|
|
ospath_free_str(tmp); |
562 |
|
|
return 0; |
563 |
|
|
} |
564 |
|
|
|
565 |
|
|
ospath_strncpy(fp,ls->fullpath,PATH_MAX); |
566 |
johnpye |
895 |
/* CONSOLE_DEBUG("SEARCHING FOR %s",ls->fullpath); */ |
567 |
johnpye |
791 |
|
568 |
|
|
f = ospath_fopen(fp,"r"); |
569 |
|
|
if(f==NULL){ |
570 |
|
|
ospath_free(fp); |
571 |
|
|
return 0; |
572 |
|
|
} |
573 |
|
|
fclose(f); |
574 |
|
|
|
575 |
|
|
/* ERROR_REPORTER_HERE(ASC_PROG_NOTE,"FOUND! %s\n",ls->fullpath); */ |
576 |
|
|
ospath_free(fp); |
577 |
|
|
return 1; |
578 |
|
|
} |
579 |
|
|
|
580 |
johnpye |
862 |
/** |
581 |
|
|
@DEPRECATED this function needs to be rewritten to use 'ImportHandler' |
582 |
|
|
functionality. |
583 |
|
|
*/ |
584 |
johnpye |
1072 |
char *SearchArchiveLibraryPath(CONST char *name, char *dpath, const char *envv){ |
585 |
johnpye |
791 |
struct FilePath *fp1, *fp2, *fp3; /* relative path */ |
586 |
|
|
char *s1; |
587 |
johnpye |
862 |
char *buffer; |
588 |
johnpye |
791 |
|
589 |
|
|
struct LibrarySearch ls; |
590 |
|
|
struct FilePath **sp; |
591 |
|
|
char *path, *foundpath; |
592 |
|
|
ospath_stat_t buf; |
593 |
|
|
FILE *f; |
594 |
|
|
|
595 |
|
|
fp1 = ospath_new_noclean(name); |
596 |
|
|
if(fp1==NULL){ |
597 |
|
|
ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",name); |
598 |
|
|
ospath_free(fp1); |
599 |
|
|
return NULL; |
600 |
|
|
} |
601 |
|
|
|
602 |
|
|
s1 = ospath_getfilestem(fp1); |
603 |
|
|
if(s1==NULL){ |
604 |
|
|
/* not a file, so fail... */ |
605 |
|
|
return NULL; |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
fp2 = ospath_getdir(fp1); |
609 |
|
|
if(fp2==NULL){ |
610 |
|
|
ERROR_REPORTER_HERE(ASC_PROG_ERR,"unable to retrieve file dir"); |
611 |
|
|
return NULL; |
612 |
|
|
} |
613 |
|
|
|
614 |
jpye |
1597 |
buffer = dynaload_lib_filename(s1); |
615 |
johnpye |
791 |
|
616 |
|
|
fp3 = ospath_new(buffer); |
617 |
johnpye |
862 |
ASC_FREE(buffer); |
618 |
johnpye |
791 |
ospath_free(fp1); |
619 |
|
|
fp1 = ospath_concat(fp2,fp3); |
620 |
|
|
ospath_free(fp2); |
621 |
|
|
ospath_free(fp3); |
622 |
|
|
ospath_free_str(s1); |
623 |
|
|
|
624 |
|
|
/* attempt to open "name" directly */ |
625 |
|
|
if(0==ospath_stat(fp1,&buf) && NULL!=(f = ospath_fopen(fp1,"r")) ){ |
626 |
|
|
char *tmp; |
627 |
|
|
tmp = ospath_str(fp1); |
628 |
|
|
CONSOLE_DEBUG("Library '%s' opened directly, without path search",tmp); |
629 |
|
|
ospath_free_str(tmp); |
630 |
|
|
fp2 = ospath_getabs(fp1); |
631 |
|
|
foundpath = ospath_str(fp2); |
632 |
|
|
ospath_free(fp2); |
633 |
|
|
fclose(f); |
634 |
|
|
}else{ |
635 |
|
|
|
636 |
|
|
ls.partialpath = fp1; |
637 |
|
|
|
638 |
|
|
path=Asc_GetEnv(envv); |
639 |
|
|
if(path==NULL){ |
640 |
johnpye |
895 |
/* CONSOLE_DEBUG("Library search path env var '%s' not found, using default path '%s'",envv,dpath); */ |
641 |
johnpye |
791 |
path=dpath; |
642 |
|
|
} |
643 |
|
|
|
644 |
|
|
/* CONSOLE_DEBUG("SEARCHPATH IS %s",path); */ |
645 |
|
|
sp = ospath_searchpath_new(path); |
646 |
|
|
|
647 |
|
|
if(NULL==ospath_searchpath_iterate(sp,&test_librarysearch,&ls)){ |
648 |
|
|
ospath_free(fp1); |
649 |
|
|
ospath_searchpath_free(sp); |
650 |
|
|
return NULL; |
651 |
|
|
} |
652 |
|
|
|
653 |
|
|
foundpath = ASC_NEW_ARRAY(char,strlen(ls.fullpath)+1); |
654 |
|
|
strcpy(foundpath,ls.fullpath); |
655 |
|
|
ospath_searchpath_free(sp); |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
ospath_free(fp1); |
659 |
|
|
return foundpath; |
660 |
|
|
} |