Commit | Line | Data |
---|---|---|
c692d670 | 1 | #include "dlfcn.h" |
2d766320 IZ |
2 | #include "string.h" |
3 | #include "stdio.h" | |
c692d670 | 4 | |
5 | #define INCL_BASE | |
6 | #include <os2.h> | |
622913ab IZ |
7 | #include <float.h> |
8 | #include <stdlib.h> | |
c692d670 | 9 | |
10 | static ULONG retcode; | |
ed344e4f | 11 | static char fail[300]; |
c692d670 | 12 | |
622913ab IZ |
13 | static ULONG dllHandle; |
14 | static int handle_found; | |
15 | static int handle_loaded; | |
5c728af0 IZ |
16 | #ifdef PERL_CORE |
17 | ||
18 | #include "EXTERN.h" | |
19 | #include "perl.h" | |
20 | ||
21 | #else | |
22 | ||
9fed8b87 IZ |
23 | char *os2error(int rc); |
24 | ||
5c728af0 IZ |
25 | #endif |
26 | ||
622913ab IZ |
27 | #ifdef DLOPEN_INITTERM |
28 | unsigned long _DLL_InitTerm(unsigned long modHandle, unsigned long flag) | |
29 | { | |
30 | switch (flag) { | |
31 | case 0: /* INIT */ | |
32 | /* Save handle */ | |
33 | dllHandle = modHandle; | |
34 | handle_found = 1; | |
35 | return TRUE; | |
36 | ||
37 | case 1: /* TERM */ | |
38 | handle_found = 0; | |
39 | dllHandle = (unsigned long)NULLHANDLE; | |
40 | return TRUE; | |
41 | } | |
42 | ||
43 | return FALSE; | |
44 | } | |
45 | ||
46 | #endif | |
47 | ||
48 | HMODULE | |
49 | find_myself(void) | |
50 | { | |
51 | ||
52 | static APIRET APIENTRY (*pDosQueryModFromEIP) (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf, | |
53 | ULONG * Offset, ULONG Address); | |
54 | HMODULE doscalls_h, mod; | |
55 | static int failed; | |
56 | ULONG obj, offset, rc; | |
57 | char buf[260]; | |
58 | ||
59 | if (failed) | |
60 | return 0; | |
61 | failed = 1; | |
62 | doscalls_h = (HMODULE)dlopen("DOSCALLS",0); | |
63 | if (!doscalls_h) | |
64 | return 0; | |
65 | /* {&doscalls_handle, NULL, 360}, */ /* DosQueryModFromEIP */ | |
66 | rc = DosQueryProcAddr(doscalls_h, 360, 0, (PFN*)&pDosQueryModFromEIP); | |
67 | if (rc) | |
68 | return 0; | |
69 | rc = pDosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)dlopen); | |
70 | if (rc) | |
71 | return 0; | |
72 | failed = 0; | |
73 | handle_found = 1; | |
74 | dllHandle = mod; | |
75 | return mod; | |
76 | } | |
77 | ||
c692d670 | 78 | void * |
35bc1fdc | 79 | dlopen(const char *path, int mode) |
c692d670 | 80 | { |
81 | HMODULE handle; | |
5c728af0 IZ |
82 | char tmp[260]; |
83 | const char *beg, *dot; | |
c692d670 | 84 | ULONG rc; |
622913ab | 85 | unsigned fpflag = _control87(0,0); |
c692d670 | 86 | |
ed344e4f | 87 | fail[0] = 0; |
622913ab IZ |
88 | if (!path) { /* Our own handle. */ |
89 | if (handle_found || find_myself()) { | |
90 | char dllname[260]; | |
91 | ||
92 | if (handle_loaded) | |
93 | return (void*)dllHandle; | |
94 | rc = DosQueryModuleName(dllHandle, sizeof(dllname), dllname); | |
95 | if (rc) { | |
96 | strcpy(fail, "can't find my DLL name by the handle"); | |
97 | retcode = rc; | |
98 | return 0; | |
99 | } | |
100 | rc = DosLoadModule(fail, sizeof fail, dllname, &handle); | |
101 | if (rc) { | |
102 | strcpy(fail, "can't load my own DLL"); | |
103 | retcode = rc; | |
104 | return 0; | |
105 | } | |
106 | handle_loaded = 1; | |
107 | goto ret; | |
108 | } | |
109 | retcode = ERROR_MOD_NOT_FOUND; | |
110 | strcpy(fail, "can't load from myself: compiled without -DDLOPEN_INITTERM"); | |
111 | return 0; | |
112 | } | |
35bc1fdc | 113 | if ((rc = DosLoadModule(fail, sizeof fail, (char*)path, &handle)) == 0) |
622913ab | 114 | goto ret; |
c692d670 | 115 | |
116 | retcode = rc; | |
117 | ||
35bc1fdc IZ |
118 | if (strlen(path) >= sizeof(tmp)) |
119 | return NULL; | |
120 | ||
c692d670 | 121 | /* Not found. Check for non-FAT name and try truncated name. */ |
122 | /* Don't know if this helps though... */ | |
123 | for (beg = dot = path + strlen(path); | |
124 | beg > path && !strchr(":/\\", *(beg-1)); | |
125 | beg--) | |
126 | if (*beg == '.') | |
127 | dot = beg; | |
128 | if (dot - beg > 8) { | |
129 | int n = beg+8-path; | |
35bc1fdc | 130 | |
c692d670 | 131 | memmove(tmp, path, n); |
132 | memmove(tmp+n, dot, strlen(dot)+1); | |
133 | if (DosLoadModule(fail, sizeof fail, tmp, &handle) == 0) | |
622913ab | 134 | goto ret; |
c692d670 | 135 | } |
622913ab | 136 | handle = 0; |
c692d670 | 137 | |
622913ab IZ |
138 | ret: |
139 | _control87(fpflag, MCW_EM); /* Some modules reset FP flags on load */ | |
140 | return (void *)handle; | |
c692d670 | 141 | } |
142 | ||
622913ab IZ |
143 | #define ERROR_WRONG_PROCTYPE 0xffffffff |
144 | ||
c692d670 | 145 | void * |
35bc1fdc | 146 | dlsym(void *handle, const char *symbol) |
c692d670 | 147 | { |
148 | ULONG rc, type; | |
149 | PFN addr; | |
150 | ||
ed344e4f | 151 | fail[0] = 0; |
c692d670 | 152 | rc = DosQueryProcAddr((HMODULE)handle, 0, symbol, &addr); |
153 | if (rc == 0) { | |
154 | rc = DosQueryProcType((HMODULE)handle, 0, symbol, &type); | |
155 | if (rc == 0 && type == PT_32BIT) | |
156 | return (void *)addr; | |
622913ab | 157 | rc = ERROR_WRONG_PROCTYPE; |
c692d670 | 158 | } |
159 | retcode = rc; | |
160 | return NULL; | |
161 | } | |
162 | ||
163 | char * | |
164 | dlerror(void) | |
165 | { | |
ed344e4f | 166 | static char buf[700]; |
c692d670 | 167 | ULONG len; |
9fed8b87 | 168 | char *err; |
c692d670 | 169 | |
170 | if (retcode == 0) | |
171 | return NULL; | |
622913ab IZ |
172 | if (retcode == ERROR_WRONG_PROCTYPE) |
173 | err = "Wrong procedure type"; | |
174 | else | |
175 | err = os2error(retcode); | |
9fed8b87 IZ |
176 | len = strlen(err); |
177 | if (len > sizeof(buf) - 1) | |
178 | len = sizeof(buf) - 1; | |
179 | strncpy(buf, err, len+1); | |
622913ab | 180 | if (fail[0] && len + strlen(fail) < sizeof(buf) - 100) |
9fed8b87 | 181 | sprintf(buf + len, ", possible problematic module: '%s'", fail); |
c692d670 | 182 | retcode = 0; |
183 | return buf; | |
184 | } | |
185 | ||
403d6f8e GS |
186 | int |
187 | dlclose(void *handle) | |
188 | { | |
189 | ULONG rc; | |
190 | ||
191 | if ((rc = DosFreeModule((HMODULE)handle)) == 0) return 0; | |
192 | ||
193 | retcode = rc; | |
194 | return 2; | |
195 | } |