]> git.saurik.com Git - wxWidgets.git/blob - src/iodbc/dlf.c
OnExit() is called for modules which were initialized even if the init of
[wxWidgets.git] / src / iodbc / dlf.c
1 /** dynamic library loader (mapping to svr4)
2
3 Copyright (C) 1995 by Ke Jin <kejin@empress.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 **/
15
16 #ifdef DLDAPI_OS2
17 # define INCL_DOSMODULEMGR /* Module Manager values */
18 # define INCL_DOSERRORS /* Error values */
19 # include <os2.h>
20 # include <stdio.h>
21 #endif
22
23 #include "wx/setup.h"
24 #include <../iodbc/dlf.h>
25 #include <errno.h>
26
27 #ifdef DLDAPI_DEFINED
28 # undef DLDAPI_DEFINED
29 #endif
30
31 #ifdef DLDAPI_SVR4_DLFCN
32 # define DLDAPI_DEFINED
33 static char sccsid[] = "@(#)dynamic load interface -- SVR4 dlfcn";
34 #endif
35
36 /*********************************
37 *
38 * HP/UX
39 *
40 *********************************/
41 #ifdef DLDAPI_HP_SHL
42 # define DLDAPI_DEFINED
43 # include <dl.h>
44
45 static char sccsid[] = "@(#)dynamic load interface -- HP/UX dl(shl)";
46
47 void* dlopen(char* path, int mode)
48 {
49 return (void*)shl_load((char*)(path), BIND_DEFERRED, 0L);
50 }
51
52 void* dlsym(void* hdll, char* sym)
53 {
54 void* symaddr = 0;
55 int ret;
56
57 if( ! hdll )
58 hdll = (void*)PROG_HANDLE;
59
60 /* Remember, a driver may export calls as function pointers
61 * (i.e. with type TYPE_DATA) rather than as functions
62 * (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we
63 * uses TYPE_UNDEFINED to cover all of them.
64 */
65 ret = shl_findsym((shl_t*)&hdll, sym, TYPE_UNDEFINED, &symaddr);
66
67 if( ret == -1 )
68 return 0;
69
70 return symaddr;
71 }
72
73 char* dlerror()
74 {
75 extern char* strerror();
76
77 return strerror(errno);
78 }
79
80 int dlclose(void* hdll)
81 {
82 return shl_unload((shl_t)hdll);
83 }
84
85 #endif /* end of HP/UX Seection */
86
87 /*********************************
88 *
89 * IBM AIX
90 *
91 *********************************/
92 #ifdef DLDAPI_AIX_LOAD
93 # define DLDAPI_DEFINED
94 # include <sys/ldr.h>
95 # include <sys/stat.h>
96 # include <nlist.h>
97
98 /*
99 * Following id sting is a copyright mark. Removing(i.e. use the
100 * source code in this .c file without include it or make it not
101 * appear in the final object file of AIX platform) or modifing
102 * it without permission from original author(kejin@empress.com)
103 * are copyright violation.
104 */
105 static char sccsid[]
106 = "@(#)dynamic load interface, Copyright(c) 1995 by Ke Jin";
107
108 # ifndef HTAB_SIZE
109 # define HTAB_SIZE 256
110 # endif
111
112 # define FACTOR 0.618039887 /* i.e. (sqrt(5) - 1)/2 */
113
114 # ifndef ENTRY_SYM
115 # define ENTRY_SYM ".__start" /* default entry point for aix */
116 # endif
117
118 typedef struct slot_s
119 {
120 char* sym;
121 long fdesc[3]; /* 12 bytes function descriptor */
122 struct slot_s* next;
123 } slot_t;
124
125 /* Note: on AIX, a function pointer actually points to a
126 * function descriptor, a 12 bytes data. The first 4 bytes
127 * is the virtual address of the function. The next 4 bytes
128 * is the virtual address of TOC (Table of Contents) of the
129 * object module the function belong to. The last 4 bytes
130 * are always 0 for C and Fortran functions. Every object
131 * module has an entry point (which can be specified at link
132 * time by -e ld option). iODBC driver manager requires ODBC
133 * driver shared library always use the default entry point
134 * (so you shouldn't use -e ld option when creating a driver
135 * share library). load() returns the function descriptor of
136 * a module's entry point. From which we can calculate function
137 * descriptors of other functions in the same module by using
138 * the fact that the load() doesn't change the relative
139 * offset of functions to their module entry point(i.e the
140 * offset in memory loaded by load() will be as same as in
141 * the module library file).
142 */
143
144 typedef slot_t* hent_t;
145 typedef struct nlist nlist_t;
146 typedef struct stat stat_t;
147
148 typedef struct obj
149 {
150 int dev; /* device id */
151 int ino; /* inode number */
152 char* path; /* file name */
153 int (*pentry)(); /* entry point of this share library */
154 int refn; /* number of reference */
155 hent_t htab[HTAB_SIZE];
156 struct obj*
157 next;
158 } obj_t;
159
160 static char* errmsg = 0;
161
162 static void init_htab(hent_t* ht)
163 /* initate a hashing table */
164 {
165 int i;
166
167 for(i=0; i<HTAB_SIZE; i++)
168 ht[i] = (slot_t*)0;
169
170 return;
171 }
172
173 static void clean_htab(hent_t* ht)
174 /* free all slots */
175 {
176 int i;
177 slot_t* ent;
178 slot_t* tent;
179
180 for(i = 0; i< HTAB_SIZE; i++)
181 {
182 for( ent = ht[i]; ent; )
183 {
184 tent = ent->next;
185
186 free(ent->sym);
187 free(ent);
188
189 ent = tent;
190 }
191
192 ht[i] = 0;
193 }
194
195 return;
196 }
197
198 static int hash(char* sym )
199 {
200 int a, key;
201 double f;
202
203 if( !sym || !*sym )
204 return 0;
205
206 for(key=*sym;*sym;sym++)
207 {
208 key += *sym;
209 a = key;
210
211 key = (int)( (a<<8) + (key>>8) );
212 key = (key>0)? key:-key;
213 }
214
215 f = key*FACTOR;
216 a = (int)f;
217
218 return (int)((HTAB_SIZE - 1)*( f - a ));
219 }
220
221 static hent_t search(hent_t* htab, char* sym)
222 /* search hashing table to find a matched slot */
223 {
224 int key;
225 slot_t* ent;
226
227 key = hash(sym);
228
229 for(ent = htab[key]; ent; ent = ent->next )
230 {
231 if(!strcmp(ent->sym, sym))
232 return ent;
233 }
234
235 return 0; /* no match */
236 }
237
238 static void insert(hent_t* htab, slot_t* ent)
239 /* insert a new slot to hashing table */
240 {
241 int key;
242
243 key = hash(ent->sym);
244
245 ent->next = htab[key];
246 htab[key] = ent;
247
248 return;
249 }
250
251 static slot_t* slot_alloc(char* sym)
252 /* allocate a new slot with symbol */
253 {
254 slot_t* ent;
255
256 ent = (slot_t*)malloc(sizeof(slot_t));
257
258 ent->sym = (char*)malloc(strlen(sym)+1);
259
260 if( ! ent->sym )
261 {
262 free(ent);
263 return 0;
264 }
265
266 strcpy( ent->sym, sym );
267
268 return ent;
269 }
270
271 static obj_t* obj_list = 0;
272
273 void* dlopen(char* file, int mode )
274 {
275 stat_t st;
276 obj_t* pobj;
277 char buf[1024];
278
279 if( ! file || ! *file )
280 {
281 errno = EINVAL;
282 return 0;
283 }
284
285 errno = 0;
286 errmsg = 0;
287
288 #if 0
289 if( file[0] != '/' && file[0] != '.' )
290 {
291 for(;;)
292 {
293 sprintf(buf, "/lib/%s", file);
294
295 if( stat( buf, &st ) )
296 {
297 file = buf;
298 break;
299 }
300
301 sprintf(buf, "/usr/lib/%s", file);
302
303 if( stat( buf, &st ) )
304 {
305 file = buf;
306 break;
307 }
308
309 if( stat( file, &st ) )
310 break;
311
312 return 0;
313 }
314 }
315 else
316 #endif
317 if( stat( file, &st ) )
318 return 0;
319
320 for( pobj = obj_list; pobj; pobj = pobj->next )
321 /* find a match object */
322 {
323 if( pobj->ino == st.st_ino
324 && pobj->dev == st.st_dev )
325 {
326 /* found a match. increase its
327 * reference count and return
328 * its address */
329 pobj->refn ++;
330 return pobj;
331 }
332 }
333
334 pobj = (obj_t*)malloc( sizeof(obj_t) );
335
336 if( ! pobj )
337 return 0;
338
339 pobj->path = (char*)malloc( strlen(file) + 1);
340
341 if( ! pobj->path )
342 {
343 free( pobj );
344 return 0;
345 }
346
347 strcpy( pobj->path, file );
348
349 pobj->dev = st.st_dev;
350 pobj->ino = st.st_ino;
351 pobj->refn = 1;
352
353 pobj->pentry = (int(*)())load(file, 0, 0);
354
355 if( ! pobj->pentry )
356 {
357 free( pobj->path );
358 free( pobj );
359 return 0;
360 }
361
362 init_htab(pobj->htab);
363
364 pobj->next = obj_list;
365 obj_list = pobj;
366
367 return pobj;
368 }
369
370 int dlclose(void* hobj)
371 {
372 obj_t* pobj = (obj_t*)hobj;
373 obj_t* tpobj;
374 int match = 0;
375
376 if( ! hobj )
377 {
378 errno = EINVAL;
379 return -1;
380 }
381
382 errno = 0;
383 errmsg = 0;
384
385 if( pobj == obj_list )
386 {
387 pobj->refn --;
388
389 if( pobj->refn )
390 return 0;
391
392 match = 1;
393 obj_list = pobj->next;
394 }
395
396 for( tpobj = obj_list; !match && tpobj; tpobj = tpobj->next )
397 {
398 if( tpobj->next == pobj )
399 {
400 pobj->refn --;
401
402 if( pobj->refn )
403 return 0;
404
405 match = 1;
406 tpobj->next = pobj->next;
407 }
408 }
409
410 if(match)
411 {
412 unload((void*)(pobj->pentry));
413 clean_htab(pobj->htab);
414 free(pobj->path);
415 free(pobj);
416 }
417
418 return 0;
419 }
420
421 char* dlerror()
422 {
423 extern char* sys_errlist[];
424
425 if( ! errmsg || ! errmsg[0] )
426 {
427 if( errno >= 0 )
428 return sys_errlist[errno];
429
430 return "";
431 }
432
433 return errmsg;
434 }
435
436 void* dlsym(void* hdl, char* sym)
437 {
438 nlist_t nl[3];
439 obj_t* pobj = (obj_t*)hdl;
440 slot_t* ent;
441 int (*fp)();
442 long lbuf[3];
443
444 if( !hdl || !(pobj->htab) || !sym || ! *sym )
445 {
446 errno = EINVAL;
447 return 0;
448 }
449
450 errno = 0;
451 errmsg = 0;
452
453 ent = search( pobj->htab, sym );
454
455 if( ent )
456 return ent->fdesc;
457
458 #define n_name _n._n_name
459
460 nl[0].n_name = ENTRY_SYM;
461 nl[1].n_name = sym;
462 nl[2].n_name = 0;
463
464 /* There is a potential problem here. If application
465 * did not pass a full path name, and changed the
466 * working directory after the load(), then nlist()
467 * will be unable to open the original shared library
468 * file to resolve the symbols. there are 3 ways to working
469 * round this: 1. convert to full pathname in driver
470 * manager. 2. applications always pass driver's full
471 * path name. 3. if driver itself don't support
472 * SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS
473 * as flag immidately after SQLConnect(), SQLDriverConnect()
474 * and SQLBrowseConnect() to force the driver manager
475 * resolving all will be used symbols.
476 */
477 if( nlist( pobj->path, nl) == -1 )
478 return 0;
479
480 if( ! nl[0].n_type && ! nl[0].n_value )
481 {
482 errmsg = "can't locate module entry symbol";
483 return 0;
484 }
485
486 /* Note: On AIX 3.x if the object library is not
487 * built with -g compiling option, .n_type field
488 * is always 0. While on 4.x it will be 32.
489 * On AIX 4.x, if the symbol is a entry point,
490 * n_value will be 0. However, one thing is for sure
491 * that if a symbol is not existance in the file,
492 * both .n_type and .n_value would be 0.
493 */
494
495 if( ! nl[1].n_type && ! nl[1].n_value )
496 {
497 errmsg = "symbol not existance in this module";
498 return 0;
499 }
500
501 ent = slot_alloc(sym);
502
503 if( ! ent )
504 return 0;
505
506 /* catch it with a slot in the hashing table */
507 insert(pobj->htab, ent);
508
509 memcpy(ent->fdesc, pobj->pentry, sizeof(ent->fdesc));
510
511 /* now ent->fdesc[0] is the virtual address of entry point
512 * and ent->fdesc[1] is the TOC of the module
513 */
514
515 /* let's calculate the virtual address of the symbol
516 * by adding a relative offset getting from the module
517 * file symbol table, i.e
518 *
519 * functin virtual address = entry point virtual address +
520 * + ( function offset in file - entry point offset in file )
521 */
522
523 (ent->fdesc)[0] = (ent->fdesc)[0] +
524 ( nl[1].n_value - nl[0].n_value );
525
526 /* return the function descriptor */
527 return ent->fdesc;
528 }
529
530 #endif /* end of IBM AIX Section */
531
532
533 /*********************************
534 *
535 * Windows 3.x, 95, NT
536 *
537 *********************************/
538 #ifdef DLDAPI_WINDOWS
539 # define DLDAPI_DEFINED
540 # include <windows.h>
541
542 void FAR* dlopen(char FAR* dll, int mode)
543 {
544 HINSTANCE hint;
545
546 if( dll == NULL )
547 {
548 return GetWindowWord( NULL, GWW_HINSTANCE );
549 }
550
551 hint = LoadLibrary(dll);
552
553 if( hint < HINSTANCE_ERROR )
554 {
555 return NULL;
556 }
557
558 return (void FAR*)hint;
559 }
560
561 void FAR* dlsym( void FAR* hdll, char FAR* sym )
562 {
563 return (void FAR*)GetProcAddress(hdll, sym);
564 }
565
566 char FAR* dlerror()
567 {
568 return 0L; /* unimplemented yet */
569 }
570
571 int dlclose(void FAR* hdll)
572 {
573 FreeLibrary((HINSTANCE)hdll);
574 }
575
576 #endif /* end of Windows family */
577
578 /*********************************
579 *
580 * OS/2 2.x, 3.x
581 *
582 *********************************/
583 #ifdef DLDAPI_OS2
584 # define DLDAPI_DEFINED
585 /*
586 * DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ...
587 */
588
589 void FAR* dlopen(char FAR* dll, int mode)
590 {
591 APIRET rc = NO_ERROR; /* API return code */
592 UCHAR LoadError[256] = ""; /* Area for Load fail. info */
593 HMODULE ModuleHandle = NULLHANDLE; /* Module handle */
594
595 if( dll == NULL || '\0' == *dll )
596 {
597 return NULL;
598 }
599
600 rc = NO_ERROR;
601 rc = DosLoadModule( LoadError, /* Failure info buffer */
602 sizeof(LoadError), /* Size of buffer */
603 dll, /* Module to load */
604 &ModuleHandle ); /* Module handle returned */
605 if (rc != NO_ERROR)
606 {
607 #ifdef DEBUG
608 fprintf( stderr,
609 "[dlf.c] dlopen: DosLoadModule(0x%08lX, %d, \"%s\", 0x%08lX) = %d\n",
610 &LoadError, sizeof(LoadError), dll, &ModuleHandle, rc
611 );
612 fprintf( stderr,
613 " ---> missing module '%s'\n",
614 LoadError );
615 #endif
616 return NULL;
617 }
618
619 return (void FAR*) ModuleHandle;
620
621 }
622
623 void FAR* dlsym( void FAR* hdll, char FAR* sym )
624 {
625 APIRET rc = NO_ERROR; /* API return code */
626 PFN ModuleAddress = NULL; /* Module address */
627
628 rc = DosQueryProcAddr( (HMODULE) hdll, 0, sym, &ModuleAddress );
629
630 return (void FAR*) (NO_ERROR == rc) ? ModuleAddress
631 : NULL;
632 }
633
634 char FAR* dlerror()
635 {
636 return 0L; /* unimplemented yet */
637 }
638
639 int dlclose(void FAR* hdll)
640 {
641 return DosFreeModule( (HMODULE) hdll );
642 }
643
644 #endif
645
646 /***********************************
647 *
648 * other platforms
649 *
650 ***********************************/
651 #ifdef DLDAPI_MAC
652 # define DLDAPI_DEFINED
653 #endif
654
655 #ifdef DLDAPI_NEXT
656 # define DLDAPI_DEFINED
657 #endif
658
659 #ifndef DLDAPI_DEFINED
660 # error "dynamic load editor undefined"
661 #endif