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