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