Commit | Line | Data |
c692d670 |
1 | #include "dlfcn.h" |
2d766320 |
2 | #include "string.h" |
3 | #include "stdio.h" |
c692d670 |
4 | |
5 | #define INCL_BASE |
6 | #include <os2.h> |
622913ab |
7 | #include <float.h> |
8 | #include <stdlib.h> |
c692d670 |
9 | |
10 | static ULONG retcode; |
ed344e4f |
11 | static char fail[300]; |
c692d670 |
12 | |
622913ab |
13 | static ULONG dllHandle; |
14 | static int handle_found; |
15 | static int handle_loaded; |
5c728af0 |
16 | #ifdef PERL_CORE |
17 | |
18 | #include "EXTERN.h" |
19 | #include "perl.h" |
20 | |
21 | #else |
22 | |
9fed8b87 |
23 | char *os2error(int rc); |
24 | |
5c728af0 |
25 | #endif |
26 | |
622913ab |
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 |
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 |
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 |
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 |
138 | ret: |
139 | _control87(fpflag, MCW_EM); /* Some modules reset FP flags on load */ |
140 | return (void *)handle; |
c692d670 |
141 | } |
142 | |
622913ab |
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 |
172 | if (retcode == ERROR_WRONG_PROCTYPE) |
173 | err = "Wrong procedure type"; |
174 | else |
175 | err = os2error(retcode); |
9fed8b87 |
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 |
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 | } |