1/*
2 * load.c --
3 *
4 *	general purpose loader for shared libraries.
5 *	essentially the last 2 functions of 'imgInit.c'
6 *	(see 'Img' library by Jan Nijtmans).
7 *
8 * Copyright (c) 1996 Jan Nijtmans (nijtmans.nici.kun.nl)
9 * All rights reserved.
10 *
11 * CVS: $Id: load.c,v 1.5 1999/09/19 10:33:26 aku Exp $
12 */
13
14#include "transformInt.h"
15
16#define Offset(type,field) ((unsigned long) (((char *) &((type *) 0)->field)))
17
18/*
19 *----------------------------------------------------------------------
20 *
21 * Trf_LoadLibrary --
22 *
23 *	This procedure is called to load a shared library into memory.
24 *	If the extension is ".so" (e.g. Solaris, Linux) or ".sl" (HP-UX)
25 *	it is possible that the extension is appended or replaced with
26 *	a major version number. If the file cannot be found, the version
27 *	numbers will be stripped off one by one. e.g.
28 *
29 *	HP-UX:	libtiff.3.4	Linux,Solaris:	libtiff.so.3.4
30 *		libtiff.3			libtiff.so.3
31 *		libtiff.sl			libtiff.so
32 *
33 * Results:
34 *	TCL_OK if function succeeds. Otherwise TCL_ERROR while the
35 *	interpreter will contain an error-message. The last parameter
36 *	"num" contains the minimum number of symbols that is required
37 *	by the application to succeed. Only the first <num> symbols
38 *	will produce an error if they cannot be found.
39 *
40 * Side effects:
41 *	At least <num> Library functions become available by the
42 *	application.
43 *
44 *----------------------------------------------------------------------
45 */
46
47typedef struct Functions {
48    VOID *handle;
49    int (* first) _ANSI_ARGS_((void));
50    int (* next) _ANSI_ARGS_((void));
51} Functions;
52
53/* MS defines something under this name, avoid the collision
54 */
55
56#define TRF_LOAD_FAILED ((VOID *) -114)
57
58int
59Trf_LoadLibrary (interp, libName, handlePtr, symbols, num)
60    Tcl_Interp *interp;
61    CONST char *libName;
62    VOID **handlePtr;
63    char **symbols;
64    int num;
65{
66    VOID *handle = (VOID *) NULL;
67    Functions *lib = (Functions *) handlePtr;
68    char **p = (char **) &(lib->first);
69    char **q = symbols;
70    char buf[256];
71    char *r;
72    int length;
73
74    if (lib->handle != NULL) {
75      if (lib->handle == TRF_LOAD_FAILED) {
76	Tcl_AppendResult (interp, "cannot open ", (char*) NULL);
77	Tcl_AppendResult (interp, libName, (char*) NULL);
78      }
79      return (lib->handle != TRF_LOAD_FAILED) ? TCL_OK : TCL_ERROR;
80    }
81
82    length = strlen(libName);
83    strcpy(buf,libName);
84    handle = dlopen(buf, RTLD_NOW);
85
86    while (handle == NULL) {
87	if ((r = strrchr(buf,'.')) != NULL) {
88	    if ((r[1] < '0') || (r[1] > '9')) {
89	        Tcl_AppendResult (interp, "cannot open ", (char*) NULL);
90	        Tcl_AppendResult (interp, libName, (char*) NULL);
91	        Tcl_AppendResult (interp, ": ", (char*) NULL);
92	        Tcl_AppendResult (interp, dlerror (), (char*) NULL);
93		lib->handle = TRF_LOAD_FAILED;
94		return TCL_ERROR;
95	    }
96	    length = r - buf;
97	    *r = 0;
98	}
99	if (strchr(buf,'.') == NULL) {
100	    strcpy(buf+length,".sl");
101	    length += 3;
102	}
103	dlerror();
104	handle = dlopen(buf, RTLD_NOW);
105    }
106
107    buf[0] = '_';
108    while (*q) {
109	*p = (char *) dlsym(handle,*q);
110	if (*p == (char *)NULL) {
111	    strcpy(buf+1,*q);
112	    *p = (char *) dlsym(handle,buf);
113	    if ((num > 0) && (*p == (char *)NULL)) {
114	        Tcl_AppendResult (interp, "cannot open ", (char*) NULL);
115	        Tcl_AppendResult (interp, libName, (char*) NULL);
116	        Tcl_AppendResult (interp, ": symbol \"", (char*) NULL);
117	        Tcl_AppendResult (interp, *q, (char*) NULL);
118	        Tcl_AppendResult (interp, "\" not found", (char*) NULL);
119		dlclose(handle);
120		lib->handle = TRF_LOAD_FAILED;
121		return TCL_ERROR;
122	    }
123	}
124	q++; num--;
125	p += (Offset(Functions, next) - Offset(Functions, first)) /
126		sizeof(char *);
127    }
128    lib->handle = handle;
129
130    return TCL_OK;
131}
132
133/*
134 *----------------------------------------------------------------------
135 *
136 * Trf_LoadFailed --
137 *
138 *	Mark the loaded library as invalid. Remove it from memory
139 *	if possible. It will no longer be used in the future.
140 *
141 * Results:
142 *	None.
143 *
144 * Side effects:
145 *	Next time the same handle is used by TrfLoadLib, it will
146 *	fail immediately, without trying to load it.
147 *
148 *----------------------------------------------------------------------
149 */
150
151void
152Trf_LoadFailed (handlePtr)
153    VOID **handlePtr;
154{
155    if ((*handlePtr != NULL) && (*handlePtr != TRF_LOAD_FAILED)) {
156	/* Oops, still loaded. First remove it from menory */
157	dlclose(*handlePtr);
158    }
159    *handlePtr = TRF_LOAD_FAILED;
160}
161