rearrange dynaload code to avoid some OS X issues
[imager.git] / dynaload.c
1 #if defined(OS_hpux)
2 #include <dl.h>
3 typedef shl_t minthandle_t;
4 #elif defined(WIN32)
5 #define WIN32_LEAN_AND_MEAN
6 #include <windows.h>
7 typedef HMODULE minthandle_t;
8 #undef WIN32_LEAN_AND_MEAN
9 #elif defined(OS_darwin)
10 #define DL_LOADONCEONLY
11 #define DLSYMUN
12 #undef environ
13 #undef bool
14
15 #import <mach-o/dyld.h>
16 typedef void *minthandle_t; 
17 #else 
18 #include <dlfcn.h>
19 typedef void *minthandle_t; 
20 #endif 
21
22 #include "plug.h"
23
24 struct DSO_handle_tag {
25   minthandle_t handle;
26   char *filename;
27   func_ptr *function_list;
28 };
29
30 #include "imager.h"
31 #include "dynaload.h"
32 /* #include "XSUB.h"  so we can compile on threaded perls */
33 #include "imageri.h"
34
35 static symbol_table_t symbol_table=
36   {
37     i_has_format,
38     ICL_set_internal,
39     ICL_info,
40     i_img_new,
41     i_img_empty,
42     i_img_empty_ch,
43     i_img_exorcise,
44     i_img_info,
45     i_img_setmask,
46     i_img_getmask,
47     i_box,
48     i_line,
49     i_arc,
50     i_copyto,
51     i_copyto_trans,
52     i_rubthru
53   };
54
55
56 /*
57   Dynamic loading works like this:
58   dynaload opens the shared object and
59   loads all the functions into an array of functions
60   it returns a string from the dynamic function that
61   can be supplied to the parser for evaling.
62 */
63
64 void
65 DSO_call(DSO_handle *handle,int func_index,HV* hv) {
66   mm_log((1,"DSO_call(handle 0x%X, func_index %d, hv 0x%X)\n",handle,func_index,hv));
67   (handle->function_list[func_index].iptr)((void*)hv);
68 }
69
70 func_ptr *
71 DSO_funclist(DSO_handle *handle) {
72   return handle->function_list;
73 }
74
75
76 #if defined( OS_hpux )
77
78 void*
79 DSO_open(char* file,char** evalstring) {
80   shl_t tt_handle;
81   void *d_handle,**plugin_symtab,**plugin_utiltab;
82   int  rc,*iptr, (*fptr)(int);
83   func_ptr *function_list;
84   DSO_handle *dso_handle;
85   void (*f)(void *s,void *u); /* these will just have to be void for now */
86   int i;
87
88   *evalstring=NULL;
89
90   mm_log( (1,"DSO_open(file '%s' (0x%08X), evalstring 0x%08X)\n",file,file,evalstring) );
91
92   if ( (tt_handle = shl_load(file, BIND_DEFERRED,0L)) == NULL) return NULL; 
93   if ( (shl_findsym(&tt_handle, I_EVALSTR,TYPE_UNDEFINED,(void*)evalstring))) return NULL;
94
95   /*
96   if ( (shl_findsym(&tt_handle, "symbol_table",TYPE_UNDEFINED,(void*)&plugin_symtab))) return NULL;
97   if ( (shl_findsym(&tt_handle, "util_table",TYPE_UNDEFINED,&plugin_utiltab))) return NULL;
98   (*plugin_symtab)=&symbol_table;
99   (*plugin_utiltab)=&i_UTIL_table;
100   */
101
102   if ( (shl_findsym(&tt_handle, I_INSTALL_TABLES ,TYPE_UNDEFINED, &f ))) return NULL; 
103  
104   mm_log( (1,"Calling install_tables\n") );
105   f(&symbol_table,&i_UTIL_table);
106   mm_log( (1,"Call ok.\n") ); 
107  
108   if ( (shl_findsym(&tt_handle, I_FUNCTION_LIST ,TYPE_UNDEFINED,(func_ptr*)&function_list))) return NULL; 
109   if ( (dso_handle=(DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) /* checked 17jul05 tonyc */
110     return NULL;
111
112   dso_handle->handle=tt_handle; /* needed to close again */
113   dso_handle->function_list=function_list;
114   if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */
115     free(dso_handle); return NULL;
116   }
117   strcpy(dso_handle->filename,file);
118
119   mm_log((1,"DSO_open <- (0x%X)\n",dso_handle));
120   return (void*)dso_handle;
121 }
122
123 undef_int
124 DSO_close(void *ptr) {
125   DSO_handle *handle=(DSO_handle*) ptr;
126   mm_log((1,"DSO_close(ptr 0x%X)\n",ptr));
127   return !shl_unload((handle->handle));
128 }
129
130 #elif defined(WIN32)
131
132 void *
133 DSO_open(char *file, char **evalstring) {
134   HMODULE d_handle;
135   func_ptr *function_list;
136   DSO_handle *dso_handle;
137   
138   void (*f)(void *s,void *u); /* these will just have to be void for now */
139
140   mm_log( (1,"DSO_open(file '%s' (0x%08X), evalstring 0x%08X)\n",file,file,evalstring) );
141
142   *evalstring = NULL;
143   if ((d_handle = LoadLibrary(file)) == NULL) {
144     mm_log((1, "DSO_open: LoadLibrary(%s) failed: %lu\n", file, GetLastError()));
145     return NULL;
146   }
147   if ( (*evalstring = (char *)GetProcAddress(d_handle, I_EVALSTR)) == NULL) {
148     mm_log((1,"DSO_open: GetProcAddress didn't fine '%s': %lu\n", I_EVALSTR, GetLastError()));
149     FreeLibrary(d_handle);
150     return NULL;
151   }
152   if ((f = (void (*)(void *, void*))GetProcAddress(d_handle, I_INSTALL_TABLES)) == NULL) {
153     mm_log((1, "DSO_open: GetProcAddress didn't find '%s': %lu\n", I_INSTALL_TABLES, GetLastError()));
154     FreeLibrary(d_handle);
155     return NULL;
156   }
157   mm_log((1, "Calling install tables\n"));
158   f(&symbol_table, &i_UTIL_table);
159   mm_log((1, "Call ok\n"));
160   
161   if ( (function_list = (func_ptr *)GetProcAddress(d_handle, I_FUNCTION_LIST)) == NULL) {
162     mm_log((1, "DSO_open: GetProcAddress didn't find '%s': %lu\n", I_FUNCTION_LIST, GetLastError()));
163     FreeLibrary(d_handle);
164     return NULL;
165   }
166   if ( (dso_handle = (DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) { /* checked 17jul05 tonyc */
167     mm_log( (1, "DSO_Open: out of memory\n") );
168     FreeLibrary(d_handle);
169     return NULL;
170   }
171   dso_handle->handle=d_handle; /* needed to close again */
172   dso_handle->function_list=function_list;
173   if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */
174     free(dso_handle);
175     FreeLibrary(d_handle); 
176     return NULL; 
177   }
178   strcpy(dso_handle->filename,file);
179
180   mm_log( (1,"DSO_open <- 0x%X\n",dso_handle) );
181   return (void*)dso_handle;
182
183 }
184
185 undef_int
186 DSO_close(void *ptr) {
187   DSO_handle *handle = (DSO_handle *)ptr;
188   BOOL result = FreeLibrary(handle->handle);
189   free(handle->filename);
190   free(handle);
191
192   return result;
193 }
194
195 #else
196
197 /* OS/2 has no dlclose; Perl doesn't provide one. */
198 #ifdef __EMX__ /* OS/2 */
199 int
200 dlclose(minthandle_t h) {
201   return DosFreeModule(h) ? -1 : 0;
202 }
203 #endif /* __EMX__ */
204
205 #ifdef OS_darwin
206
207 #import <mach-o/dyld.h>
208
209 static char *dl_error = "unknown";
210
211 static char *dlopen(char *path, int mode /* mode is ignored */)
212 {
213   int dyld_result;
214   NSObjectFileImage ofile;
215   NSModule handle = NULL;
216
217
218
219   dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
220   if (dyld_result != NSObjectFileImageSuccess)
221     {
222      switch (dyld_result) {
223        case NSObjectFileImageFailure:
224            dl_error = "object file setup failure";
225            break;
226        case NSObjectFileImageInappropriateFile:
227            dl_error = "not a Mach-O MH_BUNDLE file type";
228            break;
229        case NSObjectFileImageArch:
230            dl_error = "no object for this architecture";
231            break;
232        case NSObjectFileImageFormat:
233            dl_error = "bad object file format";
234            break;
235        case NSObjectFileImageAccess:
236            dl_error = "can't read object file";
237            break;
238        default:
239            dl_error = "unknown error from NSCreateObjectFileImageFromFile()";
240            break;
241      }
242     }
243     else
244       {
245         // NSLinkModule will cause the run to abort on any link error's
246         // not very friendly but the error recovery functionality is limited.
247         handle = NSLinkModule(ofile, path, TRUE);
248       }
249
250   return handle;
251 }
252
253 static void *
254 dlsym(void *handle, char *symbol)
255 {
256   void *addr;
257
258   if (NSIsSymbolNameDefined(symbol))
259   {
260     addr = NSAddressOfSymbol(NSLookupAndBindSymbol(symbol));
261   }
262   else
263   {
264     dl_error = "cannot find symbol";
265     addr = NULL;
266   }
267
268   return addr;
269 }
270
271 static int dlclose(void *handle) /* stub only */
272 {
273   return 0;
274 }
275
276 static char *dlerror(void) /* stub only */
277 {
278   printf("Error occurred\n");
279   return dl_error; 
280 }
281
282 #define RTLD_LAZY 0
283
284 #endif 
285
286 void*
287 DSO_open(char* file,char** evalstring) {
288   void *d_handle;
289   func_ptr *function_list;
290   DSO_handle *dso_handle;
291
292   void (*f)(void *s,void *u); /* these will just have to be void for now */
293   
294   *evalstring=NULL;
295
296   mm_log( (1,"DSO_open(file '%s' (0x%08X), evalstring 0x%08X)\n",file,file,evalstring) );
297
298   if ( (d_handle = dlopen(file, RTLD_LAZY)) == NULL) {
299     mm_log( (1,"DSO_open: dlopen failed: %s.\n",dlerror()) );
300     return NULL;
301   }
302
303   if ( (*evalstring = (char *)dlsym(d_handle, I_EVALSTR)) == NULL) {
304     mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_EVALSTR,dlerror()) );
305     return NULL;
306   }
307
308   /*
309
310     I'll just leave this thing in here for now if I need it real soon
311
312    mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_SYMBOL_TABLE ));
313    if ( (plugin_symtab = dlsym(d_handle, I_SYMBOL_TABLE)) == NULL) {
314      mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_SYMBOL_TABLE,dlerror()) );
315      return NULL;
316    }
317   
318    mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_UTIL_TABLE ));
319     if ( (plugin_utiltab = dlsym(d_handle, I_UTIL_TABLE)) == NULL) {
320      mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_UTIL_TABLE,dlerror()) );
321      return NULL;
322    }
323
324   */
325
326   f = (void(*)(void *s,void *u))dlsym(d_handle, I_INSTALL_TABLES);
327   mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_INSTALL_TABLES ));
328   if ( (f = (void(*)(void *s,void *u))dlsym(d_handle, I_INSTALL_TABLES)) == NULL) {
329     mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_INSTALL_TABLES,dlerror()) );
330     return NULL;
331   }
332
333   mm_log( (1,"Calling install_tables\n") );
334   f(&symbol_table,&i_UTIL_table);
335   mm_log( (1,"Call ok.\n") );
336
337   /* (*plugin_symtab)=&symbol_table;
338      (*plugin_utiltab)=&i_UTIL_table; */
339   
340   mm_log( (1,"DSO_open: going to dlsym '%s'\n", I_FUNCTION_LIST ));
341   if ( (function_list=(func_ptr *)dlsym(d_handle, I_FUNCTION_LIST)) == NULL) {
342     mm_log( (1,"DSO_open: dlsym didn't find '%s': %s.\n",I_FUNCTION_LIST,dlerror()) );
343     return NULL;
344   }
345   
346   if ( (dso_handle=(DSO_handle*)malloc(sizeof(DSO_handle))) == NULL) /* checked 17jul05 tonyc */
347     return NULL;
348   
349   dso_handle->handle=d_handle; /* needed to close again */
350   dso_handle->function_list=function_list;
351   if ( (dso_handle->filename=(char*)malloc(strlen(file)+1)) == NULL) { /* checked 17jul05 tonyc */
352     free(dso_handle); 
353     return NULL;
354   }
355   strcpy(dso_handle->filename,file);
356
357   mm_log( (1,"DSO_open <- 0x%X\n",dso_handle) );
358   return (void*)dso_handle;
359 }
360
361 undef_int
362 DSO_close(void *ptr) {
363   DSO_handle *handle;
364   mm_log((1,"DSO_close(ptr 0x%X)\n",ptr));
365   handle=(DSO_handle*) ptr;
366   return !dlclose(handle->handle);
367 }
368
369 #endif
370