1 | #define INCL_DOS
|
---|
2 | #define INCL_NOPM
|
---|
3 | #define INCL_DOSFILEMGR
|
---|
4 | #define INCL_DOSMEMMGR
|
---|
5 | #define INCL_DOSERRORS
|
---|
6 | #define INCL_WINERRORS
|
---|
7 | #define INCL_WINSYS
|
---|
8 | /* These 3 are needed for compile if os2.h includes os2tk.h, not os2emx.h */
|
---|
9 | #define INCL_DOSPROCESS
|
---|
10 | #define SPU_DISABLESUPPRESSION 0
|
---|
11 | #define SPU_ENABLESUPPRESSION 1
|
---|
12 | #include <os2.h>
|
---|
13 | #include "dlfcn.h"
|
---|
14 | #include <emx/syscalls.h>
|
---|
15 | #include <sys/emxload.h>
|
---|
16 |
|
---|
17 | #include <sys/uflags.h>
|
---|
18 |
|
---|
19 | /*
|
---|
20 | * Various Unix compatibility functions for OS/2
|
---|
21 | */
|
---|
22 |
|
---|
23 | #include <stdio.h>
|
---|
24 | #include <errno.h>
|
---|
25 | #include <limits.h>
|
---|
26 | #include <process.h>
|
---|
27 | #include <fcntl.h>
|
---|
28 | #include <pwd.h>
|
---|
29 | #include <grp.h>
|
---|
30 |
|
---|
31 | #define PERLIO_NOT_STDIO 0
|
---|
32 |
|
---|
33 | #include "EXTERN.h"
|
---|
34 | #include "perl.h"
|
---|
35 |
|
---|
36 | enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full,
|
---|
37 | mod_name_C_function = 0x100, mod_name_HMODULE = 0x200};
|
---|
38 |
|
---|
39 | /* Find module name to which *this* subroutine is compiled */
|
---|
40 | #define module_name(how) module_name_at(&module_name_at, how)
|
---|
41 |
|
---|
42 | static SV* module_name_at(void *pp, enum module_name_how how);
|
---|
43 |
|
---|
44 | void
|
---|
45 | croak_with_os2error(char *s)
|
---|
46 | {
|
---|
47 | Perl_croak_nocontext("%s: %s", s, os2error(Perl_rc));
|
---|
48 | }
|
---|
49 |
|
---|
50 | struct PMWIN_entries_t PMWIN_entries;
|
---|
51 |
|
---|
52 | /*****************************************************************************/
|
---|
53 | /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
|
---|
54 |
|
---|
55 | struct dll_handle_t {
|
---|
56 | const char *modname;
|
---|
57 | HMODULE handle;
|
---|
58 | int requires_pm;
|
---|
59 | };
|
---|
60 |
|
---|
61 | static struct dll_handle_t dll_handles[] = {
|
---|
62 | {"doscalls", 0, 0},
|
---|
63 | {"tcp32dll", 0, 0},
|
---|
64 | {"pmwin", 0, 1},
|
---|
65 | {"rexx", 0, 0},
|
---|
66 | {"rexxapi", 0, 0},
|
---|
67 | {"sesmgr", 0, 0},
|
---|
68 | {"pmshapi", 0, 1},
|
---|
69 | {"pmwp", 0, 1},
|
---|
70 | {"pmgpi", 0, 1},
|
---|
71 | {NULL, 0},
|
---|
72 | };
|
---|
73 |
|
---|
74 | enum dll_handle_e {
|
---|
75 | dll_handle_doscalls,
|
---|
76 | dll_handle_tcp32dll,
|
---|
77 | dll_handle_pmwin,
|
---|
78 | dll_handle_rexx,
|
---|
79 | dll_handle_rexxapi,
|
---|
80 | dll_handle_sesmgr,
|
---|
81 | dll_handle_pmshapi,
|
---|
82 | dll_handle_pmwp,
|
---|
83 | dll_handle_pmgpi,
|
---|
84 | dll_handle_LAST,
|
---|
85 | };
|
---|
86 |
|
---|
87 | #define doscalls_handle (dll_handles[dll_handle_doscalls])
|
---|
88 | #define tcp_handle (dll_handles[dll_handle_tcp32dll])
|
---|
89 | #define pmwin_handle (dll_handles[dll_handle_pmwin])
|
---|
90 | #define rexx_handle (dll_handles[dll_handle_rexx])
|
---|
91 | #define rexxapi_handle (dll_handles[dll_handle_rexxapi])
|
---|
92 | #define sesmgr_handle (dll_handles[dll_handle_sesmgr])
|
---|
93 | #define pmshapi_handle (dll_handles[dll_handle_pmshapi])
|
---|
94 | #define pmwp_handle (dll_handles[dll_handle_pmwp])
|
---|
95 | #define pmgpi_handle (dll_handles[dll_handle_pmgpi])
|
---|
96 |
|
---|
97 | /* The following local-scope data is not yet included:
|
---|
98 | fargs.140 // const => OK
|
---|
99 | ino.165 // locked - and the access is almost cosmetic
|
---|
100 | layout_table.260 // startup only, locked
|
---|
101 | osv_res.257 // startup only, locked
|
---|
102 | old_esp.254 // startup only, locked
|
---|
103 | priors // const ==> OK
|
---|
104 | use_my_flock.283 // locked
|
---|
105 | emx_init_done.268 // locked
|
---|
106 | dll_handles // locked
|
---|
107 | hmtx_emx_init.267 // THIS is the lock for startup
|
---|
108 | perlos2_state_mutex // THIS is the lock for all the rest
|
---|
109 | BAD:
|
---|
110 | perlos2_state // see below
|
---|
111 | */
|
---|
112 | /* The following global-scope data is not yet included:
|
---|
113 | OS2_Perl_data
|
---|
114 | pthreads_states // const now?
|
---|
115 | start_thread_mutex
|
---|
116 | thread_join_count // protected
|
---|
117 | thread_join_data // protected
|
---|
118 | tmppath
|
---|
119 |
|
---|
120 | pDosVerifyPidTid
|
---|
121 |
|
---|
122 | Perl_OS2_init3() - should it be protected?
|
---|
123 | */
|
---|
124 | OS2_Perl_data_t OS2_Perl_data;
|
---|
125 |
|
---|
126 | static struct perlos2_state_t {
|
---|
127 | int po2__my_pwent; /* = -1; */
|
---|
128 | int po2_DOS_harderr_state; /* = -1; */
|
---|
129 | signed char po2_DOS_suppression_state; /* = -1; */
|
---|
130 |
|
---|
131 | PFN po2_ExtFCN[ORD_NENTRIES]; /* Labeled by ord ORD_*. */
|
---|
132 | /* struct PMWIN_entries_t po2_PMWIN_entries; */
|
---|
133 |
|
---|
134 | int po2_emx_wasnt_initialized;
|
---|
135 |
|
---|
136 | char po2_fname[9];
|
---|
137 | int po2_rmq_cnt;
|
---|
138 |
|
---|
139 | int po2_grent_cnt;
|
---|
140 |
|
---|
141 | char *po2_newp;
|
---|
142 | char *po2_oldp;
|
---|
143 | int po2_newl;
|
---|
144 | int po2_oldl;
|
---|
145 | int po2_notfound;
|
---|
146 | char po2_mangle_ret[STATIC_FILE_LENGTH+1];
|
---|
147 | ULONG po2_os2_dll_fake;
|
---|
148 | ULONG po2_os2_mytype;
|
---|
149 | ULONG po2_os2_mytype_ini;
|
---|
150 | int po2_pidtid_lookup;
|
---|
151 | struct passwd po2_pw;
|
---|
152 |
|
---|
153 | int po2_pwent_cnt;
|
---|
154 | char po2_pthreads_state_buf[80];
|
---|
155 | char po2_os2error_buf[300];
|
---|
156 | /* There is no big sense to make it thread-specific, since signals
|
---|
157 | are delivered to thread 1 only. XXXX Maybe make it into an array? */
|
---|
158 | int po2_spawn_pid;
|
---|
159 | int po2_spawn_killed;
|
---|
160 |
|
---|
161 | jmp_buf po2_at_exit_buf;
|
---|
162 | int po2_longjmp_at_exit;
|
---|
163 | int po2_emx_runtime_init; /* If 1, we need to manually init it */
|
---|
164 | int po2_emx_exception_init; /* If 1, we need to manually set it */
|
---|
165 | int po2_emx_runtime_secondary;
|
---|
166 | char* (*po2_perllib_mangle_installed)(char *s, unsigned int l);
|
---|
167 | char* po2_perl_sh_installed;
|
---|
168 | PGINFOSEG po2_gTable;
|
---|
169 | PLINFOSEG po2_lTable;
|
---|
170 | } perlos2_state = {
|
---|
171 | -1, /* po2__my_pwent */
|
---|
172 | -1, /* po2_DOS_harderr_state */
|
---|
173 | -1, /* po2_DOS_suppression_state */
|
---|
174 | };
|
---|
175 |
|
---|
176 | #define Perl_po2() (&perlos2_state)
|
---|
177 |
|
---|
178 | #define ExtFCN (Perl_po2()->po2_ExtFCN)
|
---|
179 | /* #define PMWIN_entries (Perl_po2()->po2_PMWIN_entries) */
|
---|
180 | #define emx_wasnt_initialized (Perl_po2()->po2_emx_wasnt_initialized)
|
---|
181 | #define fname (Perl_po2()->po2_fname)
|
---|
182 | #define rmq_cnt (Perl_po2()->po2_rmq_cnt)
|
---|
183 | #define grent_cnt (Perl_po2()->po2_grent_cnt)
|
---|
184 | #define newp (Perl_po2()->po2_newp)
|
---|
185 | #define oldp (Perl_po2()->po2_oldp)
|
---|
186 | #define newl (Perl_po2()->po2_newl)
|
---|
187 | #define oldl (Perl_po2()->po2_oldl)
|
---|
188 | #define notfound (Perl_po2()->po2_notfound)
|
---|
189 | #define mangle_ret (Perl_po2()->po2_mangle_ret)
|
---|
190 | #define os2_dll_fake (Perl_po2()->po2_os2_dll_fake)
|
---|
191 | #define os2_mytype (Perl_po2()->po2_os2_mytype)
|
---|
192 | #define os2_mytype_ini (Perl_po2()->po2_os2_mytype_ini)
|
---|
193 | #define pidtid_lookup (Perl_po2()->po2_pidtid_lookup)
|
---|
194 | #define pw (Perl_po2()->po2_pw)
|
---|
195 | #define pwent_cnt (Perl_po2()->po2_pwent_cnt)
|
---|
196 | #define _my_pwent (Perl_po2()->po2__my_pwent)
|
---|
197 | #define pthreads_state_buf (Perl_po2()->po2_pthreads_state_buf)
|
---|
198 | #define os2error_buf (Perl_po2()->po2_os2error_buf)
|
---|
199 | /* There is no big sense to make it thread-specific, since signals
|
---|
200 | are delivered to thread 1 only. XXXX Maybe make it into an array? */
|
---|
201 | #define spawn_pid (Perl_po2()->po2_spawn_pid)
|
---|
202 | #define spawn_killed (Perl_po2()->po2_spawn_killed)
|
---|
203 | #define DOS_harderr_state (Perl_po2()->po2_DOS_harderr_state)
|
---|
204 | #define DOS_suppression_state (Perl_po2()->po2_DOS_suppression_state)
|
---|
205 |
|
---|
206 | #define at_exit_buf (Perl_po2()->po2_at_exit_buf)
|
---|
207 | #define longjmp_at_exit (Perl_po2()->po2_longjmp_at_exit)
|
---|
208 | #define emx_runtime_init (Perl_po2()->po2_emx_runtime_init)
|
---|
209 | #define emx_exception_init (Perl_po2()->po2_emx_exception_init)
|
---|
210 | #define emx_runtime_secondary (Perl_po2()->po2_emx_runtime_secondary)
|
---|
211 | #define perllib_mangle_installed (Perl_po2()->po2_perllib_mangle_installed)
|
---|
212 | #define perl_sh_installed (Perl_po2()->po2_perl_sh_installed)
|
---|
213 | #define gTable (Perl_po2()->po2_gTable)
|
---|
214 | #define lTable (Perl_po2()->po2_lTable)
|
---|
215 |
|
---|
216 | const Perl_PFN * const pExtFCN = (Perl_po2()->po2_ExtFCN);
|
---|
217 |
|
---|
218 | #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
|
---|
219 |
|
---|
220 | typedef void (*emx_startroutine)(void *);
|
---|
221 | typedef void* (*pthreads_startroutine)(void *);
|
---|
222 |
|
---|
223 | enum pthreads_state {
|
---|
224 | pthreads_st_none = 0,
|
---|
225 | pthreads_st_run,
|
---|
226 | pthreads_st_exited,
|
---|
227 | pthreads_st_detached,
|
---|
228 | pthreads_st_waited,
|
---|
229 | pthreads_st_norun,
|
---|
230 | pthreads_st_exited_waited,
|
---|
231 | };
|
---|
232 | const char * const pthreads_states[] = {
|
---|
233 | "uninit",
|
---|
234 | "running",
|
---|
235 | "exited",
|
---|
236 | "detached",
|
---|
237 | "waited for",
|
---|
238 | "could not start",
|
---|
239 | "exited, then waited on",
|
---|
240 | };
|
---|
241 |
|
---|
242 | enum pthread_exists { pthread_not_existant = -0xff };
|
---|
243 |
|
---|
244 | static const char*
|
---|
245 | pthreads_state_string(enum pthreads_state state)
|
---|
246 | {
|
---|
247 | if (state < 0 || state >= sizeof(pthreads_states)/sizeof(*pthreads_states)) {
|
---|
248 | snprintf(pthreads_state_buf, sizeof(pthreads_state_buf),
|
---|
249 | "unknown thread state %d", (int)state);
|
---|
250 | return pthreads_state_buf;
|
---|
251 | }
|
---|
252 | return pthreads_states[state];
|
---|
253 | }
|
---|
254 |
|
---|
255 | typedef struct {
|
---|
256 | void *status;
|
---|
257 | perl_cond cond;
|
---|
258 | enum pthreads_state state;
|
---|
259 | } thread_join_t;
|
---|
260 |
|
---|
261 | thread_join_t *thread_join_data;
|
---|
262 | int thread_join_count;
|
---|
263 | perl_mutex start_thread_mutex;
|
---|
264 | static perl_mutex perlos2_state_mutex;
|
---|
265 |
|
---|
266 |
|
---|
267 | int
|
---|
268 | pthread_join(perl_os_thread tid, void **status)
|
---|
269 | {
|
---|
270 | MUTEX_LOCK(&start_thread_mutex);
|
---|
271 | if (tid < 1 || tid >= thread_join_count) {
|
---|
272 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
273 | if (tid != pthread_not_existant)
|
---|
274 | Perl_croak_nocontext("panic: join with a thread with strange ordinal %d", (int)tid);
|
---|
275 | Perl_warn_nocontext("panic: join with a thread which could not start");
|
---|
276 | *status = 0;
|
---|
277 | return 0;
|
---|
278 | }
|
---|
279 | switch (thread_join_data[tid].state) {
|
---|
280 | case pthreads_st_exited:
|
---|
281 | thread_join_data[tid].state = pthreads_st_exited_waited;
|
---|
282 | *status = thread_join_data[tid].status;
|
---|
283 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
284 | COND_SIGNAL(&thread_join_data[tid].cond);
|
---|
285 | break;
|
---|
286 | case pthreads_st_waited:
|
---|
287 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
288 | Perl_croak_nocontext("join with a thread with a waiter");
|
---|
289 | break;
|
---|
290 | case pthreads_st_norun:
|
---|
291 | {
|
---|
292 | int state = (int)thread_join_data[tid].status;
|
---|
293 |
|
---|
294 | thread_join_data[tid].state = pthreads_st_none;
|
---|
295 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
296 | Perl_croak_nocontext("panic: join with a thread which could not run"
|
---|
297 | " due to attempt of tid reuse (state='%s')",
|
---|
298 | pthreads_state_string(state));
|
---|
299 | break;
|
---|
300 | }
|
---|
301 | case pthreads_st_run:
|
---|
302 | {
|
---|
303 | perl_cond cond;
|
---|
304 |
|
---|
305 | thread_join_data[tid].state = pthreads_st_waited;
|
---|
306 | thread_join_data[tid].status = (void *)status;
|
---|
307 | COND_INIT(&thread_join_data[tid].cond);
|
---|
308 | cond = thread_join_data[tid].cond;
|
---|
309 | COND_WAIT(&thread_join_data[tid].cond, &start_thread_mutex);
|
---|
310 | COND_DESTROY(&cond);
|
---|
311 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
312 | break;
|
---|
313 | }
|
---|
314 | default:
|
---|
315 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
316 | Perl_croak_nocontext("panic: join with thread in unknown thread state: '%s'",
|
---|
317 | pthreads_state_string(thread_join_data[tid].state));
|
---|
318 | break;
|
---|
319 | }
|
---|
320 | return 0;
|
---|
321 | }
|
---|
322 |
|
---|
323 | typedef struct {
|
---|
324 | pthreads_startroutine sub;
|
---|
325 | void *arg;
|
---|
326 | void *ctx;
|
---|
327 | } pthr_startit;
|
---|
328 |
|
---|
329 | /* The lock is used:
|
---|
330 | a) Since we temporarily usurp the caller interp, so malloc() may
|
---|
331 | use it to decide on debugging the call;
|
---|
332 | b) Since *args is on the caller's stack.
|
---|
333 | */
|
---|
334 | void
|
---|
335 | pthread_startit(void *arg1)
|
---|
336 | {
|
---|
337 | /* Thread is already started, we need to transfer control only */
|
---|
338 | pthr_startit args = *(pthr_startit *)arg1;
|
---|
339 | int tid = pthread_self();
|
---|
340 | void *rc;
|
---|
341 | int state;
|
---|
342 |
|
---|
343 | if (tid <= 1) {
|
---|
344 | /* Can't croak, the setjmp() is not in scope... */
|
---|
345 | char buf[80];
|
---|
346 |
|
---|
347 | snprintf(buf, sizeof(buf),
|
---|
348 | "panic: thread with strange ordinal %d created\n\r", tid);
|
---|
349 | write(2,buf,strlen(buf));
|
---|
350 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
351 | return;
|
---|
352 | }
|
---|
353 | /* Until args.sub resets it, makes debugging Perl_malloc() work: */
|
---|
354 | PERL_SET_CONTEXT(0);
|
---|
355 | if (tid >= thread_join_count) {
|
---|
356 | int oc = thread_join_count;
|
---|
357 |
|
---|
358 | thread_join_count = tid + 5 + tid/5;
|
---|
359 | if (thread_join_data) {
|
---|
360 | Renew(thread_join_data, thread_join_count, thread_join_t);
|
---|
361 | Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
|
---|
362 | } else {
|
---|
363 | Newxz(thread_join_data, thread_join_count, thread_join_t);
|
---|
364 | }
|
---|
365 | }
|
---|
366 | if (thread_join_data[tid].state != pthreads_st_none) {
|
---|
367 | /* Can't croak, the setjmp() is not in scope... */
|
---|
368 | char buf[80];
|
---|
369 |
|
---|
370 | snprintf(buf, sizeof(buf),
|
---|
371 | "panic: attempt to reuse thread id %d (state='%s')\n\r",
|
---|
372 | tid, pthreads_state_string(thread_join_data[tid].state));
|
---|
373 | write(2,buf,strlen(buf));
|
---|
374 | thread_join_data[tid].status = (void*)thread_join_data[tid].state;
|
---|
375 | thread_join_data[tid].state = pthreads_st_norun;
|
---|
376 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
377 | return;
|
---|
378 | }
|
---|
379 | thread_join_data[tid].state = pthreads_st_run;
|
---|
380 | /* Now that we copied/updated the guys, we may release the caller... */
|
---|
381 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
382 | rc = (*args.sub)(args.arg);
|
---|
383 | MUTEX_LOCK(&start_thread_mutex);
|
---|
384 | switch (thread_join_data[tid].state) {
|
---|
385 | case pthreads_st_waited:
|
---|
386 | COND_SIGNAL(&thread_join_data[tid].cond);
|
---|
387 | thread_join_data[tid].state = pthreads_st_none;
|
---|
388 | *((void**)thread_join_data[tid].status) = rc;
|
---|
389 | break;
|
---|
390 | case pthreads_st_detached:
|
---|
391 | thread_join_data[tid].state = pthreads_st_none;
|
---|
392 | break;
|
---|
393 | case pthreads_st_run:
|
---|
394 | /* Somebody can wait on us; cannot exit, since OS can reuse the tid
|
---|
395 | and our waiter will get somebody else's status. */
|
---|
396 | thread_join_data[tid].state = pthreads_st_exited;
|
---|
397 | thread_join_data[tid].status = rc;
|
---|
398 | COND_INIT(&thread_join_data[tid].cond);
|
---|
399 | COND_WAIT(&thread_join_data[tid].cond, &start_thread_mutex);
|
---|
400 | COND_DESTROY(&thread_join_data[tid].cond);
|
---|
401 | thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
|
---|
402 | break;
|
---|
403 | default:
|
---|
404 | state = thread_join_data[tid].state;
|
---|
405 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
406 | Perl_croak_nocontext("panic: unexpected thread state on exit: '%s'",
|
---|
407 | pthreads_state_string(state));
|
---|
408 | }
|
---|
409 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
410 | }
|
---|
411 |
|
---|
412 | int
|
---|
413 | pthread_create(perl_os_thread *tidp, const pthread_attr_t *attr,
|
---|
414 | void *(*start_routine)(void*), void *arg)
|
---|
415 | {
|
---|
416 | dTHX;
|
---|
417 | pthr_startit args;
|
---|
418 |
|
---|
419 | args.sub = (void*)start_routine;
|
---|
420 | args.arg = arg;
|
---|
421 | args.ctx = PERL_GET_CONTEXT;
|
---|
422 |
|
---|
423 | MUTEX_LOCK(&start_thread_mutex);
|
---|
424 | /* Test suite creates 31 extra threads;
|
---|
425 | on machine without shared-memory-hogs this stack sizeis OK with 31: */
|
---|
426 | *tidp = _beginthread(pthread_startit, /*stack*/ NULL,
|
---|
427 | /*stacksize*/ 4*1024*1024, (void*)&args);
|
---|
428 | if (*tidp == -1) {
|
---|
429 | *tidp = pthread_not_existant;
|
---|
430 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
431 | return EINVAL;
|
---|
432 | }
|
---|
433 | MUTEX_LOCK(&start_thread_mutex); /* Wait for init to proceed */
|
---|
434 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
435 | return 0;
|
---|
436 | }
|
---|
437 |
|
---|
438 | int
|
---|
439 | pthread_detach(perl_os_thread tid)
|
---|
440 | {
|
---|
441 | MUTEX_LOCK(&start_thread_mutex);
|
---|
442 | if (tid < 1 || tid >= thread_join_count) {
|
---|
443 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
444 | if (tid != pthread_not_existant)
|
---|
445 | Perl_croak_nocontext("panic: detach of a thread with strange ordinal %d", (int)tid);
|
---|
446 | Perl_warn_nocontext("detach of a thread which could not start");
|
---|
447 | return 0;
|
---|
448 | }
|
---|
449 | switch (thread_join_data[tid].state) {
|
---|
450 | case pthreads_st_waited:
|
---|
451 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
452 | Perl_croak_nocontext("detach on a thread with a waiter");
|
---|
453 | break;
|
---|
454 | case pthreads_st_run:
|
---|
455 | thread_join_data[tid].state = pthreads_st_detached;
|
---|
456 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
457 | break;
|
---|
458 | case pthreads_st_exited:
|
---|
459 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
460 | COND_SIGNAL(&thread_join_data[tid].cond);
|
---|
461 | break;
|
---|
462 | case pthreads_st_detached:
|
---|
463 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
464 | Perl_warn_nocontext("detach on an already detached thread");
|
---|
465 | break;
|
---|
466 | case pthreads_st_norun:
|
---|
467 | {
|
---|
468 | int state = (int)thread_join_data[tid].status;
|
---|
469 |
|
---|
470 | thread_join_data[tid].state = pthreads_st_none;
|
---|
471 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
472 | Perl_croak_nocontext("panic: detaching thread which could not run"
|
---|
473 | " due to attempt of tid reuse (state='%s')",
|
---|
474 | pthreads_state_string(state));
|
---|
475 | break;
|
---|
476 | }
|
---|
477 | default:
|
---|
478 | MUTEX_UNLOCK(&start_thread_mutex);
|
---|
479 | Perl_croak_nocontext("panic: detach of a thread with unknown thread state: '%s'",
|
---|
480 | pthreads_state_string(thread_join_data[tid].state));
|
---|
481 | break;
|
---|
482 | }
|
---|
483 | return 0;
|
---|
484 | }
|
---|
485 |
|
---|
486 | /* This is a very bastardized version; may be OK due to edge trigger of Wait */
|
---|
487 | int
|
---|
488 | os2_cond_wait(perl_cond *c, perl_mutex *m)
|
---|
489 | {
|
---|
490 | int rc;
|
---|
491 | STRLEN n_a;
|
---|
492 | if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
|
---|
493 | Perl_rc = rc, croak_with_os2error("panic: COND_WAIT-reset");
|
---|
494 | if (m) MUTEX_UNLOCK(m);
|
---|
495 | if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
|
---|
496 | && (rc != ERROR_INTERRUPT))
|
---|
497 | croak_with_os2error("panic: COND_WAIT");
|
---|
498 | if (rc == ERROR_INTERRUPT)
|
---|
499 | errno = EINTR;
|
---|
500 | if (m) MUTEX_LOCK(m);
|
---|
501 | return 0;
|
---|
502 | }
|
---|
503 | #endif
|
---|
504 |
|
---|
505 | static int exe_is_aout(void);
|
---|
506 |
|
---|
507 | /* This should match enum entries_ordinals defined in os2ish.h. */
|
---|
508 | static const struct {
|
---|
509 | struct dll_handle_t *dll;
|
---|
510 | const char *entryname;
|
---|
511 | int entrypoint;
|
---|
512 | } loadOrdinals[] = {
|
---|
513 | {&doscalls_handle, NULL, 874}, /* DosQueryExtLibpath */
|
---|
514 | {&doscalls_handle, NULL, 873}, /* DosSetExtLibpath */
|
---|
515 | {&doscalls_handle, NULL, 460}, /* DosVerifyPidTid */
|
---|
516 | {&tcp_handle, "SETHOSTENT", 0},
|
---|
517 | {&tcp_handle, "SETNETENT" , 0},
|
---|
518 | {&tcp_handle, "SETPROTOENT", 0},
|
---|
519 | {&tcp_handle, "SETSERVENT", 0},
|
---|
520 | {&tcp_handle, "GETHOSTENT", 0},
|
---|
521 | {&tcp_handle, "GETNETENT" , 0},
|
---|
522 | {&tcp_handle, "GETPROTOENT", 0},
|
---|
523 | {&tcp_handle, "GETSERVENT", 0},
|
---|
524 | {&tcp_handle, "ENDHOSTENT", 0},
|
---|
525 | {&tcp_handle, "ENDNETENT", 0},
|
---|
526 | {&tcp_handle, "ENDPROTOENT", 0},
|
---|
527 | {&tcp_handle, "ENDSERVENT", 0},
|
---|
528 | {&pmwin_handle, NULL, 763}, /* WinInitialize */
|
---|
529 | {&pmwin_handle, NULL, 716}, /* WinCreateMsgQueue */
|
---|
530 | {&pmwin_handle, NULL, 726}, /* WinDestroyMsgQueue */
|
---|
531 | {&pmwin_handle, NULL, 918}, /* WinPeekMsg */
|
---|
532 | {&pmwin_handle, NULL, 915}, /* WinGetMsg */
|
---|
533 | {&pmwin_handle, NULL, 912}, /* WinDispatchMsg */
|
---|
534 | {&pmwin_handle, NULL, 753}, /* WinGetLastError */
|
---|
535 | {&pmwin_handle, NULL, 705}, /* WinCancelShutdown */
|
---|
536 | /* These are needed in extensions.
|
---|
537 | How to protect PMSHAPI: it comes through EMX functions? */
|
---|
538 | {&rexx_handle, "RexxStart", 0},
|
---|
539 | {&rexx_handle, "RexxVariablePool", 0},
|
---|
540 | {&rexxapi_handle, "RexxRegisterFunctionExe", 0},
|
---|
541 | {&rexxapi_handle, "RexxDeregisterFunction", 0},
|
---|
542 | {&sesmgr_handle, "DOSSMSETTITLE", 0}, /* Would not work runtime-loaded */
|
---|
543 | {&pmshapi_handle, "PRF32QUERYPROFILESIZE", 0},
|
---|
544 | {&pmshapi_handle, "PRF32OPENPROFILE", 0},
|
---|
545 | {&pmshapi_handle, "PRF32CLOSEPROFILE", 0},
|
---|
546 | {&pmshapi_handle, "PRF32QUERYPROFILE", 0},
|
---|
547 | {&pmshapi_handle, "PRF32RESET", 0},
|
---|
548 | {&pmshapi_handle, "PRF32QUERYPROFILEDATA", 0},
|
---|
549 | {&pmshapi_handle, "PRF32WRITEPROFILEDATA", 0},
|
---|
550 |
|
---|
551 | /* At least some of these do not work by name, since they need
|
---|
552 | WIN32 instead of WIN... */
|
---|
553 | #if 0
|
---|
554 | These were generated with
|
---|
555 | nm I:\emx\lib\os2.a | fgrep -f API-list | grep = > API-list-entries
|
---|
556 | perl -wnle "next unless /^0+\s+E\s+_(\w+)=(\w+).(\d+)/; print qq( ORD_$1,)" API-list-entries > API-list-ORD_
|
---|
557 | perl -wnle "next unless /^0+\s+E\s+_(\w+)=(\w+).(\d+)/; print qq( {${2}_handle, NULL, $3},\t\t/* $1 */)" WinSwitch-API-list-entries >API-list-entry
|
---|
558 | #endif
|
---|
559 | {&pmshapi_handle, NULL, 123}, /* WinChangeSwitchEntry */
|
---|
560 | {&pmshapi_handle, NULL, 124}, /* WinQuerySwitchEntry */
|
---|
561 | {&pmshapi_handle, NULL, 125}, /* WinQuerySwitchHandle */
|
---|
562 | {&pmshapi_handle, NULL, 126}, /* WinQuerySwitchList */
|
---|
563 | {&pmshapi_handle, NULL, 131}, /* WinSwitchToProgram */
|
---|
564 | {&pmwin_handle, NULL, 702}, /* WinBeginEnumWindows */
|
---|
565 | {&pmwin_handle, NULL, 737}, /* WinEndEnumWindows */
|
---|
566 | {&pmwin_handle, NULL, 740}, /* WinEnumDlgItem */
|
---|
567 | {&pmwin_handle, NULL, 756}, /* WinGetNextWindow */
|
---|
568 | {&pmwin_handle, NULL, 768}, /* WinIsChild */
|
---|
569 | {&pmwin_handle, NULL, 799}, /* WinQueryActiveWindow */
|
---|
570 | {&pmwin_handle, NULL, 805}, /* WinQueryClassName */
|
---|
571 | {&pmwin_handle, NULL, 817}, /* WinQueryFocus */
|
---|
572 | {&pmwin_handle, NULL, 834}, /* WinQueryWindow */
|
---|
573 | {&pmwin_handle, NULL, 837}, /* WinQueryWindowPos */
|
---|
574 | {&pmwin_handle, NULL, 838}, /* WinQueryWindowProcess */
|
---|
575 | {&pmwin_handle, NULL, 841}, /* WinQueryWindowText */
|
---|
576 | {&pmwin_handle, NULL, 842}, /* WinQueryWindowTextLength */
|
---|
577 | {&pmwin_handle, NULL, 860}, /* WinSetFocus */
|
---|
578 | {&pmwin_handle, NULL, 875}, /* WinSetWindowPos */
|
---|
579 | {&pmwin_handle, NULL, 877}, /* WinSetWindowText */
|
---|
580 | {&pmwin_handle, NULL, 883}, /* WinShowWindow */
|
---|
581 | {&pmwin_handle, NULL, 772}, /* WinIsWindow */
|
---|
582 | {&pmwin_handle, NULL, 899}, /* WinWindowFromId */
|
---|
583 | {&pmwin_handle, NULL, 900}, /* WinWindowFromPoint */
|
---|
584 | {&pmwin_handle, NULL, 919}, /* WinPostMsg */
|
---|
585 | {&pmwin_handle, NULL, 735}, /* WinEnableWindow */
|
---|
586 | {&pmwin_handle, NULL, 736}, /* WinEnableWindowUpdate */
|
---|
587 | {&pmwin_handle, NULL, 773}, /* WinIsWindowEnabled */
|
---|
588 | {&pmwin_handle, NULL, 774}, /* WinIsWindowShowing */
|
---|
589 | {&pmwin_handle, NULL, 775}, /* WinIsWindowVisible */
|
---|
590 | {&pmwin_handle, NULL, 839}, /* WinQueryWindowPtr */
|
---|
591 | {&pmwin_handle, NULL, 843}, /* WinQueryWindowULong */
|
---|
592 | {&pmwin_handle, NULL, 844}, /* WinQueryWindowUShort */
|
---|
593 | {&pmwin_handle, NULL, 874}, /* WinSetWindowBits */
|
---|
594 | {&pmwin_handle, NULL, 876}, /* WinSetWindowPtr */
|
---|
595 | {&pmwin_handle, NULL, 878}, /* WinSetWindowULong */
|
---|
596 | {&pmwin_handle, NULL, 879}, /* WinSetWindowUShort */
|
---|
597 | {&pmwin_handle, NULL, 813}, /* WinQueryDesktopWindow */
|
---|
598 | {&pmwin_handle, NULL, 851}, /* WinSetActiveWindow */
|
---|
599 | {&doscalls_handle, NULL, 360}, /* DosQueryModFromEIP */
|
---|
600 | {&doscalls_handle, NULL, 582}, /* Dos32QueryHeaderInfo */
|
---|
601 | {&doscalls_handle, NULL, 362}, /* DosTmrQueryFreq */
|
---|
602 | {&doscalls_handle, NULL, 363}, /* DosTmrQueryTime */
|
---|
603 | {&pmwp_handle, NULL, 262}, /* WinQueryActiveDesktopPathname */
|
---|
604 | {&pmwin_handle, NULL, 765}, /* WinInvalidateRect */
|
---|
605 | {&pmwin_handle, NULL, 906}, /* WinCreateFrameControl */
|
---|
606 | {&pmwin_handle, NULL, 807}, /* WinQueryClipbrdFmtInfo */
|
---|
607 | {&pmwin_handle, NULL, 808}, /* WinQueryClipbrdOwner */
|
---|
608 | {&pmwin_handle, NULL, 809}, /* WinQueryClipbrdViewer */
|
---|
609 | {&pmwin_handle, NULL, 806}, /* WinQueryClipbrdData */
|
---|
610 | {&pmwin_handle, NULL, 793}, /* WinOpenClipbrd */
|
---|
611 | {&pmwin_handle, NULL, 707}, /* WinCloseClipbrd */
|
---|
612 | {&pmwin_handle, NULL, 854}, /* WinSetClipbrdData */
|
---|
613 | {&pmwin_handle, NULL, 855}, /* WinSetClipbrdOwner */
|
---|
614 | {&pmwin_handle, NULL, 856}, /* WinSetClipbrdViewer */
|
---|
615 | {&pmwin_handle, NULL, 739}, /* WinEnumClipbrdFmts */
|
---|
616 | {&pmwin_handle, NULL, 733}, /* WinEmptyClipbrd */
|
---|
617 | {&pmwin_handle, NULL, 700}, /* WinAddAtom */
|
---|
618 | {&pmwin_handle, NULL, 744}, /* WinFindAtom */
|
---|
619 | {&pmwin_handle, NULL, 721}, /* WinDeleteAtom */
|
---|
620 | {&pmwin_handle, NULL, 803}, /* WinQueryAtomUsage */
|
---|
621 | {&pmwin_handle, NULL, 802}, /* WinQueryAtomName */
|
---|
622 | {&pmwin_handle, NULL, 801}, /* WinQueryAtomLength */
|
---|
623 | {&pmwin_handle, NULL, 830}, /* WinQuerySystemAtomTable */
|
---|
624 | {&pmwin_handle, NULL, 714}, /* WinCreateAtomTable */
|
---|
625 | {&pmwin_handle, NULL, 724}, /* WinDestroyAtomTable */
|
---|
626 | {&pmwin_handle, NULL, 794}, /* WinOpenWindowDC */
|
---|
627 | {&pmgpi_handle, NULL, 610}, /* DevOpenDC */
|
---|
628 | {&pmgpi_handle, NULL, 606}, /* DevQueryCaps */
|
---|
629 | {&pmgpi_handle, NULL, 604}, /* DevCloseDC */
|
---|
630 | {&pmwin_handle, NULL, 789}, /* WinMessageBox */
|
---|
631 | {&pmwin_handle, NULL, 1015}, /* WinMessageBox2 */
|
---|
632 | {&pmwin_handle, NULL, 829}, /* WinQuerySysValue */
|
---|
633 | {&pmwin_handle, NULL, 873}, /* WinSetSysValue */
|
---|
634 | {&pmwin_handle, NULL, 701}, /* WinAlarm */
|
---|
635 | {&pmwin_handle, NULL, 745}, /* WinFlashWindow */
|
---|
636 | {&pmwin_handle, NULL, 780}, /* WinLoadPointer */
|
---|
637 | {&pmwin_handle, NULL, 828}, /* WinQuerySysPointer */
|
---|
638 | {&doscalls_handle, NULL, 417}, /* DosReplaceModule */
|
---|
639 | {&doscalls_handle, NULL, 976}, /* DosPerfSysCall */
|
---|
640 | {&rexxapi_handle, "RexxRegisterSubcomExe", 0},
|
---|
641 | };
|
---|
642 |
|
---|
643 | HMODULE
|
---|
644 | loadModule(const char *modname, int fail)
|
---|
645 | {
|
---|
646 | HMODULE h = (HMODULE)dlopen(modname, 0);
|
---|
647 |
|
---|
648 | if (!h && fail)
|
---|
649 | Perl_croak_nocontext("Error loading module '%s': %s",
|
---|
650 | modname, dlerror());
|
---|
651 | return h;
|
---|
652 | }
|
---|
653 |
|
---|
654 | /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
|
---|
655 |
|
---|
656 | static int
|
---|
657 | my_type()
|
---|
658 | {
|
---|
659 | int rc;
|
---|
660 | TIB *tib;
|
---|
661 | PIB *pib;
|
---|
662 |
|
---|
663 | if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
|
---|
664 | if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
|
---|
665 | return -1;
|
---|
666 |
|
---|
667 | return (pib->pib_ultype);
|
---|
668 | }
|
---|
669 |
|
---|
670 | static void
|
---|
671 | my_type_set(int type)
|
---|
672 | {
|
---|
673 | int rc;
|
---|
674 | TIB *tib;
|
---|
675 | PIB *pib;
|
---|
676 |
|
---|
677 | if (!(_emx_env & 0x200))
|
---|
678 | Perl_croak_nocontext("Can't set type on DOS"); /* not OS/2. */
|
---|
679 | if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
|
---|
680 | croak_with_os2error("Error getting info blocks");
|
---|
681 | pib->pib_ultype = type;
|
---|
682 | }
|
---|
683 |
|
---|
684 | PFN
|
---|
685 | loadByOrdinal(enum entries_ordinals ord, int fail)
|
---|
686 | {
|
---|
687 | if (sizeof(loadOrdinals)/sizeof(loadOrdinals[0]) != ORD_NENTRIES)
|
---|
688 | Perl_croak_nocontext(
|
---|
689 | "Wrong size of loadOrdinals array: expected %d, actual %d",
|
---|
690 | sizeof(loadOrdinals)/sizeof(loadOrdinals[0]), ORD_NENTRIES);
|
---|
691 | if (ExtFCN[ord] == NULL) {
|
---|
692 | PFN fcn = (PFN)-1;
|
---|
693 | APIRET rc;
|
---|
694 |
|
---|
695 | if (!loadOrdinals[ord].dll->handle) {
|
---|
696 | if (loadOrdinals[ord].dll->requires_pm && my_type() < 2) { /* FS */
|
---|
697 | char *s = getenv("PERL_ASIF_PM");
|
---|
698 |
|
---|
699 | if (!s || !atoi(s)) {
|
---|
700 | /* The module will not function well without PM.
|
---|
701 | The usual way to detect PM is the existence of the mutex
|
---|
702 | \SEM32\PMDRAG.SEM. */
|
---|
703 | HMTX hMtx = 0;
|
---|
704 |
|
---|
705 | if (CheckOSError(DosOpenMutexSem("\\SEM32\\PMDRAG.SEM",
|
---|
706 | &hMtx)))
|
---|
707 | Perl_croak_nocontext("Looks like we have no PM; will not load DLL %s without $ENV{PERL_ASIF_PM}",
|
---|
708 | loadOrdinals[ord].dll->modname);
|
---|
709 | DosCloseMutexSem(hMtx);
|
---|
710 | }
|
---|
711 | }
|
---|
712 | MUTEX_LOCK(&perlos2_state_mutex);
|
---|
713 | loadOrdinals[ord].dll->handle
|
---|
714 | = loadModule(loadOrdinals[ord].dll->modname, fail);
|
---|
715 | MUTEX_UNLOCK(&perlos2_state_mutex);
|
---|
716 | }
|
---|
717 | if (!loadOrdinals[ord].dll->handle)
|
---|
718 | return 0; /* Possible with FAIL==0 only */
|
---|
719 | if (CheckOSError(DosQueryProcAddr(loadOrdinals[ord].dll->handle,
|
---|
720 | loadOrdinals[ord].entrypoint,
|
---|
721 | loadOrdinals[ord].entryname,&fcn))) {
|
---|
722 | char buf[20], *s = (char*)loadOrdinals[ord].entryname;
|
---|
723 |
|
---|
724 | if (!fail)
|
---|
725 | return 0;
|
---|
726 | if (!s)
|
---|
727 | sprintf(s = buf, "%d", loadOrdinals[ord].entrypoint);
|
---|
728 | Perl_croak_nocontext(
|
---|
729 | "This version of OS/2 does not support %s.%s",
|
---|
730 | loadOrdinals[ord].dll->modname, s);
|
---|
731 | }
|
---|
732 | ExtFCN[ord] = fcn;
|
---|
733 | }
|
---|
734 | if ((long)ExtFCN[ord] == -1)
|
---|
735 | Perl_croak_nocontext("panic queryaddr");
|
---|
736 | return ExtFCN[ord];
|
---|
737 | }
|
---|
738 |
|
---|
739 | void
|
---|
740 | init_PMWIN_entries(void)
|
---|
741 | {
|
---|
742 | int i;
|
---|
743 |
|
---|
744 | for (i = ORD_WinInitialize; i <= ORD_WinCancelShutdown; i++)
|
---|
745 | ((PFN*)&PMWIN_entries)[i - ORD_WinInitialize] = loadByOrdinal(i, 1);
|
---|
746 | }
|
---|
747 |
|
---|
748 | /*****************************************************/
|
---|
749 | /* socket forwarders without linking with tcpip DLLs */
|
---|
750 |
|
---|
751 | DeclFuncByORD(struct hostent *, gethostent, ORD_GETHOSTENT, (void), ())
|
---|
752 | DeclFuncByORD(struct netent *, getnetent, ORD_GETNETENT, (void), ())
|
---|
753 | DeclFuncByORD(struct protoent *, getprotoent, ORD_GETPROTOENT, (void), ())
|
---|
754 | DeclFuncByORD(struct servent *, getservent, ORD_GETSERVENT, (void), ())
|
---|
755 |
|
---|
756 | DeclVoidFuncByORD(sethostent, ORD_SETHOSTENT, (int x), (x))
|
---|
757 | DeclVoidFuncByORD(setnetent, ORD_SETNETENT, (int x), (x))
|
---|
758 | DeclVoidFuncByORD(setprotoent, ORD_SETPROTOENT, (int x), (x))
|
---|
759 | DeclVoidFuncByORD(setservent, ORD_SETSERVENT, (int x), (x))
|
---|
760 |
|
---|
761 | DeclVoidFuncByORD(endhostent, ORD_ENDHOSTENT, (void), ())
|
---|
762 | DeclVoidFuncByORD(endnetent, ORD_ENDNETENT, (void), ())
|
---|
763 | DeclVoidFuncByORD(endprotoent, ORD_ENDPROTOENT, (void), ())
|
---|
764 | DeclVoidFuncByORD(endservent, ORD_ENDSERVENT, (void), ())
|
---|
765 |
|
---|
766 | /* priorities */
|
---|
767 | static const signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
|
---|
768 | self inverse. */
|
---|
769 | #define QSS_INI_BUFFER 1024
|
---|
770 |
|
---|
771 | ULONG (*pDosVerifyPidTid) (PID pid, TID tid);
|
---|
772 |
|
---|
773 | PQTOPLEVEL
|
---|
774 | get_sysinfo(ULONG pid, ULONG flags)
|
---|
775 | {
|
---|
776 | char *pbuffer;
|
---|
777 | ULONG rc, buf_len = QSS_INI_BUFFER;
|
---|
778 | PQTOPLEVEL psi;
|
---|
779 |
|
---|
780 | if (pid) {
|
---|
781 | if (!pidtid_lookup) {
|
---|
782 | pidtid_lookup = 1;
|
---|
783 | *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0);
|
---|
784 | }
|
---|
785 | if (pDosVerifyPidTid) { /* Warp3 or later */
|
---|
786 | /* Up to some fixpak QuerySysState() kills the system if a non-existent
|
---|
787 | pid is used. */
|
---|
788 | if (CheckOSError(pDosVerifyPidTid(pid, 1)))
|
---|
789 | return 0;
|
---|
790 | }
|
---|
791 | }
|
---|
792 | Newx(pbuffer, buf_len, char);
|
---|
793 | /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
|
---|
794 | rc = QuerySysState(flags, pid, pbuffer, buf_len);
|
---|
795 | while (rc == ERROR_BUFFER_OVERFLOW) {
|
---|
796 | Renew(pbuffer, buf_len *= 2, char);
|
---|
797 | rc = QuerySysState(flags, pid, pbuffer, buf_len);
|
---|
798 | }
|
---|
799 | if (rc) {
|
---|
800 | FillOSError(rc);
|
---|
801 | Safefree(pbuffer);
|
---|
802 | return 0;
|
---|
803 | }
|
---|
804 | psi = (PQTOPLEVEL)pbuffer;
|
---|
805 | if (psi && pid && psi->procdata && pid != psi->procdata->pid) {
|
---|
806 | Safefree(psi);
|
---|
807 | Perl_croak_nocontext("panic: wrong pid in sysinfo");
|
---|
808 | }
|
---|
809 | return psi;
|
---|
810 | }
|
---|
811 |
|
---|
812 | #define PRIO_ERR 0x1111
|
---|
813 |
|
---|
814 | static ULONG
|
---|
815 | sys_prio(pid)
|
---|
816 | {
|
---|
817 | ULONG prio;
|
---|
818 | PQTOPLEVEL psi;
|
---|
819 |
|
---|
820 | if (!pid)
|
---|
821 | return PRIO_ERR;
|
---|
822 | psi = get_sysinfo(pid, QSS_PROCESS);
|
---|
823 | if (!psi)
|
---|
824 | return PRIO_ERR;
|
---|
825 | prio = psi->procdata->threads->priority;
|
---|
826 | Safefree(psi);
|
---|
827 | return prio;
|
---|
828 | }
|
---|
829 |
|
---|
830 | int
|
---|
831 | setpriority(int which, int pid, int val)
|
---|
832 | {
|
---|
833 | ULONG rc, prio = sys_prio(pid);
|
---|
834 |
|
---|
835 | if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
|
---|
836 | if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
|
---|
837 | /* Do not change class. */
|
---|
838 | return CheckOSError(DosSetPriority((pid < 0)
|
---|
839 | ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
|
---|
840 | 0,
|
---|
841 | (32 - val) % 32 - (prio & 0xFF),
|
---|
842 | abs(pid)))
|
---|
843 | ? -1 : 0;
|
---|
844 | } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
|
---|
845 | /* Documentation claims one can change both class and basevalue,
|
---|
846 | * but I find it wrong. */
|
---|
847 | /* Change class, but since delta == 0 denotes absolute 0, correct. */
|
---|
848 | if (CheckOSError(DosSetPriority((pid < 0)
|
---|
849 | ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
|
---|
850 | priors[(32 - val) >> 5] + 1,
|
---|
851 | 0,
|
---|
852 | abs(pid))))
|
---|
853 | return -1;
|
---|
854 | if ( ((32 - val) % 32) == 0 ) return 0;
|
---|
855 | return CheckOSError(DosSetPriority((pid < 0)
|
---|
856 | ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
|
---|
857 | 0,
|
---|
858 | (32 - val) % 32,
|
---|
859 | abs(pid)))
|
---|
860 | ? -1 : 0;
|
---|
861 | }
|
---|
862 | }
|
---|
863 |
|
---|
864 | int
|
---|
865 | getpriority(int which /* ignored */, int pid)
|
---|
866 | {
|
---|
867 | ULONG ret;
|
---|
868 |
|
---|
869 | if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
|
---|
870 | ret = sys_prio(pid);
|
---|
871 | if (ret == PRIO_ERR) {
|
---|
872 | return -1;
|
---|
873 | }
|
---|
874 | return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
|
---|
875 | }
|
---|
876 |
|
---|
877 | /*****************************************************************************/
|
---|
878 | /* spawn */
|
---|
879 |
|
---|
880 |
|
---|
881 |
|
---|
882 | static Signal_t
|
---|
883 | spawn_sighandler(int sig)
|
---|
884 | {
|
---|
885 | /* Some programs do not arrange for the keyboard signals to be
|
---|
886 | delivered to them. We need to deliver the signal manually. */
|
---|
887 | /* We may get a signal only if
|
---|
888 | a) kid does not receive keyboard signal: deliver it;
|
---|
889 | b) kid already died, and we get a signal. We may only hope
|
---|
890 | that the pid number was not reused.
|
---|
891 | */
|
---|
892 |
|
---|
893 | if (spawn_killed)
|
---|
894 | sig = SIGKILL; /* Try harder. */
|
---|
895 | kill(spawn_pid, sig);
|
---|
896 | spawn_killed = 1;
|
---|
897 | }
|
---|
898 |
|
---|
899 | static int
|
---|
900 | result(pTHX_ int flag, int pid)
|
---|
901 | {
|
---|
902 | int r, status;
|
---|
903 | Signal_t (*ihand)(); /* place to save signal during system() */
|
---|
904 | Signal_t (*qhand)(); /* place to save signal during system() */
|
---|
905 | #ifndef __EMX__
|
---|
906 | RESULTCODES res;
|
---|
907 | int rpid;
|
---|
908 | #endif
|
---|
909 |
|
---|
910 | if (pid < 0 || flag != 0)
|
---|
911 | return pid;
|
---|
912 |
|
---|
913 | #ifdef __EMX__
|
---|
914 | spawn_pid = pid;
|
---|
915 | spawn_killed = 0;
|
---|
916 | ihand = rsignal(SIGINT, &spawn_sighandler);
|
---|
917 | qhand = rsignal(SIGQUIT, &spawn_sighandler);
|
---|
918 | do {
|
---|
919 | r = wait4pid(pid, &status, 0);
|
---|
920 | } while (r == -1 && errno == EINTR);
|
---|
921 | rsignal(SIGINT, ihand);
|
---|
922 | rsignal(SIGQUIT, qhand);
|
---|
923 |
|
---|
924 | PL_statusvalue = (U16)status;
|
---|
925 | if (r < 0)
|
---|
926 | return -1;
|
---|
927 | return status & 0xFFFF;
|
---|
928 | #else
|
---|
929 | ihand = rsignal(SIGINT, SIG_IGN);
|
---|
930 | r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
|
---|
931 | rsignal(SIGINT, ihand);
|
---|
932 | PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
|
---|
933 | if (r)
|
---|
934 | return -1;
|
---|
935 | return PL_statusvalue;
|
---|
936 | #endif
|
---|
937 | }
|
---|
938 |
|
---|
939 | enum execf_t {
|
---|
940 | EXECF_SPAWN,
|
---|
941 | EXECF_EXEC,
|
---|
942 | EXECF_TRUEEXEC,
|
---|
943 | EXECF_SPAWN_NOWAIT,
|
---|
944 | EXECF_SPAWN_BYFLAG,
|
---|
945 | EXECF_SYNC
|
---|
946 | };
|
---|
947 |
|
---|
948 | static ULONG
|
---|
949 | file_type(char *path)
|
---|
950 | {
|
---|
951 | int rc;
|
---|
952 | ULONG apptype;
|
---|
953 |
|
---|
954 | if (!(_emx_env & 0x200))
|
---|
955 | Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
|
---|
956 | if (CheckOSError(DosQueryAppType(path, &apptype))) {
|
---|
957 | switch (rc) {
|
---|
958 | case ERROR_FILE_NOT_FOUND:
|
---|
959 | case ERROR_PATH_NOT_FOUND:
|
---|
960 | return -1;
|
---|
961 | case ERROR_ACCESS_DENIED: /* Directory with this name found? */
|
---|
962 | return -3;
|
---|
963 | default: /* Found, but not an
|
---|
964 | executable, or some other
|
---|
965 | read error. */
|
---|
966 | return -2;
|
---|
967 | }
|
---|
968 | }
|
---|
969 | return apptype;
|
---|
970 | }
|
---|
971 |
|
---|
972 | /* Spawn/exec a program, revert to shell if needed. */
|
---|
973 | /* global PL_Argv[] contains arguments. */
|
---|
974 |
|
---|
975 | extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *,
|
---|
976 | EXCEPTIONREGISTRATIONRECORD *,
|
---|
977 | CONTEXTRECORD *,
|
---|
978 | void *);
|
---|
979 |
|
---|
980 | int
|
---|
981 | do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
|
---|
982 | {
|
---|
983 | int trueflag = flag;
|
---|
984 | int rc, pass = 1;
|
---|
985 | char *real_name = NULL; /* Shut down the warning */
|
---|
986 | char const * args[4];
|
---|
987 | static const char * const fargs[4]
|
---|
988 | = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
|
---|
989 | const char * const *argsp = fargs;
|
---|
990 | int nargs = 4;
|
---|
991 | int force_shell;
|
---|
992 | int new_stderr = -1, nostderr = 0;
|
---|
993 | int fl_stderr = 0;
|
---|
994 | STRLEN n_a;
|
---|
995 | char *buf;
|
---|
996 | PerlIO *file;
|
---|
997 |
|
---|
998 | if (flag == P_WAIT)
|
---|
999 | flag = P_NOWAIT;
|
---|
1000 | if (really && !*(real_name = SvPV(really, n_a)))
|
---|
1001 | really = Nullsv;
|
---|
1002 |
|
---|
1003 | retry:
|
---|
1004 | if (strEQ(PL_Argv[0],"/bin/sh"))
|
---|
1005 | PL_Argv[0] = PL_sh_path;
|
---|
1006 |
|
---|
1007 | /* We should check PERL_SH* and PERLLIB_* as well? */
|
---|
1008 | if (!really || pass >= 2)
|
---|
1009 | real_name = PL_Argv[0];
|
---|
1010 | if (real_name[0] != '/' && real_name[0] != '\\'
|
---|
1011 | && !(real_name[0] && real_name[1] == ':'
|
---|
1012 | && (real_name[2] == '/' || real_name[2] != '\\'))
|
---|
1013 | ) /* will spawnvp use PATH? */
|
---|
1014 | TAINT_ENV(); /* testing IFS here is overkill, probably */
|
---|
1015 |
|
---|
1016 | reread:
|
---|
1017 | force_shell = 0;
|
---|
1018 | if (_emx_env & 0x200) { /* OS/2. */
|
---|
1019 | int type = file_type(real_name);
|
---|
1020 | type_again:
|
---|
1021 | if (type == -1) { /* Not found */
|
---|
1022 | errno = ENOENT;
|
---|
1023 | rc = -1;
|
---|
1024 | goto do_script;
|
---|
1025 | }
|
---|
1026 | else if (type == -2) { /* Not an EXE */
|
---|
1027 | errno = ENOEXEC;
|
---|
1028 | rc = -1;
|
---|
1029 | goto do_script;
|
---|
1030 | }
|
---|
1031 | else if (type == -3) { /* Is a directory? */
|
---|
1032 | /* Special-case this */
|
---|
1033 | char tbuf[512];
|
---|
1034 | int l = strlen(real_name);
|
---|
1035 |
|
---|
1036 | if (l + 5 <= sizeof tbuf) {
|
---|
1037 | strcpy(tbuf, real_name);
|
---|
1038 | strcpy(tbuf + l, ".exe");
|
---|
1039 | type = file_type(tbuf);
|
---|
1040 | if (type >= -3)
|
---|
1041 | goto type_again;
|
---|
1042 | }
|
---|
1043 |
|
---|
1044 | errno = ENOEXEC;
|
---|
1045 | rc = -1;
|
---|
1046 | goto do_script;
|
---|
1047 | }
|
---|
1048 | switch (type & 7) {
|
---|
1049 | /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
|
---|
1050 | case FAPPTYP_WINDOWAPI:
|
---|
1051 | { /* Apparently, kids are started basing on startup type, not the morphed type */
|
---|
1052 | if (os2_mytype != 3) { /* not PM */
|
---|
1053 | if (flag == P_NOWAIT)
|
---|
1054 | flag = P_PM;
|
---|
1055 | else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION && ckWARN(WARN_EXEC))
|
---|
1056 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting PM process with flag=%d, mytype=%d",
|
---|
1057 | flag, os2_mytype);
|
---|
1058 | }
|
---|
1059 | }
|
---|
1060 | break;
|
---|
1061 | case FAPPTYP_NOTWINDOWCOMPAT:
|
---|
1062 | {
|
---|
1063 | if (os2_mytype != 0) { /* not full screen */
|
---|
1064 | if (flag == P_NOWAIT)
|
---|
1065 | flag = P_SESSION;
|
---|
1066 | else if ((flag & 7) != P_SESSION && ckWARN(WARN_EXEC))
|
---|
1067 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting Full Screen process with flag=%d, mytype=%d",
|
---|
1068 | flag, os2_mytype);
|
---|
1069 | }
|
---|
1070 | }
|
---|
1071 | break;
|
---|
1072 | case FAPPTYP_NOTSPEC:
|
---|
1073 | /* Let the shell handle this... */
|
---|
1074 | force_shell = 1;
|
---|
1075 | buf = ""; /* Pacify a warning */
|
---|
1076 | file = 0; /* Pacify a warning */
|
---|
1077 | goto doshell_args;
|
---|
1078 | break;
|
---|
1079 | }
|
---|
1080 | }
|
---|
1081 |
|
---|
1082 | if (addflag) {
|
---|
1083 | addflag = 0;
|
---|
1084 | new_stderr = dup(2); /* Preserve stderr */
|
---|
1085 | if (new_stderr == -1) {
|
---|
1086 | if (errno == EBADF)
|
---|
1087 | nostderr = 1;
|
---|
1088 | else {
|
---|
1089 | rc = -1;
|
---|
1090 | goto finish;
|
---|
1091 | }
|
---|
1092 | } else
|
---|
1093 | fl_stderr = fcntl(2, F_GETFD);
|
---|
1094 | rc = dup2(1,2);
|
---|
1095 | if (rc == -1)
|
---|
1096 | goto finish;
|
---|
1097 | fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 | #if 0
|
---|
1101 | rc = result(aTHX_ trueflag, spawnvp(flag,real_name,PL_Argv));
|
---|
1102 | #else
|
---|
1103 | if (execf == EXECF_TRUEEXEC)
|
---|
1104 | rc = execvp(real_name,PL_Argv);
|
---|
1105 | else if (execf == EXECF_EXEC)
|
---|
1106 | rc = spawnvp(trueflag | P_OVERLAY,real_name,PL_Argv);
|
---|
1107 | else if (execf == EXECF_SPAWN_NOWAIT)
|
---|
1108 | rc = spawnvp(flag,real_name,PL_Argv);
|
---|
1109 | else if (execf == EXECF_SYNC)
|
---|
1110 | rc = spawnvp(trueflag,real_name,PL_Argv);
|
---|
1111 | else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
|
---|
1112 | rc = result(aTHX_ trueflag,
|
---|
1113 | spawnvp(flag,real_name,PL_Argv));
|
---|
1114 | #endif
|
---|
1115 | if (rc < 0 && pass == 1) {
|
---|
1116 | do_script:
|
---|
1117 | if (real_name == PL_Argv[0]) {
|
---|
1118 | int err = errno;
|
---|
1119 |
|
---|
1120 | if (err == ENOENT || err == ENOEXEC) {
|
---|
1121 | /* No such file, or is a script. */
|
---|
1122 | /* Try adding script extensions to the file name, and
|
---|
1123 | search on PATH. */
|
---|
1124 | char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
|
---|
1125 |
|
---|
1126 | if (scr) {
|
---|
1127 | char *s = 0, *s1;
|
---|
1128 | SV *scrsv = sv_2mortal(newSVpv(scr, 0));
|
---|
1129 | SV *bufsv = sv_newmortal();
|
---|
1130 |
|
---|
1131 | Safefree(scr);
|
---|
1132 | scr = SvPV(scrsv, n_a); /* free()ed later */
|
---|
1133 |
|
---|
1134 | file = PerlIO_open(scr, "r");
|
---|
1135 | PL_Argv[0] = scr;
|
---|
1136 | if (!file)
|
---|
1137 | goto panic_file;
|
---|
1138 |
|
---|
1139 | buf = sv_gets(bufsv, file, 0 /* No append */);
|
---|
1140 | if (!buf)
|
---|
1141 | buf = ""; /* XXX Needed? */
|
---|
1142 | if (!buf[0]) { /* Empty... */
|
---|
1143 | PerlIO_close(file);
|
---|
1144 | /* Special case: maybe from -Zexe build, so
|
---|
1145 | there is an executable around (contrary to
|
---|
1146 | documentation, DosQueryAppType sometimes (?)
|
---|
1147 | does not append ".exe", so we could have
|
---|
1148 | reached this place). */
|
---|
1149 | sv_catpv(scrsv, ".exe");
|
---|
1150 | PL_Argv[0] = scr = SvPV(scrsv, n_a); /* Reload */
|
---|
1151 | if (PerlLIO_stat(scr,&PL_statbuf) >= 0
|
---|
1152 | && !S_ISDIR(PL_statbuf.st_mode)) { /* Found */
|
---|
1153 | real_name = scr;
|
---|
1154 | pass++;
|
---|
1155 | goto reread;
|
---|
1156 | } else { /* Restore */
|
---|
1157 | SvCUR_set(scrsv, SvCUR(scrsv) - 4);
|
---|
1158 | *SvEND(scrsv) = 0;
|
---|
1159 | }
|
---|
1160 | }
|
---|
1161 | if (PerlIO_close(file) != 0) { /* Failure */
|
---|
1162 | panic_file:
|
---|
1163 | if (ckWARN(WARN_EXEC))
|
---|
1164 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s",
|
---|
1165 | scr, Strerror(errno));
|
---|
1166 | buf = ""; /* Not #! */
|
---|
1167 | goto doshell_args;
|
---|
1168 | }
|
---|
1169 | if (buf[0] == '#') {
|
---|
1170 | if (buf[1] == '!')
|
---|
1171 | s = buf + 2;
|
---|
1172 | } else if (buf[0] == 'e') {
|
---|
1173 | if (strnEQ(buf, "extproc", 7)
|
---|
1174 | && isSPACE(buf[7]))
|
---|
1175 | s = buf + 8;
|
---|
1176 | } else if (buf[0] == 'E') {
|
---|
1177 | if (strnEQ(buf, "EXTPROC", 7)
|
---|
1178 | && isSPACE(buf[7]))
|
---|
1179 | s = buf + 8;
|
---|
1180 | }
|
---|
1181 | if (!s) {
|
---|
1182 | buf = ""; /* Not #! */
|
---|
1183 | goto doshell_args;
|
---|
1184 | }
|
---|
1185 |
|
---|
1186 | s1 = s;
|
---|
1187 | nargs = 0;
|
---|
1188 | argsp = args;
|
---|
1189 | while (1) {
|
---|
1190 | /* Do better than pdksh: allow a few args,
|
---|
1191 | strip trailing whitespace. */
|
---|
1192 | while (isSPACE(*s))
|
---|
1193 | s++;
|
---|
1194 | if (*s == 0)
|
---|
1195 | break;
|
---|
1196 | if (nargs == 4) {
|
---|
1197 | nargs = -1;
|
---|
1198 | break;
|
---|
1199 | }
|
---|
1200 | args[nargs++] = s;
|
---|
1201 | while (*s && !isSPACE(*s))
|
---|
1202 | s++;
|
---|
1203 | if (*s == 0)
|
---|
1204 | break;
|
---|
1205 | *s++ = 0;
|
---|
1206 | }
|
---|
1207 | if (nargs == -1) {
|
---|
1208 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Too many args on %.*s line of \"%s\"",
|
---|
1209 | s1 - buf, buf, scr);
|
---|
1210 | nargs = 4;
|
---|
1211 | argsp = fargs;
|
---|
1212 | }
|
---|
1213 | /* Can jump from far, buf/file invalid if force_shell: */
|
---|
1214 | doshell_args:
|
---|
1215 | {
|
---|
1216 | char **a = PL_Argv;
|
---|
1217 | const char *exec_args[2];
|
---|
1218 |
|
---|
1219 | if (force_shell
|
---|
1220 | || (!buf[0] && file)) { /* File without magic */
|
---|
1221 | /* In fact we tried all what pdksh would
|
---|
1222 | try. There is no point in calling
|
---|
1223 | pdksh, we may just emulate its logic. */
|
---|
1224 | char *shell = getenv("EXECSHELL");
|
---|
1225 | char *shell_opt = NULL;
|
---|
1226 |
|
---|
1227 | if (!shell) {
|
---|
1228 | char *s;
|
---|
1229 |
|
---|
1230 | shell_opt = "/c";
|
---|
1231 | shell = getenv("OS2_SHELL");
|
---|
1232 | if (inicmd) { /* No spaces at start! */
|
---|
1233 | s = inicmd;
|
---|
1234 | while (*s && !isSPACE(*s)) {
|
---|
1235 | if (*s++ == '/') {
|
---|
1236 | inicmd = NULL; /* Cannot use */
|
---|
1237 | break;
|
---|
1238 | }
|
---|
1239 | }
|
---|
1240 | }
|
---|
1241 | if (!inicmd) {
|
---|
1242 | s = PL_Argv[0];
|
---|
1243 | while (*s) {
|
---|
1244 | /* Dosish shells will choke on slashes
|
---|
1245 | in paths, fortunately, this is
|
---|
1246 | important for zeroth arg only. */
|
---|
1247 | if (*s == '/')
|
---|
1248 | *s = '\\';
|
---|
1249 | s++;
|
---|
1250 | }
|
---|
1251 | }
|
---|
1252 | }
|
---|
1253 | /* If EXECSHELL is set, we do not set */
|
---|
1254 |
|
---|
1255 | if (!shell)
|
---|
1256 | shell = ((_emx_env & 0x200)
|
---|
1257 | ? "c:/os2/cmd.exe"
|
---|
1258 | : "c:/command.com");
|
---|
1259 | nargs = shell_opt ? 2 : 1; /* shell file args */
|
---|
1260 | exec_args[0] = shell;
|
---|
1261 | exec_args[1] = shell_opt;
|
---|
1262 | argsp = exec_args;
|
---|
1263 | if (nargs == 2 && inicmd) {
|
---|
1264 | /* Use the original cmd line */
|
---|
1265 | /* XXXX This is good only until we refuse
|
---|
1266 | quoted arguments... */
|
---|
1267 | PL_Argv[0] = inicmd;
|
---|
1268 | PL_Argv[1] = Nullch;
|
---|
1269 | }
|
---|
1270 | } else if (!buf[0] && inicmd) { /* No file */
|
---|
1271 | /* Start with the original cmdline. */
|
---|
1272 | /* XXXX This is good only until we refuse
|
---|
1273 | quoted arguments... */
|
---|
1274 |
|
---|
1275 | PL_Argv[0] = inicmd;
|
---|
1276 | PL_Argv[1] = Nullch;
|
---|
1277 | nargs = 2; /* shell -c */
|
---|
1278 | }
|
---|
1279 |
|
---|
1280 | while (a[1]) /* Get to the end */
|
---|
1281 | a++;
|
---|
1282 | a++; /* Copy finil NULL too */
|
---|
1283 | while (a >= PL_Argv) {
|
---|
1284 | *(a + nargs) = *a; /* PL_Argv was preallocated to be
|
---|
1285 | long enough. */
|
---|
1286 | a--;
|
---|
1287 | }
|
---|
1288 | while (--nargs >= 0) /* XXXX Discard const... */
|
---|
1289 | PL_Argv[nargs] = (char*)argsp[nargs];
|
---|
1290 | /* Enable pathless exec if #! (as pdksh). */
|
---|
1291 | pass = (buf[0] == '#' ? 2 : 3);
|
---|
1292 | goto retry;
|
---|
1293 | }
|
---|
1294 | }
|
---|
1295 | /* Not found: restore errno */
|
---|
1296 | errno = err;
|
---|
1297 | }
|
---|
1298 | } else if (errno == ENOEXEC) { /* Cannot transfer `real_name' via shell. */
|
---|
1299 | if (rc < 0 && ckWARN(WARN_EXEC))
|
---|
1300 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s script `%s' with ARGV[0] being `%s'",
|
---|
1301 | ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
|
---|
1302 | ? "spawn" : "exec"),
|
---|
1303 | real_name, PL_Argv[0]);
|
---|
1304 | goto warned;
|
---|
1305 | } else if (errno == ENOENT) { /* Cannot transfer `real_name' via shell. */
|
---|
1306 | if (rc < 0 && ckWARN(WARN_EXEC))
|
---|
1307 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s `%s' with ARGV[0] being `%s' (looking for executables only, not found)",
|
---|
1308 | ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
|
---|
1309 | ? "spawn" : "exec"),
|
---|
1310 | real_name, PL_Argv[0]);
|
---|
1311 | goto warned;
|
---|
1312 | }
|
---|
1313 | } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
|
---|
1314 | char *no_dir = strrchr(PL_Argv[0], '/');
|
---|
1315 |
|
---|
1316 | /* Do as pdksh port does: if not found with /, try without
|
---|
1317 | path. */
|
---|
1318 | if (no_dir) {
|
---|
1319 | PL_Argv[0] = no_dir + 1;
|
---|
1320 | pass++;
|
---|
1321 | goto retry;
|
---|
1322 | }
|
---|
1323 | }
|
---|
1324 | if (rc < 0 && ckWARN(WARN_EXEC))
|
---|
1325 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s\n",
|
---|
1326 | ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
|
---|
1327 | ? "spawn" : "exec"),
|
---|
1328 | real_name, Strerror(errno));
|
---|
1329 | warned:
|
---|
1330 | if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
|
---|
1331 | && ((trueflag & 0xFF) == P_WAIT))
|
---|
1332 | rc = -1;
|
---|
1333 |
|
---|
1334 | finish:
|
---|
1335 | if (new_stderr != -1) { /* How can we use error codes? */
|
---|
1336 | dup2(new_stderr, 2);
|
---|
1337 | close(new_stderr);
|
---|
1338 | fcntl(2, F_SETFD, fl_stderr);
|
---|
1339 | } else if (nostderr)
|
---|
1340 | close(2);
|
---|
1341 | return rc;
|
---|
1342 | }
|
---|
1343 |
|
---|
1344 | /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
|
---|
1345 | int
|
---|
1346 | do_spawn3(pTHX_ char *cmd, int execf, int flag)
|
---|
1347 | {
|
---|
1348 | register char **a;
|
---|
1349 | register char *s;
|
---|
1350 | char *shell, *copt, *news = NULL;
|
---|
1351 | int rc, seenspace = 0, mergestderr = 0;
|
---|
1352 |
|
---|
1353 | #ifdef TRYSHELL
|
---|
1354 | if ((shell = getenv("EMXSHELL")) != NULL)
|
---|
1355 | copt = "-c";
|
---|
1356 | else if ((shell = getenv("SHELL")) != NULL)
|
---|
1357 | copt = "-c";
|
---|
1358 | else if ((shell = getenv("COMSPEC")) != NULL)
|
---|
1359 | copt = "/C";
|
---|
1360 | else
|
---|
1361 | shell = "cmd.exe";
|
---|
1362 | #else
|
---|
1363 | /* Consensus on perl5-porters is that it is _very_ important to
|
---|
1364 | have a shell which will not change between computers with the
|
---|
1365 | same architecture, to avoid "action on a distance".
|
---|
1366 | And to have simple build, this shell should be sh. */
|
---|
1367 | shell = PL_sh_path;
|
---|
1368 | copt = "-c";
|
---|
1369 | #endif
|
---|
1370 |
|
---|
1371 | while (*cmd && isSPACE(*cmd))
|
---|
1372 | cmd++;
|
---|
1373 |
|
---|
1374 | if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
|
---|
1375 | STRLEN l = strlen(PL_sh_path);
|
---|
1376 |
|
---|
1377 | Newx(news, strlen(cmd) - 7 + l + 1, char);
|
---|
1378 | strcpy(news, PL_sh_path);
|
---|
1379 | strcpy(news + l, cmd + 7);
|
---|
1380 | cmd = news;
|
---|
1381 | }
|
---|
1382 |
|
---|
1383 | /* save an extra exec if possible */
|
---|
1384 | /* see if there are shell metacharacters in it */
|
---|
1385 |
|
---|
1386 | if (*cmd == '.' && isSPACE(cmd[1]))
|
---|
1387 | goto doshell;
|
---|
1388 |
|
---|
1389 | if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
|
---|
1390 | goto doshell;
|
---|
1391 |
|
---|
1392 | for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
|
---|
1393 | if (*s == '=')
|
---|
1394 | goto doshell;
|
---|
1395 |
|
---|
1396 | for (s = cmd; *s; s++) {
|
---|
1397 | if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
|
---|
1398 | if (*s == '\n' && s[1] == '\0') {
|
---|
1399 | *s = '\0';
|
---|
1400 | break;
|
---|
1401 | } else if (*s == '\\' && !seenspace) {
|
---|
1402 | continue; /* Allow backslashes in names */
|
---|
1403 | } else if (*s == '>' && s >= cmd + 3
|
---|
1404 | && s[-1] == '2' && s[1] == '&' && s[2] == '1'
|
---|
1405 | && isSPACE(s[-2]) ) {
|
---|
1406 | char *t = s + 3;
|
---|
1407 |
|
---|
1408 | while (*t && isSPACE(*t))
|
---|
1409 | t++;
|
---|
1410 | if (!*t) {
|
---|
1411 | s[-2] = '\0';
|
---|
1412 | mergestderr = 1;
|
---|
1413 | break; /* Allow 2>&1 as the last thing */
|
---|
1414 | }
|
---|
1415 | }
|
---|
1416 | /* We do not convert this to do_spawn_ve since shell
|
---|
1417 | should be smart enough to start itself gloriously. */
|
---|
1418 | doshell:
|
---|
1419 | if (execf == EXECF_TRUEEXEC)
|
---|
1420 | rc = execl(shell,shell,copt,cmd,(char*)0);
|
---|
1421 | else if (execf == EXECF_EXEC)
|
---|
1422 | rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
|
---|
1423 | else if (execf == EXECF_SPAWN_NOWAIT)
|
---|
1424 | rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
|
---|
1425 | else if (execf == EXECF_SPAWN_BYFLAG)
|
---|
1426 | rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
|
---|
1427 | else {
|
---|
1428 | /* In the ak code internal P_NOWAIT is P_WAIT ??? */
|
---|
1429 | if (execf == EXECF_SYNC)
|
---|
1430 | rc = spawnl(P_WAIT,shell,shell,copt,cmd,(char*)0);
|
---|
1431 | else
|
---|
1432 | rc = result(aTHX_ P_WAIT,
|
---|
1433 | spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
|
---|
1434 | if (rc < 0 && ckWARN(WARN_EXEC))
|
---|
1435 | Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
|
---|
1436 | (execf == EXECF_SPAWN ? "spawn" : "exec"),
|
---|
1437 | shell, Strerror(errno));
|
---|
1438 | if (rc < 0)
|
---|
1439 | rc = -1;
|
---|
1440 | }
|
---|
1441 | if (news)
|
---|
1442 | Safefree(news);
|
---|
1443 | return rc;
|
---|
1444 | } else if (*s == ' ' || *s == '\t') {
|
---|
1445 | seenspace = 1;
|
---|
1446 | }
|
---|
1447 | }
|
---|
1448 |
|
---|
1449 | /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
|
---|
1450 | Newx(PL_Argv, (s - cmd + 11) / 2, char*);
|
---|
1451 | PL_Cmd = savepvn(cmd, s-cmd);
|
---|
1452 | a = PL_Argv;
|
---|
1453 | for (s = PL_Cmd; *s;) {
|
---|
1454 | while (*s && isSPACE(*s)) s++;
|
---|
1455 | if (*s)
|
---|
1456 | *(a++) = s;
|
---|
1457 | while (*s && !isSPACE(*s)) s++;
|
---|
1458 | if (*s)
|
---|
1459 | *s++ = '\0';
|
---|
1460 | }
|
---|
1461 | *a = Nullch;
|
---|
1462 | if (PL_Argv[0])
|
---|
1463 | rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
|
---|
1464 | else
|
---|
1465 | rc = -1;
|
---|
1466 | if (news)
|
---|
1467 | Safefree(news);
|
---|
1468 | do_execfree();
|
---|
1469 | return rc;
|
---|
1470 | }
|
---|
1471 |
|
---|
1472 | /* Array spawn/exec. */
|
---|
1473 | int
|
---|
1474 | os2_aspawn4(pTHX_ SV *really, register SV **vmark, register SV **vsp, int execing)
|
---|
1475 | {
|
---|
1476 | register SV **mark = (SV **)vmark;
|
---|
1477 | register SV **sp = (SV **)vsp;
|
---|
1478 | register char **a;
|
---|
1479 | int rc;
|
---|
1480 | int flag = P_WAIT, flag_set = 0;
|
---|
1481 | STRLEN n_a;
|
---|
1482 |
|
---|
1483 | if (sp > mark) {
|
---|
1484 | Newx(PL_Argv, sp - mark + 3, char*);
|
---|
1485 | a = PL_Argv;
|
---|
1486 |
|
---|
1487 | if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
|
---|
1488 | ++mark;
|
---|
1489 | flag = SvIVx(*mark);
|
---|
1490 | flag_set = 1;
|
---|
1491 |
|
---|
1492 | }
|
---|
1493 |
|
---|
1494 | while (++mark <= sp) {
|
---|
1495 | if (*mark)
|
---|
1496 | *a++ = SvPVx(*mark, n_a);
|
---|
1497 | else
|
---|
1498 | *a++ = "";
|
---|
1499 | }
|
---|
1500 | *a = Nullch;
|
---|
1501 |
|
---|
1502 | if ( flag_set && (a == PL_Argv + 1)
|
---|
1503 | && !really && !execing ) { /* One arg? */
|
---|
1504 | rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
|
---|
1505 | } else
|
---|
1506 | rc = do_spawn_ve(aTHX_ really, flag,
|
---|
1507 | (execing ? EXECF_EXEC : EXECF_SPAWN), NULL, 0);
|
---|
1508 | } else
|
---|
1509 | rc = -1;
|
---|
1510 | do_execfree();
|
---|
1511 | return rc;
|
---|
1512 | }
|
---|
1513 |
|
---|
1514 | /* Array spawn. */
|
---|
1515 | int
|
---|
1516 | os2_do_aspawn(pTHX_ SV *really, register SV **vmark, register SV **vsp)
|
---|
1517 | {
|
---|
1518 | return os2_aspawn4(aTHX_ really, vmark, vsp, 0);
|
---|
1519 | }
|
---|
1520 |
|
---|
1521 | /* Array exec. */
|
---|
1522 | bool
|
---|
1523 | Perl_do_aexec(pTHX_ SV* really, SV** vmark, SV** vsp)
|
---|
1524 | {
|
---|
1525 | return os2_aspawn4(aTHX_ really, vmark, vsp, 1);
|
---|
1526 | }
|
---|
1527 |
|
---|
1528 | int
|
---|
1529 | os2_do_spawn(pTHX_ char *cmd)
|
---|
1530 | {
|
---|
1531 | return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
|
---|
1532 | }
|
---|
1533 |
|
---|
1534 | int
|
---|
1535 | do_spawn_nowait(pTHX_ char *cmd)
|
---|
1536 | {
|
---|
1537 | return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
|
---|
1538 | }
|
---|
1539 |
|
---|
1540 | bool
|
---|
1541 | Perl_do_exec(pTHX_ char *cmd)
|
---|
1542 | {
|
---|
1543 | do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
|
---|
1544 | return FALSE;
|
---|
1545 | }
|
---|
1546 |
|
---|
1547 | bool
|
---|
1548 | os2exec(pTHX_ char *cmd)
|
---|
1549 | {
|
---|
1550 | return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
|
---|
1551 | }
|
---|
1552 |
|
---|
1553 | PerlIO *
|
---|
1554 | my_syspopen(pTHX_ char *cmd, char *mode)
|
---|
1555 | {
|
---|
1556 | #ifndef USE_POPEN
|
---|
1557 | int p[2];
|
---|
1558 | register I32 this, that, newfd;
|
---|
1559 | register I32 pid;
|
---|
1560 | SV *sv;
|
---|
1561 | int fh_fl = 0; /* Pacify the warning */
|
---|
1562 |
|
---|
1563 | /* `this' is what we use in the parent, `that' in the child. */
|
---|
1564 | this = (*mode == 'w');
|
---|
1565 | that = !this;
|
---|
1566 | if (PL_tainting) {
|
---|
1567 | taint_env();
|
---|
1568 | taint_proper("Insecure %s%s", "EXEC");
|
---|
1569 | }
|
---|
1570 | if (pipe(p) < 0)
|
---|
1571 | return Nullfp;
|
---|
1572 | /* Now we need to spawn the child. */
|
---|
1573 | if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
|
---|
1574 | int new = dup(p[this]);
|
---|
1575 |
|
---|
1576 | if (new == -1)
|
---|
1577 | goto closepipes;
|
---|
1578 | close(p[this]);
|
---|
1579 | p[this] = new;
|
---|
1580 | }
|
---|
1581 | newfd = dup(*mode == 'r'); /* Preserve std* */
|
---|
1582 | if (newfd == -1) {
|
---|
1583 | /* This cannot happen due to fh being bad after pipe(), since
|
---|
1584 | pipe() should have created fh 0 and 1 even if they were
|
---|
1585 | initially closed. But we closed p[this] before. */
|
---|
1586 | if (errno != EBADF) {
|
---|
1587 | closepipes:
|
---|
1588 | close(p[0]);
|
---|
1589 | close(p[1]);
|
---|
1590 | return Nullfp;
|
---|
1591 | }
|
---|
1592 | } else
|
---|
1593 | fh_fl = fcntl(*mode == 'r', F_GETFD);
|
---|
1594 | if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
|
---|
1595 | dup2(p[that], *mode == 'r');
|
---|
1596 | close(p[that]);
|
---|
1597 | }
|
---|
1598 | /* Where is `this' and newfd now? */
|
---|
1599 | fcntl(p[this], F_SETFD, FD_CLOEXEC);
|
---|
1600 | if (newfd != -1)
|
---|
1601 | fcntl(newfd, F_SETFD, FD_CLOEXEC);
|
---|
1602 | pid = do_spawn_nowait(aTHX_ cmd);
|
---|
1603 | if (newfd == -1)
|
---|
1604 | close(*mode == 'r'); /* It was closed initially */
|
---|
1605 | else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
|
---|
1606 | dup2(newfd, *mode == 'r'); /* Return std* back. */
|
---|
1607 | close(newfd);
|
---|
1608 | fcntl(*mode == 'r', F_SETFD, fh_fl);
|
---|
1609 | } else
|
---|
1610 | fcntl(*mode == 'r', F_SETFD, fh_fl);
|
---|
1611 | if (p[that] == (*mode == 'r'))
|
---|
1612 | close(p[that]);
|
---|
1613 | if (pid == -1) {
|
---|
1614 | close(p[this]);
|
---|
1615 | return Nullfp;
|
---|
1616 | }
|
---|
1617 | if (p[that] < p[this]) { /* Make fh as small as possible */
|
---|
1618 | dup2(p[this], p[that]);
|
---|
1619 | close(p[this]);
|
---|
1620 | p[this] = p[that];
|
---|
1621 | }
|
---|
1622 | sv = *av_fetch(PL_fdpid,p[this],TRUE);
|
---|
1623 | (void)SvUPGRADE(sv,SVt_IV);
|
---|
1624 | SvIVX(sv) = pid;
|
---|
1625 | PL_forkprocess = pid;
|
---|
1626 | return PerlIO_fdopen(p[this], mode);
|
---|
1627 |
|
---|
1628 | #else /* USE_POPEN */
|
---|
1629 |
|
---|
1630 | PerlIO *res;
|
---|
1631 | SV *sv;
|
---|
1632 |
|
---|
1633 | # ifdef TRYSHELL
|
---|
1634 | res = popen(cmd, mode);
|
---|
1635 | # else
|
---|
1636 | char *shell = getenv("EMXSHELL");
|
---|
1637 |
|
---|
1638 | my_setenv("EMXSHELL", PL_sh_path);
|
---|
1639 | res = popen(cmd, mode);
|
---|
1640 | my_setenv("EMXSHELL", shell);
|
---|
1641 | # endif
|
---|
1642 | sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
|
---|
1643 | (void)SvUPGRADE(sv,SVt_IV);
|
---|
1644 | SvIVX(sv) = -1; /* A cooky. */
|
---|
1645 | return res;
|
---|
1646 |
|
---|
1647 | #endif /* USE_POPEN */
|
---|
1648 |
|
---|
1649 | }
|
---|
1650 |
|
---|
1651 | /******************************************************************/
|
---|
1652 |
|
---|
1653 | #ifndef HAS_FORK
|
---|
1654 | int
|
---|
1655 | fork(void)
|
---|
1656 | {
|
---|
1657 | Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
|
---|
1658 | errno = EINVAL;
|
---|
1659 | return -1;
|
---|
1660 | }
|
---|
1661 | #endif
|
---|
1662 |
|
---|
1663 | /*******************************************************************/
|
---|
1664 | /* not implemented in EMX 0.9d */
|
---|
1665 |
|
---|
1666 | char * ctermid(char *s) { return 0; }
|
---|
1667 |
|
---|
1668 | #ifdef MYTTYNAME /* was not in emx0.9a */
|
---|
1669 | void * ttyname(x) { return 0; }
|
---|
1670 | #endif
|
---|
1671 |
|
---|
1672 | /*****************************************************************************/
|
---|
1673 | /* not implemented in C Set++ */
|
---|
1674 |
|
---|
1675 | #ifndef __EMX__
|
---|
1676 | int setuid(x) { errno = EINVAL; return -1; }
|
---|
1677 | int setgid(x) { errno = EINVAL; return -1; }
|
---|
1678 | #endif
|
---|
1679 |
|
---|
1680 | /*****************************************************************************/
|
---|
1681 | /* stat() hack for char/block device */
|
---|
1682 |
|
---|
1683 | #if OS2_STAT_HACK
|
---|
1684 |
|
---|
1685 | enum os2_stat_extra { /* EMX 0.9d fix 4 defines up to 0100000 */
|
---|
1686 | os2_stat_archived = 0x1000000, /* 0100000000 */
|
---|
1687 | os2_stat_hidden = 0x2000000, /* 0200000000 */
|
---|
1688 | os2_stat_system = 0x4000000, /* 0400000000 */
|
---|
1689 | os2_stat_force = 0x8000000, /* Do not ignore flags on chmod */
|
---|
1690 | };
|
---|
1691 |
|
---|
1692 | #define OS2_STAT_SPECIAL (os2_stat_system | os2_stat_archived | os2_stat_hidden)
|
---|
1693 |
|
---|
1694 | static void
|
---|
1695 | massage_os2_attr(struct stat *st)
|
---|
1696 | {
|
---|
1697 | if ( ((st->st_mode & S_IFMT) != S_IFREG
|
---|
1698 | && (st->st_mode & S_IFMT) != S_IFDIR)
|
---|
1699 | || !(st->st_attr & (FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM)))
|
---|
1700 | return;
|
---|
1701 |
|
---|
1702 | if ( st->st_attr & FILE_ARCHIVED )
|
---|
1703 | st->st_mode |= (os2_stat_archived | os2_stat_force);
|
---|
1704 | if ( st->st_attr & FILE_HIDDEN )
|
---|
1705 | st->st_mode |= (os2_stat_hidden | os2_stat_force);
|
---|
1706 | if ( st->st_attr & FILE_SYSTEM )
|
---|
1707 | st->st_mode |= (os2_stat_system | os2_stat_force);
|
---|
1708 | }
|
---|
1709 |
|
---|
1710 | /* First attempt used DosQueryFSAttach which crashed the system when
|
---|
1711 | used with 5.001. Now just look for /dev/. */
|
---|
1712 | int
|
---|
1713 | os2_stat(const char *name, struct stat *st)
|
---|
1714 | {
|
---|
1715 | static int ino = SHRT_MAX;
|
---|
1716 | STRLEN l = strlen(name);
|
---|
1717 |
|
---|
1718 | if ( ( l < 8 || l > 9) || strnicmp(name, "/dev/", 5) != 0
|
---|
1719 | || ( stricmp(name + 5, "con") != 0
|
---|
1720 | && stricmp(name + 5, "tty") != 0
|
---|
1721 | && stricmp(name + 5, "nul") != 0
|
---|
1722 | && stricmp(name + 5, "null") != 0) ) {
|
---|
1723 | int s = stat(name, st);
|
---|
1724 |
|
---|
1725 | if (s)
|
---|
1726 | return s;
|
---|
1727 | massage_os2_attr(st);
|
---|
1728 | return 0;
|
---|
1729 | }
|
---|
1730 |
|
---|
1731 | memset(st, 0, sizeof *st);
|
---|
1732 | st->st_mode = S_IFCHR|0666;
|
---|
1733 | MUTEX_LOCK(&perlos2_state_mutex);
|
---|
1734 | st->st_ino = (ino-- & 0x7FFF);
|
---|
1735 | MUTEX_UNLOCK(&perlos2_state_mutex);
|
---|
1736 | st->st_nlink = 1;
|
---|
1737 | return 0;
|
---|
1738 | }
|
---|
1739 |
|
---|
1740 | int
|
---|
1741 | os2_fstat(int handle, struct stat *st)
|
---|
1742 | {
|
---|
1743 | int s = fstat(handle, st);
|
---|
1744 |
|
---|
1745 | if (s)
|
---|
1746 | return s;
|
---|
1747 | massage_os2_attr(st);
|
---|
1748 | return 0;
|
---|
1749 | }
|
---|
1750 |
|
---|
1751 | #undef chmod
|
---|
1752 | int
|
---|
1753 | os2_chmod (const char *name, int pmode) /* Modelled after EMX src/lib/io/chmod.c */
|
---|
1754 | {
|
---|
1755 | int attr, rc;
|
---|
1756 |
|
---|
1757 | if (!(pmode & os2_stat_force))
|
---|
1758 | return chmod(name, pmode);
|
---|
1759 |
|
---|
1760 | attr = __chmod (name, 0, 0); /* Get attributes */
|
---|
1761 | if (attr < 0)
|
---|
1762 | return -1;
|
---|
1763 | if (pmode & S_IWRITE)
|
---|
1764 | attr &= ~FILE_READONLY;
|
---|
1765 | else
|
---|
1766 | attr |= FILE_READONLY;
|
---|
1767 | /* New logic */
|
---|
1768 | attr &= ~(FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM);
|
---|
1769 |
|
---|
1770 | if ( pmode & os2_stat_archived )
|
---|
1771 | attr |= FILE_ARCHIVED;
|
---|
1772 | if ( pmode & os2_stat_hidden )
|
---|
1773 | attr |= FILE_HIDDEN;
|
---|
1774 | if ( pmode & os2_stat_system )
|
---|
1775 | attr |= FILE_SYSTEM;
|
---|
1776 |
|
---|
1777 | rc = __chmod (name, 1, attr);
|
---|
1778 | if (rc >= 0) rc = 0;
|
---|
1779 | return rc;
|
---|
1780 | }
|
---|
1781 |
|
---|
1782 | #endif
|
---|
1783 |
|
---|
1784 | #ifdef USE_PERL_SBRK
|
---|
1785 |
|
---|
1786 | /* SBRK() emulation, mostly moved to malloc.c. */
|
---|
1787 |
|
---|
1788 | void *
|
---|
1789 | sys_alloc(int size) {
|
---|
1790 | void *got;
|
---|
1791 | APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
|
---|
1792 |
|
---|
1793 | if (rc == ERROR_NOT_ENOUGH_MEMORY) {
|
---|
1794 | return (void *) -1;
|
---|
1795 | } else if ( rc )
|
---|
1796 | Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
|
---|
1797 | return got;
|
---|
1798 | }
|
---|
1799 |
|
---|
1800 | #endif /* USE_PERL_SBRK */
|
---|
1801 |
|
---|
1802 | /* tmp path */
|
---|
1803 |
|
---|
1804 | const char *tmppath = TMPPATH1;
|
---|
1805 |
|
---|
1806 | void
|
---|
1807 | settmppath()
|
---|
1808 | {
|
---|
1809 | char *p = getenv("TMP"), *tpath;
|
---|
1810 | int len;
|
---|
1811 |
|
---|
1812 | if (!p) p = getenv("TEMP");
|
---|
1813 | if (!p) p = getenv("TMPDIR");
|
---|
1814 | if (!p) return;
|
---|
1815 | len = strlen(p);
|
---|
1816 | tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
|
---|
1817 | if (tpath) {
|
---|
1818 | strcpy(tpath, p);
|
---|
1819 | tpath[len] = '/';
|
---|
1820 | strcpy(tpath + len + 1, TMPPATH1);
|
---|
1821 | tmppath = tpath;
|
---|
1822 | }
|
---|
1823 | }
|
---|
1824 |
|
---|
1825 | #include "XSUB.h"
|
---|
1826 |
|
---|
1827 | XS(XS_File__Copy_syscopy)
|
---|
1828 | {
|
---|
1829 | dXSARGS;
|
---|
1830 | if (items < 2 || items > 3)
|
---|
1831 | Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
|
---|
1832 | {
|
---|
1833 | STRLEN n_a;
|
---|
1834 | char * src = (char *)SvPV(ST(0),n_a);
|
---|
1835 | char * dst = (char *)SvPV(ST(1),n_a);
|
---|
1836 | U32 flag;
|
---|
1837 | int RETVAL, rc;
|
---|
1838 | dXSTARG;
|
---|
1839 |
|
---|
1840 | if (items < 3)
|
---|
1841 | flag = 0;
|
---|
1842 | else {
|
---|
1843 | flag = (unsigned long)SvIV(ST(2));
|
---|
1844 | }
|
---|
1845 |
|
---|
1846 | RETVAL = !CheckOSError(DosCopy(src, dst, flag));
|
---|
1847 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
1848 | }
|
---|
1849 | XSRETURN(1);
|
---|
1850 | }
|
---|
1851 |
|
---|
1852 | /* APIRET APIENTRY DosReplaceModule (PCSZ pszOld, PCSZ pszNew, PCSZ pszBackup); */
|
---|
1853 |
|
---|
1854 | DeclOSFuncByORD(ULONG,replaceModule,ORD_DosReplaceModule,
|
---|
1855 | (char *old, char *new, char *backup), (old, new, backup))
|
---|
1856 |
|
---|
1857 | XS(XS_OS2_replaceModule); /* prototype to pass -Wmissing-prototypes */
|
---|
1858 | XS(XS_OS2_replaceModule)
|
---|
1859 | {
|
---|
1860 | dXSARGS;
|
---|
1861 | if (items < 1 || items > 3)
|
---|
1862 | Perl_croak(aTHX_ "Usage: OS2::replaceModule(target [, source [, backup]])");
|
---|
1863 | {
|
---|
1864 | char * target = (char *)SvPV_nolen(ST(0));
|
---|
1865 | char * source = (items < 2) ? Nullch : (char *)SvPV_nolen(ST(1));
|
---|
1866 | char * backup = (items < 3) ? Nullch : (char *)SvPV_nolen(ST(2));
|
---|
1867 |
|
---|
1868 | if (!replaceModule(target, source, backup))
|
---|
1869 | croak_with_os2error("replaceModule() error");
|
---|
1870 | }
|
---|
1871 | XSRETURN_EMPTY;
|
---|
1872 | }
|
---|
1873 |
|
---|
1874 | /* APIRET APIENTRY DosPerfSysCall(ULONG ulCommand, ULONG ulParm1,
|
---|
1875 | ULONG ulParm2, ULONG ulParm3); */
|
---|
1876 |
|
---|
1877 | DeclOSFuncByORD(ULONG,perfSysCall,ORD_DosPerfSysCall,
|
---|
1878 | (ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3),
|
---|
1879 | (ulCommand, ulParm1, ulParm2, ulParm3))
|
---|
1880 |
|
---|
1881 | #ifndef CMD_KI_RDCNT
|
---|
1882 | # define CMD_KI_RDCNT 0x63
|
---|
1883 | #endif
|
---|
1884 | #ifndef CMD_KI_GETQTY
|
---|
1885 | # define CMD_KI_GETQTY 0x41
|
---|
1886 | #endif
|
---|
1887 | #ifndef QSV_NUMPROCESSORS
|
---|
1888 | # define QSV_NUMPROCESSORS 26
|
---|
1889 | #endif
|
---|
1890 |
|
---|
1891 | typedef unsigned long long myCPUUTIL[4]; /* time/idle/busy/intr */
|
---|
1892 |
|
---|
1893 | /*
|
---|
1894 | NO_OUTPUT ULONG
|
---|
1895 | perfSysCall(ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3)
|
---|
1896 | PREINIT:
|
---|
1897 | ULONG rc;
|
---|
1898 | POSTCALL:
|
---|
1899 | if (!RETVAL)
|
---|
1900 | croak_with_os2error("perfSysCall() error");
|
---|
1901 | */
|
---|
1902 |
|
---|
1903 | static int
|
---|
1904 | numprocessors(void)
|
---|
1905 | {
|
---|
1906 | ULONG res;
|
---|
1907 |
|
---|
1908 | if (DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, (PVOID)&res, sizeof(res)))
|
---|
1909 | return 1; /* Old system? */
|
---|
1910 | return res;
|
---|
1911 | }
|
---|
1912 |
|
---|
1913 | XS(XS_OS2_perfSysCall); /* prototype to pass -Wmissing-prototypes */
|
---|
1914 | XS(XS_OS2_perfSysCall)
|
---|
1915 | {
|
---|
1916 | dXSARGS;
|
---|
1917 | if (items < 0 || items > 4)
|
---|
1918 | Perl_croak(aTHX_ "Usage: OS2::perfSysCall(ulCommand = CMD_KI_RDCNT, ulParm1= 0, ulParm2= 0, ulParm3= 0)");
|
---|
1919 | SP -= items;
|
---|
1920 | {
|
---|
1921 | dXSTARG;
|
---|
1922 | ULONG RETVAL, ulCommand, ulParm1, ulParm2, ulParm3, res;
|
---|
1923 | myCPUUTIL u[64];
|
---|
1924 | int total = 0, tot2 = 0;
|
---|
1925 |
|
---|
1926 | if (items < 1)
|
---|
1927 | ulCommand = CMD_KI_RDCNT;
|
---|
1928 | else {
|
---|
1929 | ulCommand = (ULONG)SvUV(ST(0));
|
---|
1930 | }
|
---|
1931 |
|
---|
1932 | if (items < 2) {
|
---|
1933 | total = (ulCommand == CMD_KI_RDCNT ? numprocessors() : 0);
|
---|
1934 | ulParm1 = (total ? (ULONG)u : 0);
|
---|
1935 |
|
---|
1936 | if (total > C_ARRAY_LENGTH(u))
|
---|
1937 | croak("Unexpected number of processors: %d", total);
|
---|
1938 | } else {
|
---|
1939 | ulParm1 = (ULONG)SvUV(ST(1));
|
---|
1940 | }
|
---|
1941 |
|
---|
1942 | if (items < 3) {
|
---|
1943 | tot2 = (ulCommand == CMD_KI_GETQTY);
|
---|
1944 | ulParm2 = (tot2 ? (ULONG)&res : 0);
|
---|
1945 | } else {
|
---|
1946 | ulParm2 = (ULONG)SvUV(ST(2));
|
---|
1947 | }
|
---|
1948 |
|
---|
1949 | if (items < 4)
|
---|
1950 | ulParm3 = 0;
|
---|
1951 | else {
|
---|
1952 | ulParm3 = (ULONG)SvUV(ST(3));
|
---|
1953 | }
|
---|
1954 |
|
---|
1955 | RETVAL = perfSysCall(ulCommand, ulParm1, ulParm2, ulParm3);
|
---|
1956 | if (!RETVAL)
|
---|
1957 | croak_with_os2error("perfSysCall() error");
|
---|
1958 | if (total) {
|
---|
1959 | int i,j;
|
---|
1960 |
|
---|
1961 | if (GIMME_V != G_ARRAY) {
|
---|
1962 | PUSHn(u[0][0]); /* Total ticks on the first processor */
|
---|
1963 | XSRETURN(1);
|
---|
1964 | }
|
---|
1965 | for (i=0; i < total; i++)
|
---|
1966 | for (j=0; j < 4; j++)
|
---|
1967 | PUSHs(sv_2mortal(newSVnv(u[i][j])));
|
---|
1968 | XSRETURN(4*total);
|
---|
1969 | }
|
---|
1970 | if (tot2) {
|
---|
1971 | PUSHu(res);
|
---|
1972 | XSRETURN(1);
|
---|
1973 | }
|
---|
1974 | }
|
---|
1975 | XSRETURN_EMPTY;
|
---|
1976 | }
|
---|
1977 |
|
---|
1978 | #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */
|
---|
1979 | #include "patchlevel.h"
|
---|
1980 | #undef PERL_PATCHLEVEL_H_IMPLICIT
|
---|
1981 |
|
---|
1982 | char *
|
---|
1983 | mod2fname(pTHX_ SV *sv)
|
---|
1984 | {
|
---|
1985 | int pos = 6, len, avlen;
|
---|
1986 | unsigned int sum = 0;
|
---|
1987 | char *s;
|
---|
1988 | STRLEN n_a;
|
---|
1989 |
|
---|
1990 | if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
|
---|
1991 | sv = SvRV(sv);
|
---|
1992 | if (SvTYPE(sv) != SVt_PVAV)
|
---|
1993 | Perl_croak_nocontext("Not array reference given to mod2fname");
|
---|
1994 |
|
---|
1995 | avlen = av_len((AV*)sv);
|
---|
1996 | if (avlen < 0)
|
---|
1997 | Perl_croak_nocontext("Empty array reference given to mod2fname");
|
---|
1998 |
|
---|
1999 | s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
|
---|
2000 | strncpy(fname, s, 8);
|
---|
2001 | len = strlen(s);
|
---|
2002 | if (len < 6) pos = len;
|
---|
2003 | while (*s) {
|
---|
2004 | sum = 33 * sum + *(s++); /* Checksumming first chars to
|
---|
2005 | * get the capitalization into c.s. */
|
---|
2006 | }
|
---|
2007 | avlen --;
|
---|
2008 | while (avlen >= 0) {
|
---|
2009 | s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
|
---|
2010 | while (*s) {
|
---|
2011 | sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
|
---|
2012 | }
|
---|
2013 | avlen --;
|
---|
2014 | }
|
---|
2015 | /* We always load modules as *specific* DLLs, and with the full name.
|
---|
2016 | When loading a specific DLL by its full name, one cannot get a
|
---|
2017 | different DLL, even if a DLL with the same basename is loaded already.
|
---|
2018 | Thus there is no need to include the version into the mangling scheme. */
|
---|
2019 | #if 0
|
---|
2020 | sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
|
---|
2021 | #else
|
---|
2022 | # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
|
---|
2023 | # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
|
---|
2024 | # endif
|
---|
2025 | sum += COMPATIBLE_VERSION_SUM;
|
---|
2026 | #endif
|
---|
2027 | fname[pos] = 'A' + (sum % 26);
|
---|
2028 | fname[pos + 1] = 'A' + (sum / 26 % 26);
|
---|
2029 | fname[pos + 2] = '\0';
|
---|
2030 | return (char *)fname;
|
---|
2031 | }
|
---|
2032 |
|
---|
2033 | XS(XS_DynaLoader_mod2fname)
|
---|
2034 | {
|
---|
2035 | dXSARGS;
|
---|
2036 | if (items != 1)
|
---|
2037 | Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
|
---|
2038 | {
|
---|
2039 | SV * sv = ST(0);
|
---|
2040 | char * RETVAL;
|
---|
2041 | dXSTARG;
|
---|
2042 |
|
---|
2043 | RETVAL = mod2fname(aTHX_ sv);
|
---|
2044 | sv_setpv(TARG, RETVAL);
|
---|
2045 | XSprePUSH; PUSHTARG;
|
---|
2046 | }
|
---|
2047 | XSRETURN(1);
|
---|
2048 | }
|
---|
2049 |
|
---|
2050 | char *
|
---|
2051 | os2error(int rc)
|
---|
2052 | {
|
---|
2053 | dTHX;
|
---|
2054 | ULONG len;
|
---|
2055 | char *s;
|
---|
2056 | int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
|
---|
2057 |
|
---|
2058 | if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
|
---|
2059 | if (rc == 0)
|
---|
2060 | return "";
|
---|
2061 | if (number) {
|
---|
2062 | sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
|
---|
2063 | s = os2error_buf + strlen(os2error_buf);
|
---|
2064 | } else
|
---|
2065 | s = os2error_buf;
|
---|
2066 | if (DosGetMessage(NULL, 0, s, sizeof(os2error_buf) - 1 - (s-os2error_buf),
|
---|
2067 | rc, "OSO001.MSG", &len)) {
|
---|
2068 | char *name = "";
|
---|
2069 |
|
---|
2070 | if (!number) {
|
---|
2071 | sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
|
---|
2072 | s = os2error_buf + strlen(os2error_buf);
|
---|
2073 | }
|
---|
2074 | switch (rc) {
|
---|
2075 | case PMERR_INVALID_HWND:
|
---|
2076 | name = "PMERR_INVALID_HWND";
|
---|
2077 | break;
|
---|
2078 | case PMERR_INVALID_HMQ:
|
---|
2079 | name = "PMERR_INVALID_HMQ";
|
---|
2080 | break;
|
---|
2081 | case PMERR_CALL_FROM_WRONG_THREAD:
|
---|
2082 | name = "PMERR_CALL_FROM_WRONG_THREAD";
|
---|
2083 | break;
|
---|
2084 | case PMERR_NO_MSG_QUEUE:
|
---|
2085 | name = "PMERR_NO_MSG_QUEUE";
|
---|
2086 | break;
|
---|
2087 | case PMERR_NOT_IN_A_PM_SESSION:
|
---|
2088 | name = "PMERR_NOT_IN_A_PM_SESSION";
|
---|
2089 | break;
|
---|
2090 | }
|
---|
2091 | sprintf(s, "%s%s[No description found in OSO001.MSG]",
|
---|
2092 | name, (*name ? "=" : ""));
|
---|
2093 | } else {
|
---|
2094 | s[len] = '\0';
|
---|
2095 | if (len && s[len - 1] == '\n')
|
---|
2096 | s[--len] = 0;
|
---|
2097 | if (len && s[len - 1] == '\r')
|
---|
2098 | s[--len] = 0;
|
---|
2099 | if (len && s[len - 1] == '.')
|
---|
2100 | s[--len] = 0;
|
---|
2101 | if (len >= 10 && number && strnEQ(s, os2error_buf, 7)
|
---|
2102 | && s[7] == ':' && s[8] == ' ')
|
---|
2103 | /* Some messages start with SYSdddd:, some not */
|
---|
2104 | Move(s + 9, s, (len -= 9) + 1, char);
|
---|
2105 | }
|
---|
2106 | return os2error_buf;
|
---|
2107 | }
|
---|
2108 |
|
---|
2109 | void
|
---|
2110 | ResetWinError(void)
|
---|
2111 | {
|
---|
2112 | WinError_2_Perl_rc;
|
---|
2113 | }
|
---|
2114 |
|
---|
2115 | void
|
---|
2116 | CroakWinError(int die, char *name)
|
---|
2117 | {
|
---|
2118 | FillWinError;
|
---|
2119 | if (die && Perl_rc)
|
---|
2120 | croak_with_os2error(name ? name : "Win* API call");
|
---|
2121 | }
|
---|
2122 |
|
---|
2123 | static char *
|
---|
2124 | dllname2buffer(pTHX_ char *buf, STRLEN l)
|
---|
2125 | {
|
---|
2126 | char *o;
|
---|
2127 | STRLEN ll;
|
---|
2128 | SV *dll = Nullsv;
|
---|
2129 |
|
---|
2130 | dll = module_name(mod_name_full);
|
---|
2131 | o = SvPV(dll, ll);
|
---|
2132 | if (ll < l)
|
---|
2133 | memcpy(buf,o,ll);
|
---|
2134 | SvREFCNT_dec(dll);
|
---|
2135 | return (ll >= l ? "???" : buf);
|
---|
2136 | }
|
---|
2137 |
|
---|
2138 | static char *
|
---|
2139 | execname2buffer(char *buf, STRLEN l, char *oname)
|
---|
2140 | {
|
---|
2141 | char *p, *orig = oname, ok = oname != NULL;
|
---|
2142 |
|
---|
2143 | if (_execname(buf, l) != 0) {
|
---|
2144 | if (!oname || strlen(oname) >= l)
|
---|
2145 | return oname;
|
---|
2146 | strcpy(buf, oname);
|
---|
2147 | ok = 0;
|
---|
2148 | }
|
---|
2149 | p = buf;
|
---|
2150 | while (*p) {
|
---|
2151 | if (*p == '\\')
|
---|
2152 | *p = '/';
|
---|
2153 | if (*p == '/') {
|
---|
2154 | if (ok && *oname != '/' && *oname != '\\')
|
---|
2155 | ok = 0;
|
---|
2156 | } else if (ok && tolower(*oname) != tolower(*p))
|
---|
2157 | ok = 0;
|
---|
2158 | p++;
|
---|
2159 | oname++;
|
---|
2160 | }
|
---|
2161 | if (ok) { /* orig matches the real name. Use orig: */
|
---|
2162 | strcpy(buf, orig); /* _execname() is always uppercased */
|
---|
2163 | p = buf;
|
---|
2164 | while (*p) {
|
---|
2165 | if (*p == '\\')
|
---|
2166 | *p = '/';
|
---|
2167 | p++;
|
---|
2168 | }
|
---|
2169 | }
|
---|
2170 | return buf;
|
---|
2171 | }
|
---|
2172 |
|
---|
2173 | char *
|
---|
2174 | os2_execname(pTHX)
|
---|
2175 | {
|
---|
2176 | char buf[300], *p = execname2buffer(buf, sizeof buf, PL_origargv[0]);
|
---|
2177 |
|
---|
2178 | p = savepv(p);
|
---|
2179 | SAVEFREEPV(p);
|
---|
2180 | return p;
|
---|
2181 | }
|
---|
2182 |
|
---|
2183 | int
|
---|
2184 | Perl_OS2_handler_install(void *handler, enum Perlos2_handler how)
|
---|
2185 | {
|
---|
2186 | char *s, b[300];
|
---|
2187 |
|
---|
2188 | switch (how) {
|
---|
2189 | case Perlos2_handler_mangle:
|
---|
2190 | perllib_mangle_installed = (char *(*)(char *s, unsigned int l))handler;
|
---|
2191 | return 1;
|
---|
2192 | case Perlos2_handler_perl_sh:
|
---|
2193 | s = (char *)handler;
|
---|
2194 | s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perl_sh");
|
---|
2195 | perl_sh_installed = savepv(s);
|
---|
2196 | return 1;
|
---|
2197 | case Perlos2_handler_perllib_from:
|
---|
2198 | s = (char *)handler;
|
---|
2199 | s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_from");
|
---|
2200 | oldl = strlen(s);
|
---|
2201 | oldp = savepv(s);
|
---|
2202 | return 1;
|
---|
2203 | case Perlos2_handler_perllib_to:
|
---|
2204 | s = (char *)handler;
|
---|
2205 | s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_to");
|
---|
2206 | newl = strlen(s);
|
---|
2207 | newp = savepv(s);
|
---|
2208 | strcpy(mangle_ret, newp);
|
---|
2209 | s = mangle_ret - 1;
|
---|
2210 | while (*++s)
|
---|
2211 | if (*s == '\\')
|
---|
2212 | *s = '/';
|
---|
2213 | return 1;
|
---|
2214 | default:
|
---|
2215 | return 0;
|
---|
2216 | }
|
---|
2217 | }
|
---|
2218 |
|
---|
2219 | /* Returns a malloc()ed copy */
|
---|
2220 | char *
|
---|
2221 | dir_subst(char *s, unsigned int l, char *b, unsigned int bl, enum dir_subst_e flags, char *msg)
|
---|
2222 | {
|
---|
2223 | char *from, *to = b, *e = b; /* `to' assignment: shut down the warning */
|
---|
2224 | STRLEN froml = 0, tol = 0, rest = 0; /* froml: likewise */
|
---|
2225 |
|
---|
2226 | if (l >= 2 && s[0] == '~') {
|
---|
2227 | switch (s[1]) {
|
---|
2228 | case 'i': case 'I':
|
---|
2229 | from = "installprefix"; break;
|
---|
2230 | case 'd': case 'D':
|
---|
2231 | from = "dll"; break;
|
---|
2232 | case 'e': case 'E':
|
---|
2233 | from = "exe"; break;
|
---|
2234 | default:
|
---|
2235 | from = NULL;
|
---|
2236 | froml = l + 1; /* Will not match */
|
---|
2237 | break;
|
---|
2238 | }
|
---|
2239 | if (from)
|
---|
2240 | froml = strlen(from) + 1;
|
---|
2241 | if (l >= froml && strnicmp(s + 2, from + 1, froml - 2) == 0) {
|
---|
2242 | int strip = 1;
|
---|
2243 |
|
---|
2244 | switch (s[1]) {
|
---|
2245 | case 'i': case 'I':
|
---|
2246 | strip = 0;
|
---|
2247 | tol = strlen(INSTALL_PREFIX);
|
---|
2248 | if (tol >= bl) {
|
---|
2249 | if (flags & dir_subst_fatal)
|
---|
2250 | Perl_croak_nocontext("INSTALL_PREFIX too long: `%s'", INSTALL_PREFIX);
|
---|
2251 | else
|
---|
2252 | return NULL;
|
---|
2253 | }
|
---|
2254 | memcpy(b, INSTALL_PREFIX, tol + 1);
|
---|
2255 | to = b;
|
---|
2256 | e = b + tol;
|
---|
2257 | break;
|
---|
2258 | case 'd': case 'D':
|
---|
2259 | if (flags & dir_subst_fatal) {
|
---|
2260 | dTHX;
|
---|
2261 |
|
---|
2262 | to = dllname2buffer(aTHX_ b, bl);
|
---|
2263 | } else { /* No Perl present yet */
|
---|
2264 | HMODULE self = find_myself();
|
---|
2265 | APIRET rc = DosQueryModuleName(self, bl, b);
|
---|
2266 |
|
---|
2267 | if (rc)
|
---|
2268 | return 0;
|
---|
2269 | to = b - 1;
|
---|
2270 | while (*++to)
|
---|
2271 | if (*to == '\\')
|
---|
2272 | *to = '/';
|
---|
2273 | to = b;
|
---|
2274 | }
|
---|
2275 | break;
|
---|
2276 | case 'e': case 'E':
|
---|
2277 | if (flags & dir_subst_fatal) {
|
---|
2278 | dTHX;
|
---|
2279 |
|
---|
2280 | to = execname2buffer(b, bl, PL_origargv[0]);
|
---|
2281 | } else
|
---|
2282 | to = execname2buffer(b, bl, NULL);
|
---|
2283 | break;
|
---|
2284 | }
|
---|
2285 | if (!to)
|
---|
2286 | return NULL;
|
---|
2287 | if (strip) {
|
---|
2288 | e = strrchr(to, '/');
|
---|
2289 | if (!e && (flags & dir_subst_fatal))
|
---|
2290 | Perl_croak_nocontext("%s: Can't parse EXE/DLL name: '%s'", msg, to);
|
---|
2291 | else if (!e)
|
---|
2292 | return NULL;
|
---|
2293 | *e = 0;
|
---|
2294 | }
|
---|
2295 | s += froml; l -= froml;
|
---|
2296 | if (!l)
|
---|
2297 | return to;
|
---|
2298 | if (!tol)
|
---|
2299 | tol = strlen(to);
|
---|
2300 |
|
---|
2301 | while (l >= 3 && (s[0] == '/' || s[0] == '\\')
|
---|
2302 | && s[1] == '.' && s[2] == '.'
|
---|
2303 | && (l == 3 || s[3] == '/' || s[3] == '\\' || s[3] == ';')) {
|
---|
2304 | e = strrchr(b, '/');
|
---|
2305 | if (!e && (flags & dir_subst_fatal))
|
---|
2306 | Perl_croak_nocontext("%s: Error stripping dirs from EXE/DLL/INSTALLDIR name", msg);
|
---|
2307 | else if (!e)
|
---|
2308 | return NULL;
|
---|
2309 | *e = 0;
|
---|
2310 | l -= 3; s += 3;
|
---|
2311 | }
|
---|
2312 | if (l && s[0] != '/' && s[0] != '\\' && s[0] != ';')
|
---|
2313 | *e++ = '/';
|
---|
2314 | }
|
---|
2315 | } /* Else: copy as is */
|
---|
2316 | if (l && (flags & dir_subst_pathlike)) {
|
---|
2317 | STRLEN i = 0;
|
---|
2318 |
|
---|
2319 | while ( i < l - 2 && s[i] != ';') /* May have ~char after `;' */
|
---|
2320 | i++;
|
---|
2321 | if (i < l - 2) { /* Found */
|
---|
2322 | rest = l - i - 1;
|
---|
2323 | l = i + 1;
|
---|
2324 | }
|
---|
2325 | }
|
---|
2326 | if (e + l >= b + bl) {
|
---|
2327 | if (flags & dir_subst_fatal)
|
---|
2328 | Perl_croak_nocontext("%s: name `%s%s' too long", msg, b, s);
|
---|
2329 | else
|
---|
2330 | return NULL;
|
---|
2331 | }
|
---|
2332 | memcpy(e, s, l);
|
---|
2333 | if (rest) {
|
---|
2334 | e = dir_subst(s + l, rest, e + l, bl - (e + l - b), flags, msg);
|
---|
2335 | return e ? b : e;
|
---|
2336 | }
|
---|
2337 | e[l] = 0;
|
---|
2338 | return b;
|
---|
2339 | }
|
---|
2340 |
|
---|
2341 | char *
|
---|
2342 | perllib_mangle_with(char *s, unsigned int l, char *from, unsigned int froml, char *to, unsigned int tol)
|
---|
2343 | {
|
---|
2344 | if (!to)
|
---|
2345 | return s;
|
---|
2346 | if (l == 0)
|
---|
2347 | l = strlen(s);
|
---|
2348 | if (l < froml || strnicmp(from, s, froml) != 0)
|
---|
2349 | return s;
|
---|
2350 | if (l + tol - froml > STATIC_FILE_LENGTH || tol > STATIC_FILE_LENGTH)
|
---|
2351 | Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
|
---|
2352 | if (to && to != mangle_ret)
|
---|
2353 | memcpy(mangle_ret, to, tol);
|
---|
2354 | strcpy(mangle_ret + tol, s + froml);
|
---|
2355 | return mangle_ret;
|
---|
2356 | }
|
---|
2357 |
|
---|
2358 | char *
|
---|
2359 | perllib_mangle(char *s, unsigned int l)
|
---|
2360 | {
|
---|
2361 | char *name;
|
---|
2362 |
|
---|
2363 | if (perllib_mangle_installed && (name = perllib_mangle_installed(s,l)))
|
---|
2364 | return name;
|
---|
2365 | if (!newp && !notfound) {
|
---|
2366 | newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
|
---|
2367 | STRINGIFY(PERL_VERSION) STRINGIFY(PERL_SUBVERSION)
|
---|
2368 | "_PREFIX");
|
---|
2369 | if (!newp)
|
---|
2370 | newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
|
---|
2371 | STRINGIFY(PERL_VERSION) "_PREFIX");
|
---|
2372 | if (!newp)
|
---|
2373 | newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) "_PREFIX");
|
---|
2374 | if (!newp)
|
---|
2375 | newp = getenv(name = "PERLLIB_PREFIX");
|
---|
2376 | if (newp) {
|
---|
2377 | char *s, b[300];
|
---|
2378 |
|
---|
2379 | oldp = newp;
|
---|
2380 | while (*newp && !isSPACE(*newp) && *newp != ';')
|
---|
2381 | newp++; /* Skip old name. */
|
---|
2382 | oldl = newp - oldp;
|
---|
2383 | s = dir_subst(oldp, oldl, b, sizeof b, dir_subst_fatal, name);
|
---|
2384 | oldp = savepv(s);
|
---|
2385 | oldl = strlen(s);
|
---|
2386 | while (*newp && (isSPACE(*newp) || *newp == ';'))
|
---|
2387 | newp++; /* Skip whitespace. */
|
---|
2388 | Perl_OS2_handler_install((void *)newp, Perlos2_handler_perllib_to);
|
---|
2389 | if (newl == 0 || oldl == 0)
|
---|
2390 | Perl_croak_nocontext("Malformed %s", name);
|
---|
2391 | } else
|
---|
2392 | notfound = 1;
|
---|
2393 | }
|
---|
2394 | if (!newp)
|
---|
2395 | return s;
|
---|
2396 | if (l == 0)
|
---|
2397 | l = strlen(s);
|
---|
2398 | if (l < oldl || strnicmp(oldp, s, oldl) != 0)
|
---|
2399 | return s;
|
---|
2400 | if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH)
|
---|
2401 | Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
|
---|
2402 | strcpy(mangle_ret + newl, s + oldl);
|
---|
2403 | return mangle_ret;
|
---|
2404 | }
|
---|
2405 |
|
---|
2406 | unsigned long
|
---|
2407 | Perl_hab_GET() /* Needed if perl.h cannot be included */
|
---|
2408 | {
|
---|
2409 | return perl_hab_GET();
|
---|
2410 | }
|
---|
2411 |
|
---|
2412 | static void
|
---|
2413 | Create_HMQ(int serve, char *message) /* Assumes morphing */
|
---|
2414 | {
|
---|
2415 | unsigned fpflag = _control87(0,0);
|
---|
2416 |
|
---|
2417 | init_PMWIN_entries();
|
---|
2418 | /* 64 messages if before OS/2 3.0, ignored otherwise */
|
---|
2419 | Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
|
---|
2420 | if (!Perl_hmq) {
|
---|
2421 | dTHX;
|
---|
2422 |
|
---|
2423 | SAVEINT(rmq_cnt); /* Allow catch()ing. */
|
---|
2424 | if (rmq_cnt++)
|
---|
2425 | _exit(188); /* Panic can try to create a window. */
|
---|
2426 | CroakWinError(1, message ? message : "Cannot create a message queue");
|
---|
2427 | }
|
---|
2428 | if (serve != -1)
|
---|
2429 | (*PMWIN_entries.CancelShutdown)(Perl_hmq, !serve);
|
---|
2430 | /* We may have loaded some modules */
|
---|
2431 | _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
|
---|
2432 | }
|
---|
2433 |
|
---|
2434 | #define REGISTERMQ_WILL_SERVE 1
|
---|
2435 | #define REGISTERMQ_IMEDIATE_UNMORPH 2
|
---|
2436 |
|
---|
2437 | HMQ
|
---|
2438 | Perl_Register_MQ(int serve)
|
---|
2439 | {
|
---|
2440 | if (Perl_hmq_refcnt <= 0) {
|
---|
2441 | PPIB pib;
|
---|
2442 | PTIB tib;
|
---|
2443 |
|
---|
2444 | Perl_hmq_refcnt = 0; /* Be extra safe */
|
---|
2445 | DosGetInfoBlocks(&tib, &pib);
|
---|
2446 | if (!Perl_morph_refcnt) {
|
---|
2447 | Perl_os2_initial_mode = pib->pib_ultype;
|
---|
2448 | /* Try morphing into a PM application. */
|
---|
2449 | if (pib->pib_ultype != 3) /* 2 is VIO */
|
---|
2450 | pib->pib_ultype = 3; /* 3 is PM */
|
---|
2451 | }
|
---|
2452 | Create_HMQ(-1, /* We do CancelShutdown ourselves */
|
---|
2453 | "Cannot create a message queue, or morph to a PM application");
|
---|
2454 | if ((serve & REGISTERMQ_IMEDIATE_UNMORPH)) {
|
---|
2455 | if (!Perl_morph_refcnt && Perl_os2_initial_mode != 3)
|
---|
2456 | pib->pib_ultype = Perl_os2_initial_mode;
|
---|
2457 | }
|
---|
2458 | }
|
---|
2459 | if (serve & REGISTERMQ_WILL_SERVE) {
|
---|
2460 | if ( Perl_hmq_servers <= 0 /* Safe to inform us on shutdown, */
|
---|
2461 | && Perl_hmq_refcnt > 0 ) /* this was switched off before... */
|
---|
2462 | (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
|
---|
2463 | Perl_hmq_servers++;
|
---|
2464 | } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
|
---|
2465 | (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
|
---|
2466 | Perl_hmq_refcnt++;
|
---|
2467 | if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH))
|
---|
2468 | Perl_morph_refcnt++;
|
---|
2469 | return Perl_hmq;
|
---|
2470 | }
|
---|
2471 |
|
---|
2472 | int
|
---|
2473 | Perl_Serve_Messages(int force)
|
---|
2474 | {
|
---|
2475 | int cnt = 0;
|
---|
2476 | QMSG msg;
|
---|
2477 |
|
---|
2478 | if (Perl_hmq_servers > 0 && !force)
|
---|
2479 | return 0;
|
---|
2480 | if (Perl_hmq_refcnt <= 0)
|
---|
2481 | Perl_croak_nocontext("No message queue");
|
---|
2482 | while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
|
---|
2483 | cnt++;
|
---|
2484 | if (msg.msg == WM_QUIT)
|
---|
2485 | Perl_croak_nocontext("QUITing...");
|
---|
2486 | (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
|
---|
2487 | }
|
---|
2488 | return cnt;
|
---|
2489 | }
|
---|
2490 |
|
---|
2491 | int
|
---|
2492 | Perl_Process_Messages(int force, I32 *cntp)
|
---|
2493 | {
|
---|
2494 | QMSG msg;
|
---|
2495 |
|
---|
2496 | if (Perl_hmq_servers > 0 && !force)
|
---|
2497 | return 0;
|
---|
2498 | if (Perl_hmq_refcnt <= 0)
|
---|
2499 | Perl_croak_nocontext("No message queue");
|
---|
2500 | while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
|
---|
2501 | if (cntp)
|
---|
2502 | (*cntp)++;
|
---|
2503 | (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
|
---|
2504 | if (msg.msg == WM_DESTROY)
|
---|
2505 | return -1;
|
---|
2506 | if (msg.msg == WM_CREATE)
|
---|
2507 | return +1;
|
---|
2508 | }
|
---|
2509 | Perl_croak_nocontext("QUITing...");
|
---|
2510 | }
|
---|
2511 |
|
---|
2512 | void
|
---|
2513 | Perl_Deregister_MQ(int serve)
|
---|
2514 | {
|
---|
2515 | if (serve & REGISTERMQ_WILL_SERVE)
|
---|
2516 | Perl_hmq_servers--;
|
---|
2517 |
|
---|
2518 | if (--Perl_hmq_refcnt <= 0) {
|
---|
2519 | unsigned fpflag = _control87(0,0);
|
---|
2520 |
|
---|
2521 | init_PMWIN_entries(); /* To be extra safe */
|
---|
2522 | (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
|
---|
2523 | Perl_hmq = 0;
|
---|
2524 | /* We may have (un)loaded some modules */
|
---|
2525 | _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
|
---|
2526 | } else if ((serve & REGISTERMQ_WILL_SERVE) && Perl_hmq_servers <= 0)
|
---|
2527 | (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1); /* Last server exited */
|
---|
2528 | if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH) && (--Perl_morph_refcnt <= 0)) {
|
---|
2529 | /* Try morphing back from a PM application. */
|
---|
2530 | PPIB pib;
|
---|
2531 | PTIB tib;
|
---|
2532 |
|
---|
2533 | DosGetInfoBlocks(&tib, &pib);
|
---|
2534 | if (pib->pib_ultype == 3) /* 3 is PM */
|
---|
2535 | pib->pib_ultype = Perl_os2_initial_mode;
|
---|
2536 | else
|
---|
2537 | Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
|
---|
2538 | pib->pib_ultype);
|
---|
2539 | }
|
---|
2540 | }
|
---|
2541 |
|
---|
2542 | #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
|
---|
2543 | && ((path)[2] == '/' || (path)[2] == '\\'))
|
---|
2544 | #define sys_is_rooted _fnisabs
|
---|
2545 | #define sys_is_relative _fnisrel
|
---|
2546 | #define current_drive _getdrive
|
---|
2547 |
|
---|
2548 | #undef chdir /* Was _chdir2. */
|
---|
2549 | #define sys_chdir(p) (chdir(p) == 0)
|
---|
2550 | #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
|
---|
2551 |
|
---|
2552 | XS(XS_OS2_Error)
|
---|
2553 | {
|
---|
2554 | dXSARGS;
|
---|
2555 | if (items != 2)
|
---|
2556 | Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
|
---|
2557 | {
|
---|
2558 | int arg1 = SvIV(ST(0));
|
---|
2559 | int arg2 = SvIV(ST(1));
|
---|
2560 | int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
|
---|
2561 | | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
|
---|
2562 | int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
|
---|
2563 | unsigned long rc;
|
---|
2564 |
|
---|
2565 | if (CheckOSError(DosError(a)))
|
---|
2566 | Perl_croak_nocontext("DosError(%d) failed: %s", a, os2error(Perl_rc));
|
---|
2567 | ST(0) = sv_newmortal();
|
---|
2568 | if (DOS_harderr_state >= 0)
|
---|
2569 | sv_setiv(ST(0), DOS_harderr_state);
|
---|
2570 | DOS_harderr_state = RETVAL;
|
---|
2571 | }
|
---|
2572 | XSRETURN(1);
|
---|
2573 | }
|
---|
2574 |
|
---|
2575 | XS(XS_OS2_Errors2Drive)
|
---|
2576 | {
|
---|
2577 | dXSARGS;
|
---|
2578 | if (items != 1)
|
---|
2579 | Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
|
---|
2580 | {
|
---|
2581 | STRLEN n_a;
|
---|
2582 | SV *sv = ST(0);
|
---|
2583 | int suppress = SvOK(sv);
|
---|
2584 | char *s = suppress ? SvPV(sv, n_a) : NULL;
|
---|
2585 | char drive = (s ? *s : 0);
|
---|
2586 | unsigned long rc;
|
---|
2587 |
|
---|
2588 | if (suppress && !isALPHA(drive))
|
---|
2589 | Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
|
---|
2590 | if (CheckOSError(DosSuppressPopUps((suppress
|
---|
2591 | ? SPU_ENABLESUPPRESSION
|
---|
2592 | : SPU_DISABLESUPPRESSION),
|
---|
2593 | drive)))
|
---|
2594 | Perl_croak_nocontext("DosSuppressPopUps(%c) failed: %s", drive,
|
---|
2595 | os2error(Perl_rc));
|
---|
2596 | ST(0) = sv_newmortal();
|
---|
2597 | if (DOS_suppression_state > 0)
|
---|
2598 | sv_setpvn(ST(0), &DOS_suppression_state, 1);
|
---|
2599 | else if (DOS_suppression_state == 0)
|
---|
2600 | sv_setpvn(ST(0), "", 0);
|
---|
2601 | DOS_suppression_state = drive;
|
---|
2602 | }
|
---|
2603 | XSRETURN(1);
|
---|
2604 | }
|
---|
2605 |
|
---|
2606 | int
|
---|
2607 | async_mssleep(ULONG ms, int switch_priority) {
|
---|
2608 | /* This is similar to DosSleep(), but has 8ms granularity in time-critical
|
---|
2609 | threads even on Warp3. */
|
---|
2610 | HEV hevEvent1 = 0; /* Event semaphore handle */
|
---|
2611 | HTIMER htimerEvent1 = 0; /* Timer handle */
|
---|
2612 | APIRET rc = NO_ERROR; /* Return code */
|
---|
2613 | int ret = 1;
|
---|
2614 | ULONG priority = 0, nesting; /* Shut down the warnings */
|
---|
2615 | PPIB pib;
|
---|
2616 | PTIB tib;
|
---|
2617 | char *e = NULL;
|
---|
2618 | APIRET badrc;
|
---|
2619 |
|
---|
2620 | if (!(_emx_env & 0x200)) /* DOS */
|
---|
2621 | return !_sleep2(ms);
|
---|
2622 |
|
---|
2623 | os2cp_croak(DosCreateEventSem(NULL, /* Unnamed */
|
---|
2624 | &hevEvent1, /* Handle of semaphore returned */
|
---|
2625 | DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
|
---|
2626 | FALSE), /* Semaphore is in RESET state */
|
---|
2627 | "DosCreateEventSem");
|
---|
2628 |
|
---|
2629 | if (ms >= switch_priority)
|
---|
2630 | switch_priority = 0;
|
---|
2631 | if (switch_priority) {
|
---|
2632 | if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
|
---|
2633 | switch_priority = 0;
|
---|
2634 | else {
|
---|
2635 | /* In Warp3, to switch scheduling to 8ms step, one needs to do
|
---|
2636 | DosAsyncTimer() in time-critical thread. On laters versions,
|
---|
2637 | more and more cases of wait-for-something are covered.
|
---|
2638 |
|
---|
2639 | It turns out that on Warp3fp42 it is the priority at the time
|
---|
2640 | of DosAsyncTimer() which matters. Let's hope that this works
|
---|
2641 | with later versions too... XXXX
|
---|
2642 | */
|
---|
2643 | priority = (tib->tib_ptib2->tib2_ulpri);
|
---|
2644 | if ((priority & 0xFF00) == 0x0300) /* already time-critical */
|
---|
2645 | switch_priority = 0;
|
---|
2646 | /* Make us time-critical. Just modifying TIB is not enough... */
|
---|
2647 | /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/
|
---|
2648 | /* We do not want to run at high priority if a signal causes us
|
---|
2649 | to longjmp() out of this section... */
|
---|
2650 | if (DosEnterMustComplete(&nesting))
|
---|
2651 | switch_priority = 0;
|
---|
2652 | else
|
---|
2653 | DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
|
---|
2654 | }
|
---|
2655 | }
|
---|
2656 |
|
---|
2657 | if ((badrc = DosAsyncTimer(ms,
|
---|
2658 | (HSEM) hevEvent1, /* Semaphore to post */
|
---|
2659 | &htimerEvent1))) /* Timer handler (returned) */
|
---|
2660 | e = "DosAsyncTimer";
|
---|
2661 |
|
---|
2662 | if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300) {
|
---|
2663 | /* Nobody switched priority while we slept... Ignore errors... */
|
---|
2664 | /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */
|
---|
2665 | if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0)))
|
---|
2666 | rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0);
|
---|
2667 | }
|
---|
2668 | if (switch_priority)
|
---|
2669 | rc = DosExitMustComplete(&nesting); /* Ignore errors */
|
---|
2670 |
|
---|
2671 | /* The actual blocking call is made with "normal" priority. This way we
|
---|
2672 | should not bother with DosSleep(0) etc. to compensate for us interrupting
|
---|
2673 | higher-priority threads. The goal is to prohibit the system spending too
|
---|
2674 | much time halt()ing, not to run us "no matter what". */
|
---|
2675 | if (!e) /* Wait for AsyncTimer event */
|
---|
2676 | badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT);
|
---|
2677 |
|
---|
2678 | if (e) ; /* Do nothing */
|
---|
2679 | else if (badrc == ERROR_INTERRUPT)
|
---|
2680 | ret = 0;
|
---|
2681 | else if (badrc)
|
---|
2682 | e = "DosWaitEventSem";
|
---|
2683 | if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
|
---|
2684 | e = "DosCloseEventSem";
|
---|
2685 | badrc = rc;
|
---|
2686 | }
|
---|
2687 | if (e)
|
---|
2688 | os2cp_croak(badrc, e);
|
---|
2689 | return ret;
|
---|
2690 | }
|
---|
2691 |
|
---|
2692 | XS(XS_OS2_ms_sleep) /* for testing only... */
|
---|
2693 | {
|
---|
2694 | dXSARGS;
|
---|
2695 | ULONG ms, lim;
|
---|
2696 |
|
---|
2697 | if (items > 2 || items < 1)
|
---|
2698 | Perl_croak_nocontext("Usage: OS2::ms_sleep(wait_ms [, high_priority_limit])");
|
---|
2699 | ms = SvUV(ST(0));
|
---|
2700 | lim = items > 1 ? SvUV(ST(1)) : ms + 1;
|
---|
2701 | async_mssleep(ms, lim);
|
---|
2702 | XSRETURN_EMPTY;
|
---|
2703 | }
|
---|
2704 |
|
---|
2705 | ULONG (*pDosTmrQueryFreq) (PULONG);
|
---|
2706 | ULONG (*pDosTmrQueryTime) (unsigned long long *);
|
---|
2707 |
|
---|
2708 | XS(XS_OS2_Timer)
|
---|
2709 | {
|
---|
2710 | dXSARGS;
|
---|
2711 | static ULONG freq;
|
---|
2712 | unsigned long long count;
|
---|
2713 | ULONG rc;
|
---|
2714 |
|
---|
2715 | if (items != 0)
|
---|
2716 | Perl_croak_nocontext("Usage: OS2::Timer()");
|
---|
2717 | if (!freq) {
|
---|
2718 | *(PFN*)&pDosTmrQueryFreq = loadByOrdinal(ORD_DosTmrQueryFreq, 0);
|
---|
2719 | *(PFN*)&pDosTmrQueryTime = loadByOrdinal(ORD_DosTmrQueryTime, 0);
|
---|
2720 | MUTEX_LOCK(&perlos2_state_mutex);
|
---|
2721 | if (!freq)
|
---|
2722 | if (CheckOSError(pDosTmrQueryFreq(&freq)))
|
---|
2723 | croak_with_os2error("DosTmrQueryFreq");
|
---|
2724 | MUTEX_UNLOCK(&perlos2_state_mutex);
|
---|
2725 | }
|
---|
2726 | if (CheckOSError(pDosTmrQueryTime(&count)))
|
---|
2727 | croak_with_os2error("DosTmrQueryTime");
|
---|
2728 | {
|
---|
2729 | dXSTARG;
|
---|
2730 |
|
---|
2731 | XSprePUSH; PUSHn(((NV)count)/freq);
|
---|
2732 | }
|
---|
2733 | XSRETURN(1);
|
---|
2734 | }
|
---|
2735 |
|
---|
2736 | XS(XS_OS2_msCounter)
|
---|
2737 | {
|
---|
2738 | dXSARGS;
|
---|
2739 |
|
---|
2740 | if (items != 0)
|
---|
2741 | Perl_croak_nocontext("Usage: OS2::msCounter()");
|
---|
2742 | {
|
---|
2743 | dXSTARG;
|
---|
2744 |
|
---|
2745 | XSprePUSH; PUSHu(msCounter());
|
---|
2746 | }
|
---|
2747 | XSRETURN(1);
|
---|
2748 | }
|
---|
2749 |
|
---|
2750 | XS(XS_OS2__InfoTable)
|
---|
2751 | {
|
---|
2752 | dXSARGS;
|
---|
2753 | int is_local = 0;
|
---|
2754 |
|
---|
2755 | if (items > 1)
|
---|
2756 | Perl_croak_nocontext("Usage: OS2::_infoTable([isLocal])");
|
---|
2757 | if (items == 1)
|
---|
2758 | is_local = (int)SvIV(ST(0));
|
---|
2759 | {
|
---|
2760 | dXSTARG;
|
---|
2761 |
|
---|
2762 | XSprePUSH; PUSHu(InfoTable(is_local));
|
---|
2763 | }
|
---|
2764 | XSRETURN(1);
|
---|
2765 | }
|
---|
2766 |
|
---|
2767 | static const char * const dc_fields[] = {
|
---|
2768 | "FAMILY",
|
---|
2769 | "IO_CAPS",
|
---|
2770 | "TECHNOLOGY",
|
---|
2771 | "DRIVER_VERSION",
|
---|
2772 | "WIDTH",
|
---|
2773 | "HEIGHT",
|
---|
2774 | "WIDTH_IN_CHARS",
|
---|
2775 | "HEIGHT_IN_CHARS",
|
---|
2776 | "HORIZONTAL_RESOLUTION",
|
---|
2777 | "VERTICAL_RESOLUTION",
|
---|
2778 | "CHAR_WIDTH",
|
---|
2779 | "CHAR_HEIGHT",
|
---|
2780 | "SMALL_CHAR_WIDTH",
|
---|
2781 | "SMALL_CHAR_HEIGHT",
|
---|
2782 | "COLORS",
|
---|
2783 | "COLOR_PLANES",
|
---|
2784 | "COLOR_BITCOUNT",
|
---|
2785 | "COLOR_TABLE_SUPPORT",
|
---|
2786 | "MOUSE_BUTTONS",
|
---|
2787 | "FOREGROUND_MIX_SUPPORT",
|
---|
2788 | "BACKGROUND_MIX_SUPPORT",
|
---|
2789 | "VIO_LOADABLE_FONTS",
|
---|
2790 | "WINDOW_BYTE_ALIGNMENT",
|
---|
2791 | "BITMAP_FORMATS",
|
---|
2792 | "RASTER_CAPS",
|
---|
2793 | "MARKER_HEIGHT",
|
---|
2794 | "MARKER_WIDTH",
|
---|
2795 | "DEVICE_FONTS",
|
---|
2796 | "GRAPHICS_SUBSET",
|
---|
2797 | "GRAPHICS_VERSION",
|
---|
2798 | "GRAPHICS_VECTOR_SUBSET",
|
---|
2799 | "DEVICE_WINDOWING",
|
---|
2800 | "ADDITIONAL_GRAPHICS",
|
---|
2801 | "PHYS_COLORS",
|
---|
2802 | "COLOR_INDEX",
|
---|
2803 | "GRAPHICS_CHAR_WIDTH",
|
---|
2804 | "GRAPHICS_CHAR_HEIGHT",
|
---|
2805 | "HORIZONTAL_FONT_RES",
|
---|
2806 | "VERTICAL_FONT_RES",
|
---|
2807 | "DEVICE_FONT_SIM",
|
---|
2808 | "LINEWIDTH_THICK",
|
---|
2809 | "DEVICE_POLYSET_POINTS",
|
---|
2810 | };
|
---|
2811 |
|
---|
2812 | enum {
|
---|
2813 | DevCap_dc, DevCap_hwnd
|
---|
2814 | };
|
---|
2815 |
|
---|
2816 | HDC (*pWinOpenWindowDC) (HWND hwnd);
|
---|
2817 | HMF (*pDevCloseDC) (HDC hdc);
|
---|
2818 | HDC (*pDevOpenDC) (HAB hab, LONG lType, PCSZ pszToken, LONG lCount,
|
---|
2819 | PDEVOPENDATA pdopData, HDC hdcComp);
|
---|
2820 | BOOL (*pDevQueryCaps) (HDC hdc, LONG lStart, LONG lCount, PLONG alArray);
|
---|
2821 |
|
---|
2822 |
|
---|
2823 | XS(XS_OS2_DevCap)
|
---|
2824 | {
|
---|
2825 | dXSARGS;
|
---|
2826 | if (items > 2)
|
---|
2827 | Perl_croak_nocontext("Usage: OS2::DevCap()");
|
---|
2828 | {
|
---|
2829 | /* Device Capabilities Data Buffer (10 extra w.r.t. Warp 4.5) */
|
---|
2830 | LONG si[CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1];
|
---|
2831 | int i = 0, j = 0, how = DevCap_dc;
|
---|
2832 | HDC hScreenDC;
|
---|
2833 | DEVOPENSTRUC doStruc= {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
|
---|
2834 | ULONG rc1 = NO_ERROR;
|
---|
2835 | HWND hwnd;
|
---|
2836 | static volatile int devcap_loaded;
|
---|
2837 |
|
---|
2838 | if (!devcap_loaded) {
|
---|
2839 | *(PFN*)&pWinOpenWindowDC = loadByOrdinal(ORD_WinOpenWindowDC, 0);
|
---|
2840 | *(PFN*)&pDevOpenDC = loadByOrdinal(ORD_DevOpenDC, 0);
|
---|
2841 | *(PFN*)&pDevCloseDC = loadByOrdinal(ORD_DevCloseDC, 0);
|
---|
2842 | *(PFN*)&pDevQueryCaps = loadByOrdinal(ORD_DevQueryCaps, 0);
|
---|
2843 | devcap_loaded = 1;
|
---|
2844 | }
|
---|
2845 |
|
---|
2846 | if (items >= 2)
|
---|
2847 | how = SvIV(ST(1));
|
---|
2848 | if (!items) { /* Get device contents from PM */
|
---|
2849 | hScreenDC = pDevOpenDC(perl_hab_GET(), OD_MEMORY, (PSZ)"*", 0,
|
---|
2850 | (PDEVOPENDATA)&doStruc, NULLHANDLE);
|
---|
2851 | if (CheckWinError(hScreenDC))
|
---|
2852 | croak_with_os2error("DevOpenDC() failed");
|
---|
2853 | } else if (how == DevCap_dc)
|
---|
2854 | hScreenDC = (HDC)SvIV(ST(0));
|
---|
2855 | else { /* DevCap_hwnd */
|
---|
2856 | if (!Perl_hmq)
|
---|
2857 | Perl_croak(aTHX_ "Getting a window's device context without a message queue would lock PM");
|
---|
2858 | hwnd = (HWND)SvIV(ST(0));
|
---|
2859 | hScreenDC = pWinOpenWindowDC(hwnd); /* No need to DevCloseDC() */
|
---|
2860 | if (CheckWinError(hScreenDC))
|
---|
2861 | croak_with_os2error("WinOpenWindowDC() failed");
|
---|
2862 | }
|
---|
2863 | if (CheckWinError(pDevQueryCaps(hScreenDC,
|
---|
2864 | CAPS_FAMILY, /* W3 documented caps */
|
---|
2865 | CAPS_DEVICE_POLYSET_POINTS
|
---|
2866 | - CAPS_FAMILY + 1,
|
---|
2867 | si)))
|
---|
2868 | rc1 = Perl_rc;
|
---|
2869 | if (!items && CheckWinError(pDevCloseDC(hScreenDC)))
|
---|
2870 | Perl_warn_nocontext("DevCloseDC() failed: %s", os2error(Perl_rc));
|
---|
2871 | if (rc1)
|
---|
2872 | Perl_rc = rc1, croak_with_os2error("DevQueryCaps() failed");
|
---|
2873 | EXTEND(SP,2*(CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1));
|
---|
2874 | while (i < CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1) {
|
---|
2875 | ST(j) = sv_newmortal();
|
---|
2876 | sv_setpv(ST(j++), dc_fields[i]);
|
---|
2877 | ST(j) = sv_newmortal();
|
---|
2878 | sv_setiv(ST(j++), si[i]);
|
---|
2879 | i++;
|
---|
2880 | }
|
---|
2881 | }
|
---|
2882 | XSRETURN(2 * (CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1));
|
---|
2883 | }
|
---|
2884 |
|
---|
2885 | LONG (*pWinQuerySysValue) (HWND hwndDesktop, LONG iSysValue);
|
---|
2886 | BOOL (*pWinSetSysValue) (HWND hwndDesktop, LONG iSysValue, LONG lValue);
|
---|
2887 |
|
---|
2888 | const char * const sv_keys[] = {
|
---|
2889 | "SWAPBUTTON",
|
---|
2890 | "DBLCLKTIME",
|
---|
2891 | "CXDBLCLK",
|
---|
2892 | "CYDBLCLK",
|
---|
2893 | "CXSIZEBORDER",
|
---|
2894 | "CYSIZEBORDER",
|
---|
2895 | "ALARM",
|
---|
2896 | "7",
|
---|
2897 | "8",
|
---|
2898 | "CURSORRATE",
|
---|
2899 | "FIRSTSCROLLRATE",
|
---|
2900 | "SCROLLRATE",
|
---|
2901 | "NUMBEREDLISTS",
|
---|
2902 | "WARNINGFREQ",
|
---|
2903 | "NOTEFREQ",
|
---|
2904 | "ERRORFREQ",
|
---|
2905 | "WARNINGDURATION",
|
---|
2906 | "NOTEDURATION",
|
---|
2907 | "ERRORDURATION",
|
---|
2908 | "19",
|
---|
2909 | "CXSCREEN",
|
---|
2910 | "CYSCREEN",
|
---|
2911 | "CXVSCROLL",
|
---|
2912 | "CYHSCROLL",
|
---|
2913 | "CYVSCROLLARROW",
|
---|
2914 | "CXHSCROLLARROW",
|
---|
2915 | "CXBORDER",
|
---|
2916 | "CYBORDER",
|
---|
2917 | "CXDLGFRAME",
|
---|
2918 | "CYDLGFRAME",
|
---|
2919 | "CYTITLEBAR",
|
---|
2920 | "CYVSLIDER",
|
---|
2921 | "CXHSLIDER",
|
---|
2922 | "CXMINMAXBUTTON",
|
---|
2923 | "CYMINMAXBUTTON",
|
---|
2924 | "CYMENU",
|
---|
2925 | "CXFULLSCREEN",
|
---|
2926 | "CYFULLSCREEN",
|
---|
2927 | "CXICON",
|
---|
2928 | "CYICON",
|
---|
2929 | "CXPOINTER",
|
---|
2930 | "CYPOINTER",
|
---|
2931 | "DEBUG",
|
---|
2932 | "CPOINTERBUTTONS",
|
---|
2933 | "POINTERLEVEL",
|
---|
2934 | "CURSORLEVEL",
|
---|
2935 | "TRACKRECTLEVEL",
|
---|
2936 | "CTIMERS",
|
---|
2937 | "MOUSEPRESENT",
|
---|
2938 | "CXALIGN",
|
---|
2939 | "CYALIGN",
|
---|
2940 | "DESKTOPWORKAREAYTOP",
|
---|
2941 | "DESKTOPWORKAREAYBOTTOM",
|
---|
2942 | "DESKTOPWORKAREAXRIGHT",
|
---|
2943 | "DESKTOPWORKAREAXLEFT",
|
---|
2944 | "55",
|
---|
2945 | "NOTRESERVED",
|
---|
2946 | "EXTRAKEYBEEP",
|
---|
2947 | "SETLIGHTS",
|
---|
2948 | "INSERTMODE",
|
---|
2949 | "60",
|
---|
2950 | "61",
|
---|
2951 | "62",
|
---|
2952 | "63",
|
---|
2953 | "MENUROLLDOWNDELAY",
|
---|
2954 | "MENUROLLUPDELAY",
|
---|
2955 | "ALTMNEMONIC",
|
---|
2956 | "TASKLISTMOUSEACCESS",
|
---|
2957 | "CXICONTEXTWIDTH",
|
---|
2958 | "CICONTEXTLINES",
|
---|
2959 | "CHORDTIME",
|
---|
2960 | "CXCHORD",
|
---|
2961 | "CYCHORD",
|
---|
2962 | "CXMOTIONSTART",
|
---|
2963 | "CYMOTIONSTART",
|
---|
2964 | "BEGINDRAG",
|
---|
2965 | "ENDDRAG",
|
---|
2966 | "SINGLESELECT",
|
---|
2967 | "OPEN",
|
---|
2968 | "CONTEXTMENU",
|
---|
2969 | "CONTEXTHELP",
|
---|
2970 | "TEXTEDIT",
|
---|
2971 | "BEGINSELECT",
|
---|
2972 | "ENDSELECT",
|
---|
2973 | "BEGINDRAGKB",
|
---|
2974 | "ENDDRAGKB",
|
---|
2975 | "SELECTKB",
|
---|
2976 | "OPENKB",
|
---|
2977 | "CONTEXTMENUKB",
|
---|
2978 | "CONTEXTHELPKB",
|
---|
2979 | "TEXTEDITKB",
|
---|
2980 | "BEGINSELECTKB",
|
---|
2981 | "ENDSELECTKB",
|
---|
2982 | "ANIMATION",
|
---|
2983 | "ANIMATIONSPEED",
|
---|
2984 | "MONOICONS",
|
---|
2985 | "KBDALTERED",
|
---|
2986 | "PRINTSCREEN", /* 97, the last one on one of the DDK header */
|
---|
2987 | "LOCKSTARTINPUT",
|
---|
2988 | "DYNAMICDRAG",
|
---|
2989 | "100",
|
---|
2990 | "101",
|
---|
2991 | "102",
|
---|
2992 | "103",
|
---|
2993 | "104",
|
---|
2994 | "105",
|
---|
2995 | "106",
|
---|
2996 | "107",
|
---|
2997 | /* "CSYSVALUES",*/
|
---|
2998 | /* In recent DDK the limit is 108 */
|
---|
2999 | };
|
---|
3000 |
|
---|
3001 | XS(XS_OS2_SysValues)
|
---|
3002 | {
|
---|
3003 | dXSARGS;
|
---|
3004 | if (items > 2)
|
---|
3005 | Perl_croak_nocontext("Usage: OS2::SysValues(which = -1, hwndDesktop = HWND_DESKTOP)");
|
---|
3006 | {
|
---|
3007 | int i = 0, j = 0, which = -1;
|
---|
3008 | HWND hwnd = HWND_DESKTOP;
|
---|
3009 | static volatile int sv_loaded;
|
---|
3010 | LONG RETVAL;
|
---|
3011 |
|
---|
3012 | if (!sv_loaded) {
|
---|
3013 | *(PFN*)&pWinQuerySysValue = loadByOrdinal(ORD_WinQuerySysValue, 0);
|
---|
3014 | sv_loaded = 1;
|
---|
3015 | }
|
---|
3016 |
|
---|
3017 | if (items == 2)
|
---|
3018 | hwnd = (HWND)SvIV(ST(1));
|
---|
3019 | if (items >= 1)
|
---|
3020 | which = (int)SvIV(ST(0));
|
---|
3021 | if (which == -1) {
|
---|
3022 | EXTEND(SP,2*C_ARRAY_LENGTH(sv_keys));
|
---|
3023 | while (i < C_ARRAY_LENGTH(sv_keys)) {
|
---|
3024 | ResetWinError();
|
---|
3025 | RETVAL = pWinQuerySysValue(hwnd, i);
|
---|
3026 | if ( !RETVAL
|
---|
3027 | && !(sv_keys[i][0] >= '0' && sv_keys[i][0] <= '9'
|
---|
3028 | && i <= SV_PRINTSCREEN) ) {
|
---|
3029 | FillWinError;
|
---|
3030 | if (Perl_rc) {
|
---|
3031 | if (i > SV_PRINTSCREEN)
|
---|
3032 | break; /* May be not present on older systems */
|
---|
3033 | croak_with_os2error("SysValues():");
|
---|
3034 | }
|
---|
3035 |
|
---|
3036 | }
|
---|
3037 | ST(j) = sv_newmortal();
|
---|
3038 | sv_setpv(ST(j++), sv_keys[i]);
|
---|
3039 | ST(j) = sv_newmortal();
|
---|
3040 | sv_setiv(ST(j++), RETVAL);
|
---|
3041 | i++;
|
---|
3042 | }
|
---|
3043 | XSRETURN(2 * i);
|
---|
3044 | } else {
|
---|
3045 | dXSTARG;
|
---|
3046 |
|
---|
3047 | ResetWinError();
|
---|
3048 | RETVAL = pWinQuerySysValue(hwnd, which);
|
---|
3049 | if (!RETVAL) {
|
---|
3050 | FillWinError;
|
---|
3051 | if (Perl_rc)
|
---|
3052 | croak_with_os2error("SysValues():");
|
---|
3053 | }
|
---|
3054 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
3055 | }
|
---|
3056 | }
|
---|
3057 | }
|
---|
3058 |
|
---|
3059 | XS(XS_OS2_SysValues_set)
|
---|
3060 | {
|
---|
3061 | dXSARGS;
|
---|
3062 | if (items < 2 || items > 3)
|
---|
3063 | Perl_croak_nocontext("Usage: OS2::SysValues_set(which, val, hwndDesktop = HWND_DESKTOP)");
|
---|
3064 | {
|
---|
3065 | int which = (int)SvIV(ST(0));
|
---|
3066 | LONG val = (LONG)SvIV(ST(1));
|
---|
3067 | HWND hwnd = HWND_DESKTOP;
|
---|
3068 | static volatile int svs_loaded;
|
---|
3069 |
|
---|
3070 | if (!svs_loaded) {
|
---|
3071 | *(PFN*)&pWinSetSysValue = loadByOrdinal(ORD_WinSetSysValue, 0);
|
---|
3072 | svs_loaded = 1;
|
---|
3073 | }
|
---|
3074 |
|
---|
3075 | if (items == 3)
|
---|
3076 | hwnd = (HWND)SvIV(ST(2));
|
---|
3077 | if (CheckWinError(pWinSetSysValue(hwnd, which, val)))
|
---|
3078 | croak_with_os2error("SysValues_set()");
|
---|
3079 | }
|
---|
3080 | XSRETURN_EMPTY;
|
---|
3081 | }
|
---|
3082 |
|
---|
3083 | #define QSV_MAX_WARP3 QSV_MAX_COMP_LENGTH
|
---|
3084 |
|
---|
3085 | static const char * const si_fields[] = {
|
---|
3086 | "MAX_PATH_LENGTH",
|
---|
3087 | "MAX_TEXT_SESSIONS",
|
---|
3088 | "MAX_PM_SESSIONS",
|
---|
3089 | "MAX_VDM_SESSIONS",
|
---|
3090 | "BOOT_DRIVE",
|
---|
3091 | "DYN_PRI_VARIATION",
|
---|
3092 | "MAX_WAIT",
|
---|
3093 | "MIN_SLICE",
|
---|
3094 | "MAX_SLICE",
|
---|
3095 | "PAGE_SIZE",
|
---|
3096 | "VERSION_MAJOR",
|
---|
3097 | "VERSION_MINOR",
|
---|
3098 | "VERSION_REVISION",
|
---|
3099 | "MS_COUNT",
|
---|
3100 | "TIME_LOW",
|
---|
3101 | "TIME_HIGH",
|
---|
3102 | "TOTPHYSMEM",
|
---|
3103 | "TOTRESMEM",
|
---|
3104 | "TOTAVAILMEM",
|
---|
3105 | "MAXPRMEM",
|
---|
3106 | "MAXSHMEM",
|
---|
3107 | "TIMER_INTERVAL",
|
---|
3108 | "MAX_COMP_LENGTH",
|
---|
3109 | "FOREGROUND_FS_SESSION",
|
---|
3110 | "FOREGROUND_PROCESS", /* Warp 3 toolkit defines up to this */
|
---|
3111 | "NUMPROCESSORS",
|
---|
3112 | "MAXHPRMEM",
|
---|
3113 | "MAXHSHMEM",
|
---|
3114 | "MAXPROCESSES",
|
---|
3115 | "VIRTUALADDRESSLIMIT",
|
---|
3116 | "INT10ENABLED", /* From $TOOLKIT-ddk\DDK\video\rel\os2c\include\base\os2\bsedos.h */
|
---|
3117 | };
|
---|
3118 |
|
---|
3119 | XS(XS_OS2_SysInfo)
|
---|
3120 | {
|
---|
3121 | dXSARGS;
|
---|
3122 | if (items != 0)
|
---|
3123 | Perl_croak_nocontext("Usage: OS2::SysInfo()");
|
---|
3124 | {
|
---|
3125 | /* System Information Data Buffer (10 extra w.r.t. Warp 4.5) */
|
---|
3126 | ULONG si[C_ARRAY_LENGTH(si_fields) + 10];
|
---|
3127 | APIRET rc = NO_ERROR; /* Return code */
|
---|
3128 | int i = 0, j = 0, last = QSV_MAX_WARP3;
|
---|
3129 |
|
---|
3130 | if (CheckOSError(DosQuerySysInfo(1L, /* Request documented system */
|
---|
3131 | last, /* info for Warp 3 */
|
---|
3132 | (PVOID)si,
|
---|
3133 | sizeof(si))))
|
---|
3134 | croak_with_os2error("DosQuerySysInfo() failed");
|
---|
3135 | while (last++ <= C_ARRAY_LENGTH(si)) {
|
---|
3136 | if (CheckOSError(DosQuerySysInfo(last, last, /* One entry only */
|
---|
3137 | (PVOID)(si+last-1),
|
---|
3138 | sizeof(*si)))) {
|
---|
3139 | if (Perl_rc != ERROR_INVALID_PARAMETER)
|
---|
3140 | croak_with_os2error("DosQuerySysInfo() failed");
|
---|
3141 | break;
|
---|
3142 | }
|
---|
3143 | }
|
---|
3144 | last--;
|
---|
3145 | EXTEND(SP,2*last);
|
---|
3146 | while (i < last) {
|
---|
3147 | ST(j) = sv_newmortal();
|
---|
3148 | sv_setpv(ST(j++), si_fields[i]);
|
---|
3149 | ST(j) = sv_newmortal();
|
---|
3150 | sv_setiv(ST(j++), si[i]);
|
---|
3151 | i++;
|
---|
3152 | }
|
---|
3153 | XSRETURN(2 * last);
|
---|
3154 | }
|
---|
3155 | }
|
---|
3156 |
|
---|
3157 | XS(XS_OS2_SysInfoFor)
|
---|
3158 | {
|
---|
3159 | dXSARGS;
|
---|
3160 | int count = (items == 2 ? (int)SvIV(ST(1)) : 1);
|
---|
3161 |
|
---|
3162 | if (items < 1 || items > 2)
|
---|
3163 | Perl_croak_nocontext("Usage: OS2::SysInfoFor(id[,count])");
|
---|
3164 | {
|
---|
3165 | /* System Information Data Buffer (10 extra w.r.t. Warp 4.5) */
|
---|
3166 | ULONG si[C_ARRAY_LENGTH(si_fields) + 10];
|
---|
3167 | APIRET rc = NO_ERROR; /* Return code */
|
---|
3168 | int i = 0;
|
---|
3169 | int start = (int)SvIV(ST(0));
|
---|
3170 |
|
---|
3171 | if (count > C_ARRAY_LENGTH(si) || count <= 0)
|
---|
3172 | Perl_croak(aTHX_ "unexpected count %d for OS2::SysInfoFor()", count);
|
---|
3173 | if (CheckOSError(DosQuerySysInfo(start,
|
---|
3174 | start + count - 1,
|
---|
3175 | (PVOID)si,
|
---|
3176 | sizeof(si))))
|
---|
3177 | croak_with_os2error("DosQuerySysInfo() failed");
|
---|
3178 | EXTEND(SP,count);
|
---|
3179 | while (i < count) {
|
---|
3180 | ST(i) = sv_newmortal();
|
---|
3181 | sv_setiv(ST(i), si[i]);
|
---|
3182 | i++;
|
---|
3183 | }
|
---|
3184 | }
|
---|
3185 | XSRETURN(count);
|
---|
3186 | }
|
---|
3187 |
|
---|
3188 | XS(XS_OS2_BootDrive)
|
---|
3189 | {
|
---|
3190 | dXSARGS;
|
---|
3191 | if (items != 0)
|
---|
3192 | Perl_croak_nocontext("Usage: OS2::BootDrive()");
|
---|
3193 | {
|
---|
3194 | ULONG si[1] = {0}; /* System Information Data Buffer */
|
---|
3195 | APIRET rc = NO_ERROR; /* Return code */
|
---|
3196 | char c;
|
---|
3197 | dXSTARG;
|
---|
3198 |
|
---|
3199 | if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
|
---|
3200 | (PVOID)si, sizeof(si))))
|
---|
3201 | croak_with_os2error("DosQuerySysInfo() failed");
|
---|
3202 | c = 'a' - 1 + si[0];
|
---|
3203 | sv_setpvn(TARG, &c, 1);
|
---|
3204 | XSprePUSH; PUSHTARG;
|
---|
3205 | }
|
---|
3206 | XSRETURN(1);
|
---|
3207 | }
|
---|
3208 |
|
---|
3209 | XS(XS_OS2_Beep)
|
---|
3210 | {
|
---|
3211 | dXSARGS;
|
---|
3212 | if (items > 2) /* Defaults as for WinAlarm(ERROR) */
|
---|
3213 | Perl_croak_nocontext("Usage: OS2::Beep(freq = 440, ms = 100)");
|
---|
3214 | {
|
---|
3215 | ULONG freq = (items > 0 ? (ULONG)SvUV(ST(0)) : 440);
|
---|
3216 | ULONG ms = (items > 1 ? (ULONG)SvUV(ST(1)) : 100);
|
---|
3217 | ULONG rc;
|
---|
3218 |
|
---|
3219 | if (CheckOSError(DosBeep(freq, ms)))
|
---|
3220 | croak_with_os2error("SysValues_set()");
|
---|
3221 | }
|
---|
3222 | XSRETURN_EMPTY;
|
---|
3223 | }
|
---|
3224 |
|
---|
3225 |
|
---|
3226 |
|
---|
3227 | XS(XS_OS2_MorphPM)
|
---|
3228 | {
|
---|
3229 | dXSARGS;
|
---|
3230 | if (items != 1)
|
---|
3231 | Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
|
---|
3232 | {
|
---|
3233 | bool serve = SvOK(ST(0));
|
---|
3234 | unsigned long pmq = perl_hmq_GET(serve);
|
---|
3235 | dXSTARG;
|
---|
3236 |
|
---|
3237 | XSprePUSH; PUSHi((IV)pmq);
|
---|
3238 | }
|
---|
3239 | XSRETURN(1);
|
---|
3240 | }
|
---|
3241 |
|
---|
3242 | XS(XS_OS2_UnMorphPM)
|
---|
3243 | {
|
---|
3244 | dXSARGS;
|
---|
3245 | if (items != 1)
|
---|
3246 | Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
|
---|
3247 | {
|
---|
3248 | bool serve = SvOK(ST(0));
|
---|
3249 |
|
---|
3250 | perl_hmq_UNSET(serve);
|
---|
3251 | }
|
---|
3252 | XSRETURN(0);
|
---|
3253 | }
|
---|
3254 |
|
---|
3255 | XS(XS_OS2_Serve_Messages)
|
---|
3256 | {
|
---|
3257 | dXSARGS;
|
---|
3258 | if (items != 1)
|
---|
3259 | Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
|
---|
3260 | {
|
---|
3261 | bool force = SvOK(ST(0));
|
---|
3262 | unsigned long cnt = Perl_Serve_Messages(force);
|
---|
3263 | dXSTARG;
|
---|
3264 |
|
---|
3265 | XSprePUSH; PUSHi((IV)cnt);
|
---|
3266 | }
|
---|
3267 | XSRETURN(1);
|
---|
3268 | }
|
---|
3269 |
|
---|
3270 | XS(XS_OS2_Process_Messages)
|
---|
3271 | {
|
---|
3272 | dXSARGS;
|
---|
3273 | if (items < 1 || items > 2)
|
---|
3274 | Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
|
---|
3275 | {
|
---|
3276 | bool force = SvOK(ST(0));
|
---|
3277 | unsigned long cnt;
|
---|
3278 | dXSTARG;
|
---|
3279 |
|
---|
3280 | if (items == 2) {
|
---|
3281 | I32 cntr;
|
---|
3282 | SV *sv = ST(1);
|
---|
3283 |
|
---|
3284 | (void)SvIV(sv); /* Force SvIVX */
|
---|
3285 | if (!SvIOK(sv))
|
---|
3286 | Perl_croak_nocontext("Can't upgrade count to IV");
|
---|
3287 | cntr = SvIVX(sv);
|
---|
3288 | cnt = Perl_Process_Messages(force, &cntr);
|
---|
3289 | SvIVX(sv) = cntr;
|
---|
3290 | } else {
|
---|
3291 | cnt = Perl_Process_Messages(force, NULL);
|
---|
3292 | }
|
---|
3293 | XSprePUSH; PUSHi((IV)cnt);
|
---|
3294 | }
|
---|
3295 | XSRETURN(1);
|
---|
3296 | }
|
---|
3297 |
|
---|
3298 | XS(XS_Cwd_current_drive)
|
---|
3299 | {
|
---|
3300 | dXSARGS;
|
---|
3301 | if (items != 0)
|
---|
3302 | Perl_croak_nocontext("Usage: Cwd::current_drive()");
|
---|
3303 | {
|
---|
3304 | char RETVAL;
|
---|
3305 | dXSTARG;
|
---|
3306 |
|
---|
3307 | RETVAL = current_drive();
|
---|
3308 | sv_setpvn(TARG, (char *)&RETVAL, 1);
|
---|
3309 | XSprePUSH; PUSHTARG;
|
---|
3310 | }
|
---|
3311 | XSRETURN(1);
|
---|
3312 | }
|
---|
3313 |
|
---|
3314 | XS(XS_Cwd_sys_chdir)
|
---|
3315 | {
|
---|
3316 | dXSARGS;
|
---|
3317 | if (items != 1)
|
---|
3318 | Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
|
---|
3319 | {
|
---|
3320 | STRLEN n_a;
|
---|
3321 | char * path = (char *)SvPV(ST(0),n_a);
|
---|
3322 | bool RETVAL;
|
---|
3323 |
|
---|
3324 | RETVAL = sys_chdir(path);
|
---|
3325 | ST(0) = boolSV(RETVAL);
|
---|
3326 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3327 | }
|
---|
3328 | XSRETURN(1);
|
---|
3329 | }
|
---|
3330 |
|
---|
3331 | XS(XS_Cwd_change_drive)
|
---|
3332 | {
|
---|
3333 | dXSARGS;
|
---|
3334 | if (items != 1)
|
---|
3335 | Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
|
---|
3336 | {
|
---|
3337 | STRLEN n_a;
|
---|
3338 | char d = (char)*SvPV(ST(0),n_a);
|
---|
3339 | bool RETVAL;
|
---|
3340 |
|
---|
3341 | RETVAL = change_drive(d);
|
---|
3342 | ST(0) = boolSV(RETVAL);
|
---|
3343 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3344 | }
|
---|
3345 | XSRETURN(1);
|
---|
3346 | }
|
---|
3347 |
|
---|
3348 | XS(XS_Cwd_sys_is_absolute)
|
---|
3349 | {
|
---|
3350 | dXSARGS;
|
---|
3351 | if (items != 1)
|
---|
3352 | Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
|
---|
3353 | {
|
---|
3354 | STRLEN n_a;
|
---|
3355 | char * path = (char *)SvPV(ST(0),n_a);
|
---|
3356 | bool RETVAL;
|
---|
3357 |
|
---|
3358 | RETVAL = sys_is_absolute(path);
|
---|
3359 | ST(0) = boolSV(RETVAL);
|
---|
3360 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3361 | }
|
---|
3362 | XSRETURN(1);
|
---|
3363 | }
|
---|
3364 |
|
---|
3365 | XS(XS_Cwd_sys_is_rooted)
|
---|
3366 | {
|
---|
3367 | dXSARGS;
|
---|
3368 | if (items != 1)
|
---|
3369 | Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
|
---|
3370 | {
|
---|
3371 | STRLEN n_a;
|
---|
3372 | char * path = (char *)SvPV(ST(0),n_a);
|
---|
3373 | bool RETVAL;
|
---|
3374 |
|
---|
3375 | RETVAL = sys_is_rooted(path);
|
---|
3376 | ST(0) = boolSV(RETVAL);
|
---|
3377 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3378 | }
|
---|
3379 | XSRETURN(1);
|
---|
3380 | }
|
---|
3381 |
|
---|
3382 | XS(XS_Cwd_sys_is_relative)
|
---|
3383 | {
|
---|
3384 | dXSARGS;
|
---|
3385 | if (items != 1)
|
---|
3386 | Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
|
---|
3387 | {
|
---|
3388 | STRLEN n_a;
|
---|
3389 | char * path = (char *)SvPV(ST(0),n_a);
|
---|
3390 | bool RETVAL;
|
---|
3391 |
|
---|
3392 | RETVAL = sys_is_relative(path);
|
---|
3393 | ST(0) = boolSV(RETVAL);
|
---|
3394 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3395 | }
|
---|
3396 | XSRETURN(1);
|
---|
3397 | }
|
---|
3398 |
|
---|
3399 | XS(XS_Cwd_sys_cwd)
|
---|
3400 | {
|
---|
3401 | dXSARGS;
|
---|
3402 | if (items != 0)
|
---|
3403 | Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
|
---|
3404 | {
|
---|
3405 | char p[MAXPATHLEN];
|
---|
3406 | char * RETVAL;
|
---|
3407 |
|
---|
3408 | /* Can't use TARG, since tainting behaves differently */
|
---|
3409 | RETVAL = _getcwd2(p, MAXPATHLEN);
|
---|
3410 | ST(0) = sv_newmortal();
|
---|
3411 | sv_setpv(ST(0), RETVAL);
|
---|
3412 | #ifndef INCOMPLETE_TAINTS
|
---|
3413 | SvTAINTED_on(ST(0));
|
---|
3414 | #endif
|
---|
3415 | }
|
---|
3416 | XSRETURN(1);
|
---|
3417 | }
|
---|
3418 |
|
---|
3419 | XS(XS_Cwd_sys_abspath)
|
---|
3420 | {
|
---|
3421 | dXSARGS;
|
---|
3422 | if (items > 2)
|
---|
3423 | Perl_croak_nocontext("Usage: Cwd::sys_abspath(path = '.', dir = NULL)");
|
---|
3424 | {
|
---|
3425 | STRLEN n_a;
|
---|
3426 | char * path = items ? (char *)SvPV(ST(0),n_a) : ".";
|
---|
3427 | char * dir, *s, *t, *e;
|
---|
3428 | char p[MAXPATHLEN];
|
---|
3429 | char * RETVAL;
|
---|
3430 | int l;
|
---|
3431 | SV *sv;
|
---|
3432 |
|
---|
3433 | if (items < 2)
|
---|
3434 | dir = NULL;
|
---|
3435 | else {
|
---|
3436 | dir = (char *)SvPV(ST(1),n_a);
|
---|
3437 | }
|
---|
3438 | if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
|
---|
3439 | path += 2;
|
---|
3440 | }
|
---|
3441 | if (dir == NULL) {
|
---|
3442 | if (_abspath(p, path, MAXPATHLEN) == 0) {
|
---|
3443 | RETVAL = p;
|
---|
3444 | } else {
|
---|
3445 | RETVAL = NULL;
|
---|
3446 | }
|
---|
3447 | } else {
|
---|
3448 | /* Absolute with drive: */
|
---|
3449 | if ( sys_is_absolute(path) ) {
|
---|
3450 | if (_abspath(p, path, MAXPATHLEN) == 0) {
|
---|
3451 | RETVAL = p;
|
---|
3452 | } else {
|
---|
3453 | RETVAL = NULL;
|
---|
3454 | }
|
---|
3455 | } else if (path[0] == '/' || path[0] == '\\') {
|
---|
3456 | /* Rooted, but maybe on different drive. */
|
---|
3457 | if (isALPHA(dir[0]) && dir[1] == ':' ) {
|
---|
3458 | char p1[MAXPATHLEN];
|
---|
3459 |
|
---|
3460 | /* Need to prepend the drive. */
|
---|
3461 | p1[0] = dir[0];
|
---|
3462 | p1[1] = dir[1];
|
---|
3463 | Copy(path, p1 + 2, strlen(path) + 1, char);
|
---|
3464 | RETVAL = p;
|
---|
3465 | if (_abspath(p, p1, MAXPATHLEN) == 0) {
|
---|
3466 | RETVAL = p;
|
---|
3467 | } else {
|
---|
3468 | RETVAL = NULL;
|
---|
3469 | }
|
---|
3470 | } else if (_abspath(p, path, MAXPATHLEN) == 0) {
|
---|
3471 | RETVAL = p;
|
---|
3472 | } else {
|
---|
3473 | RETVAL = NULL;
|
---|
3474 | }
|
---|
3475 | } else {
|
---|
3476 | /* Either path is relative, or starts with a drive letter. */
|
---|
3477 | /* If the path starts with a drive letter, then dir is
|
---|
3478 | relevant only if
|
---|
3479 | a/b) it is absolute/x:relative on the same drive.
|
---|
3480 | c) path is on current drive, and dir is rooted
|
---|
3481 | In all the cases it is safe to drop the drive part
|
---|
3482 | of the path. */
|
---|
3483 | if ( !sys_is_relative(path) ) {
|
---|
3484 | if ( ( ( sys_is_absolute(dir)
|
---|
3485 | || (isALPHA(dir[0]) && dir[1] == ':'
|
---|
3486 | && strnicmp(dir, path,1) == 0))
|
---|
3487 | && strnicmp(dir, path,1) == 0)
|
---|
3488 | || ( !(isALPHA(dir[0]) && dir[1] == ':')
|
---|
3489 | && toupper(path[0]) == current_drive())) {
|
---|
3490 | path += 2;
|
---|
3491 | } else if (_abspath(p, path, MAXPATHLEN) == 0) {
|
---|
3492 | RETVAL = p; goto done;
|
---|
3493 | } else {
|
---|
3494 | RETVAL = NULL; goto done;
|
---|
3495 | }
|
---|
3496 | }
|
---|
3497 | {
|
---|
3498 | /* Need to prepend the absolute path of dir. */
|
---|
3499 | char p1[MAXPATHLEN];
|
---|
3500 |
|
---|
3501 | if (_abspath(p1, dir, MAXPATHLEN) == 0) {
|
---|
3502 | int l = strlen(p1);
|
---|
3503 |
|
---|
3504 | if (p1[ l - 1 ] != '/') {
|
---|
3505 | p1[ l ] = '/';
|
---|
3506 | l++;
|
---|
3507 | }
|
---|
3508 | Copy(path, p1 + l, strlen(path) + 1, char);
|
---|
3509 | if (_abspath(p, p1, MAXPATHLEN) == 0) {
|
---|
3510 | RETVAL = p;
|
---|
3511 | } else {
|
---|
3512 | RETVAL = NULL;
|
---|
3513 | }
|
---|
3514 | } else {
|
---|
3515 | RETVAL = NULL;
|
---|
3516 | }
|
---|
3517 | }
|
---|
3518 | done:
|
---|
3519 | }
|
---|
3520 | }
|
---|
3521 | if (!RETVAL)
|
---|
3522 | XSRETURN_EMPTY;
|
---|
3523 | /* Backslashes are already converted to slashes. */
|
---|
3524 | /* Remove trailing slashes */
|
---|
3525 | l = strlen(RETVAL);
|
---|
3526 | while (l > 0 && RETVAL[l-1] == '/')
|
---|
3527 | l--;
|
---|
3528 | ST(0) = sv_newmortal();
|
---|
3529 | sv_setpvn( sv = (SV*)ST(0), RETVAL, l);
|
---|
3530 | /* Remove duplicate slashes, skipping the first three, which
|
---|
3531 | may be parts of a server-based path */
|
---|
3532 | s = t = 3 + SvPV_force(sv, n_a);
|
---|
3533 | e = SvEND(sv);
|
---|
3534 | /* Do not worry about multibyte chars here, this would contradict the
|
---|
3535 | eventual UTFization, and currently most other places break too... */
|
---|
3536 | while (s < e) {
|
---|
3537 | if (s[0] == t[-1] && s[0] == '/')
|
---|
3538 | s++; /* Skip duplicate / */
|
---|
3539 | else
|
---|
3540 | *t++ = *s++;
|
---|
3541 | }
|
---|
3542 | if (t < e) {
|
---|
3543 | *t = 0;
|
---|
3544 | SvCUR_set(sv, t - SvPVX(sv));
|
---|
3545 | }
|
---|
3546 | #ifndef INCOMPLETE_TAINTS
|
---|
3547 | if (!items)
|
---|
3548 | SvTAINTED_on(ST(0));
|
---|
3549 | #endif
|
---|
3550 | }
|
---|
3551 | XSRETURN(1);
|
---|
3552 | }
|
---|
3553 | typedef APIRET (*PELP)(PSZ path, ULONG type);
|
---|
3554 |
|
---|
3555 | /* Kernels after 2000/09/15 understand this too: */
|
---|
3556 | #ifndef LIBPATHSTRICT
|
---|
3557 | # define LIBPATHSTRICT 3
|
---|
3558 | #endif
|
---|
3559 |
|
---|
3560 | APIRET
|
---|
3561 | ExtLIBPATH(ULONG ord, PSZ path, IV type, int fatal)
|
---|
3562 | {
|
---|
3563 | ULONG what;
|
---|
3564 | PFN f = loadByOrdinal(ord, fatal); /* if fatal: load or die! */
|
---|
3565 |
|
---|
3566 | if (!f) /* Impossible with fatal */
|
---|
3567 | return Perl_rc;
|
---|
3568 | if (type > 0)
|
---|
3569 | what = END_LIBPATH;
|
---|
3570 | else if (type == 0)
|
---|
3571 | what = BEGIN_LIBPATH;
|
---|
3572 | else
|
---|
3573 | what = LIBPATHSTRICT;
|
---|
3574 | return (*(PELP)f)(path, what);
|
---|
3575 | }
|
---|
3576 |
|
---|
3577 | #define extLibpath(to,type, fatal) \
|
---|
3578 | (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type), fatal)) ? NULL : (to) )
|
---|
3579 |
|
---|
3580 | #define extLibpath_set(p,type, fatal) \
|
---|
3581 | (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type), fatal)))
|
---|
3582 |
|
---|
3583 | static void
|
---|
3584 | early_error(char *msg1, char *msg2, char *msg3)
|
---|
3585 | { /* Buffer overflow detected; there is very little we can do... */
|
---|
3586 | ULONG rc;
|
---|
3587 |
|
---|
3588 | DosWrite(2, msg1, strlen(msg1), &rc);
|
---|
3589 | DosWrite(2, msg2, strlen(msg2), &rc);
|
---|
3590 | DosWrite(2, msg3, strlen(msg3), &rc);
|
---|
3591 | DosExit(EXIT_PROCESS, 2);
|
---|
3592 | }
|
---|
3593 |
|
---|
3594 | XS(XS_Cwd_extLibpath)
|
---|
3595 | {
|
---|
3596 | dXSARGS;
|
---|
3597 | if (items < 0 || items > 1)
|
---|
3598 | Perl_croak_nocontext("Usage: OS2::extLibpath(type = 0)");
|
---|
3599 | {
|
---|
3600 | IV type;
|
---|
3601 | char to[1024];
|
---|
3602 | U32 rc;
|
---|
3603 | char * RETVAL;
|
---|
3604 | dXSTARG;
|
---|
3605 | STRLEN l;
|
---|
3606 |
|
---|
3607 | if (items < 1)
|
---|
3608 | type = 0;
|
---|
3609 | else {
|
---|
3610 | type = SvIV(ST(0));
|
---|
3611 | }
|
---|
3612 |
|
---|
3613 | to[0] = 1; to[1] = 0; /* Sometimes no error reported */
|
---|
3614 | RETVAL = extLibpath(to, type, 1); /* Make errors fatal */
|
---|
3615 | if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0)
|
---|
3616 | Perl_croak_nocontext("panic OS2::extLibpath parameter");
|
---|
3617 | l = strlen(to);
|
---|
3618 | if (l >= sizeof(to))
|
---|
3619 | early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `",
|
---|
3620 | to, "'\r\n"); /* Will not return */
|
---|
3621 | sv_setpv(TARG, RETVAL);
|
---|
3622 | XSprePUSH; PUSHTARG;
|
---|
3623 | }
|
---|
3624 | XSRETURN(1);
|
---|
3625 | }
|
---|
3626 |
|
---|
3627 | XS(XS_Cwd_extLibpath_set)
|
---|
3628 | {
|
---|
3629 | dXSARGS;
|
---|
3630 | if (items < 1 || items > 2)
|
---|
3631 | Perl_croak_nocontext("Usage: OS2::extLibpath_set(s, type = 0)");
|
---|
3632 | {
|
---|
3633 | STRLEN n_a;
|
---|
3634 | char * s = (char *)SvPV(ST(0),n_a);
|
---|
3635 | IV type;
|
---|
3636 | U32 rc;
|
---|
3637 | bool RETVAL;
|
---|
3638 |
|
---|
3639 | if (items < 2)
|
---|
3640 | type = 0;
|
---|
3641 | else {
|
---|
3642 | type = SvIV(ST(1));
|
---|
3643 | }
|
---|
3644 |
|
---|
3645 | RETVAL = extLibpath_set(s, type, 1); /* Make errors fatal */
|
---|
3646 | ST(0) = boolSV(RETVAL);
|
---|
3647 | if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
|
---|
3648 | }
|
---|
3649 | XSRETURN(1);
|
---|
3650 | }
|
---|
3651 |
|
---|
3652 | ULONG
|
---|
3653 | fill_extLibpath(int type, char *pre, char *post, int replace, char *msg)
|
---|
3654 | {
|
---|
3655 | char buf[2048], *to = buf, buf1[300], *s;
|
---|
3656 | STRLEN l;
|
---|
3657 | ULONG rc;
|
---|
3658 |
|
---|
3659 | if (!pre && !post)
|
---|
3660 | return 0;
|
---|
3661 | if (pre) {
|
---|
3662 | pre = dir_subst(pre, strlen(pre), buf1, sizeof buf1, dir_subst_pathlike, msg);
|
---|
3663 | if (!pre)
|
---|
3664 | return ERROR_INVALID_PARAMETER;
|
---|
3665 | l = strlen(pre);
|
---|
3666 | if (l >= sizeof(buf)/2)
|
---|
3667 | return ERROR_BUFFER_OVERFLOW;
|
---|
3668 | s = pre - 1;
|
---|
3669 | while (*++s)
|
---|
3670 | if (*s == '/')
|
---|
3671 | *s = '\\'; /* Be extra causious */
|
---|
3672 | memcpy(to, pre, l);
|
---|
3673 | if (!l || to[l-1] != ';')
|
---|
3674 | to[l++] = ';';
|
---|
3675 | to += l;
|
---|
3676 | }
|
---|
3677 |
|
---|
3678 | if (!replace) {
|
---|
3679 | to[0] = 1; to[1] = 0; /* Sometimes no error reported */
|
---|
3680 | rc = ExtLIBPATH(ORD_DosQueryExtLibpath, to, type, 0); /* Do not croak */
|
---|
3681 | if (rc)
|
---|
3682 | return rc;
|
---|
3683 | if (to[0] == 1 && to[1] == 0)
|
---|
3684 | return ERROR_INVALID_PARAMETER;
|
---|
3685 | to += strlen(to);
|
---|
3686 | if (buf + sizeof(buf) - 1 <= to) /* Buffer overflow */
|
---|
3687 | early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `",
|
---|
3688 | buf, "'\r\n"); /* Will not return */
|
---|
3689 | if (to > buf && to[-1] != ';')
|
---|
3690 | *to++ = ';';
|
---|
3691 | }
|
---|
3692 | if (post) {
|
---|
3693 | post = dir_subst(post, strlen(post), buf1, sizeof buf1, dir_subst_pathlike, msg);
|
---|
3694 | if (!post)
|
---|
3695 | return ERROR_INVALID_PARAMETER;
|
---|
3696 | l = strlen(post);
|
---|
3697 | if (l + to - buf >= sizeof(buf) - 1)
|
---|
3698 | return ERROR_BUFFER_OVERFLOW;
|
---|
3699 | s = post - 1;
|
---|
3700 | while (*++s)
|
---|
3701 | if (*s == '/')
|
---|
3702 | *s = '\\'; /* Be extra causious */
|
---|
3703 | memcpy(to, post, l);
|
---|
3704 | if (!l || to[l-1] != ';')
|
---|
3705 | to[l++] = ';';
|
---|
3706 | to += l;
|
---|
3707 | }
|
---|
3708 | *to = 0;
|
---|
3709 | rc = ExtLIBPATH(ORD_DosSetExtLibpath, buf, type, 0); /* Do not croak */
|
---|
3710 | return rc;
|
---|
3711 | }
|
---|
3712 |
|
---|
3713 | /* Input: Address, BufLen
|
---|
3714 | APIRET APIENTRY
|
---|
3715 | DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
|
---|
3716 | ULONG * Offset, ULONG Address);
|
---|
3717 | */
|
---|
3718 |
|
---|
3719 | DeclOSFuncByORD(APIRET, _DosQueryModFromEIP,ORD_DosQueryModFromEIP,
|
---|
3720 | (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
|
---|
3721 | ULONG * Offset, ULONG Address),
|
---|
3722 | (hmod, obj, BufLen, Buf, Offset, Address))
|
---|
3723 |
|
---|
3724 | static SV*
|
---|
3725 | module_name_at(void *pp, enum module_name_how how)
|
---|
3726 | {
|
---|
3727 | dTHX;
|
---|
3728 | char buf[MAXPATHLEN];
|
---|
3729 | char *p = buf;
|
---|
3730 | HMODULE mod;
|
---|
3731 | ULONG obj, offset, rc, addr = (ULONG)pp;
|
---|
3732 |
|
---|
3733 | if (how & mod_name_HMODULE) {
|
---|
3734 | if ((how & ~mod_name_HMODULE) == mod_name_shortname)
|
---|
3735 | Perl_croak(aTHX_ "Can't get short module name from a handle");
|
---|
3736 | mod = (HMODULE)pp;
|
---|
3737 | how &= ~mod_name_HMODULE;
|
---|
3738 | } else if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, addr))
|
---|
3739 | return &PL_sv_undef;
|
---|
3740 | if (how == mod_name_handle)
|
---|
3741 | return newSVuv(mod);
|
---|
3742 | /* Full name... */
|
---|
3743 | if ( how != mod_name_shortname
|
---|
3744 | && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) )
|
---|
3745 | return &PL_sv_undef;
|
---|
3746 | while (*p) {
|
---|
3747 | if (*p == '\\')
|
---|
3748 | *p = '/';
|
---|
3749 | p++;
|
---|
3750 | }
|
---|
3751 | return newSVpv(buf, 0);
|
---|
3752 | }
|
---|
3753 |
|
---|
3754 | static SV*
|
---|
3755 | module_name_of_cv(SV *cv, enum module_name_how how)
|
---|
3756 | {
|
---|
3757 | if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv))) {
|
---|
3758 | dTHX;
|
---|
3759 |
|
---|
3760 | if (how & mod_name_C_function)
|
---|
3761 | return module_name_at((void*)SvIV(cv), how & ~mod_name_C_function);
|
---|
3762 | else if (how & mod_name_HMODULE)
|
---|
3763 | return module_name_at((void*)SvIV(cv), how);
|
---|
3764 | Perl_croak(aTHX_ "Not an XSUB reference");
|
---|
3765 | }
|
---|
3766 | return module_name_at(CvXSUB(SvRV(cv)), how);
|
---|
3767 | }
|
---|
3768 |
|
---|
3769 | XS(XS_OS2_DLLname)
|
---|
3770 | {
|
---|
3771 | dXSARGS;
|
---|
3772 | if (items > 2)
|
---|
3773 | Perl_croak(aTHX_ "Usage: OS2::DLLname( [ how, [\\&xsub] ] )");
|
---|
3774 | {
|
---|
3775 | SV * RETVAL;
|
---|
3776 | int how;
|
---|
3777 |
|
---|
3778 | if (items < 1)
|
---|
3779 | how = mod_name_full;
|
---|
3780 | else {
|
---|
3781 | how = (int)SvIV(ST(0));
|
---|
3782 | }
|
---|
3783 | if (items < 2)
|
---|
3784 | RETVAL = module_name(how);
|
---|
3785 | else
|
---|
3786 | RETVAL = module_name_of_cv(ST(1), how);
|
---|
3787 | ST(0) = RETVAL;
|
---|
3788 | sv_2mortal(ST(0));
|
---|
3789 | }
|
---|
3790 | XSRETURN(1);
|
---|
3791 | }
|
---|
3792 |
|
---|
3793 | DeclOSFuncByORD(INT, _Dos32QueryHeaderInfo, ORD_Dos32QueryHeaderInfo,
|
---|
3794 | (ULONG r1, ULONG r2, PVOID buf, ULONG szbuf, ULONG fnum),
|
---|
3795 | (r1, r2, buf, szbuf, fnum))
|
---|
3796 |
|
---|
3797 | XS(XS_OS2__headerInfo)
|
---|
3798 | {
|
---|
3799 | dXSARGS;
|
---|
3800 | if (items > 4 || items < 2)
|
---|
3801 | Perl_croak(aTHX_ "Usage: OS2::_headerInfo(req,size[,handle,[offset]])");
|
---|
3802 | {
|
---|
3803 | ULONG req = (ULONG)SvIV(ST(0));
|
---|
3804 | STRLEN size = (STRLEN)SvIV(ST(1)), n_a;
|
---|
3805 | ULONG handle = (items >= 3 ? (ULONG)SvIV(ST(2)) : 0);
|
---|
3806 | ULONG offset = (items >= 4 ? (ULONG)SvIV(ST(3)) : 0);
|
---|
3807 |
|
---|
3808 | if (size <= 0)
|
---|
3809 | Perl_croak(aTHX_ "OS2::_headerInfo(): unexpected size: %d", (int)size);
|
---|
3810 | ST(0) = newSVpvn("",0);
|
---|
3811 | SvGROW(ST(0), size + 1);
|
---|
3812 | sv_2mortal(ST(0));
|
---|
3813 |
|
---|
3814 | if (!_Dos32QueryHeaderInfo(handle, offset, SvPV(ST(0), n_a), size, req))
|
---|
3815 | Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
|
---|
3816 | req, size, handle, offset, os2error(Perl_rc));
|
---|
3817 | SvCUR_set(ST(0), size);
|
---|
3818 | *SvEND(ST(0)) = 0;
|
---|
3819 | }
|
---|
3820 | XSRETURN(1);
|
---|
3821 | }
|
---|
3822 |
|
---|
3823 | #define DQHI_QUERYLIBPATHSIZE 4
|
---|
3824 | #define DQHI_QUERYLIBPATH 5
|
---|
3825 |
|
---|
3826 | XS(XS_OS2_libPath)
|
---|
3827 | {
|
---|
3828 | dXSARGS;
|
---|
3829 | if (items != 0)
|
---|
3830 | Perl_croak(aTHX_ "Usage: OS2::libPath()");
|
---|
3831 | {
|
---|
3832 | ULONG size;
|
---|
3833 | STRLEN n_a;
|
---|
3834 |
|
---|
3835 | if (!_Dos32QueryHeaderInfo(0, 0, &size, sizeof(size),
|
---|
3836 | DQHI_QUERYLIBPATHSIZE))
|
---|
3837 | Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
|
---|
3838 | DQHI_QUERYLIBPATHSIZE, sizeof(size), 0, 0,
|
---|
3839 | os2error(Perl_rc));
|
---|
3840 | ST(0) = newSVpvn("",0);
|
---|
3841 | SvGROW(ST(0), size + 1);
|
---|
3842 | sv_2mortal(ST(0));
|
---|
3843 |
|
---|
3844 | /* We should be careful: apparently, this entry point does not
|
---|
3845 | pay attention to the size argument, so may overwrite
|
---|
3846 | unrelated data! */
|
---|
3847 | if (!_Dos32QueryHeaderInfo(0, 0, SvPV(ST(0), n_a), size,
|
---|
3848 | DQHI_QUERYLIBPATH))
|
---|
3849 | Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
|
---|
3850 | DQHI_QUERYLIBPATH, size, 0, 0, os2error(Perl_rc));
|
---|
3851 | SvCUR_set(ST(0), size);
|
---|
3852 | *SvEND(ST(0)) = 0;
|
---|
3853 | }
|
---|
3854 | XSRETURN(1);
|
---|
3855 | }
|
---|
3856 |
|
---|
3857 | #define get_control87() _control87(0,0)
|
---|
3858 | #define set_control87 _control87
|
---|
3859 |
|
---|
3860 | XS(XS_OS2__control87)
|
---|
3861 | {
|
---|
3862 | dXSARGS;
|
---|
3863 | if (items != 2)
|
---|
3864 | Perl_croak(aTHX_ "Usage: OS2::_control87(new,mask)");
|
---|
3865 | {
|
---|
3866 | unsigned new = (unsigned)SvIV(ST(0));
|
---|
3867 | unsigned mask = (unsigned)SvIV(ST(1));
|
---|
3868 | unsigned RETVAL;
|
---|
3869 | dXSTARG;
|
---|
3870 |
|
---|
3871 | RETVAL = _control87(new, mask);
|
---|
3872 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
3873 | }
|
---|
3874 | XSRETURN(1);
|
---|
3875 | }
|
---|
3876 |
|
---|
3877 | XS(XS_OS2_mytype)
|
---|
3878 | {
|
---|
3879 | dXSARGS;
|
---|
3880 | int which = 0;
|
---|
3881 |
|
---|
3882 | if (items < 0 || items > 1)
|
---|
3883 | Perl_croak(aTHX_ "Usage: OS2::mytype([which])");
|
---|
3884 | if (items == 1)
|
---|
3885 | which = (int)SvIV(ST(0));
|
---|
3886 | {
|
---|
3887 | unsigned RETVAL;
|
---|
3888 | dXSTARG;
|
---|
3889 |
|
---|
3890 | switch (which) {
|
---|
3891 | case 0:
|
---|
3892 | RETVAL = os2_mytype; /* Reset after fork */
|
---|
3893 | break;
|
---|
3894 | case 1:
|
---|
3895 | RETVAL = os2_mytype_ini; /* Before any fork */
|
---|
3896 | break;
|
---|
3897 | case 2:
|
---|
3898 | RETVAL = Perl_os2_initial_mode; /* Before first morphing */
|
---|
3899 | break;
|
---|
3900 | case 3:
|
---|
3901 | RETVAL = my_type(); /* Morphed type */
|
---|
3902 | break;
|
---|
3903 | default:
|
---|
3904 | Perl_croak(aTHX_ "OS2::mytype(which): unknown which=%d", which);
|
---|
3905 | }
|
---|
3906 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
3907 | }
|
---|
3908 | XSRETURN(1);
|
---|
3909 | }
|
---|
3910 |
|
---|
3911 |
|
---|
3912 | XS(XS_OS2_mytype_set)
|
---|
3913 | {
|
---|
3914 | dXSARGS;
|
---|
3915 | int type;
|
---|
3916 |
|
---|
3917 | if (items == 1)
|
---|
3918 | type = (int)SvIV(ST(0));
|
---|
3919 | else
|
---|
3920 | Perl_croak(aTHX_ "Usage: OS2::mytype_set(type)");
|
---|
3921 | my_type_set(type);
|
---|
3922 | XSRETURN_EMPTY;
|
---|
3923 | }
|
---|
3924 |
|
---|
3925 |
|
---|
3926 | XS(XS_OS2_get_control87)
|
---|
3927 | {
|
---|
3928 | dXSARGS;
|
---|
3929 | if (items != 0)
|
---|
3930 | Perl_croak(aTHX_ "Usage: OS2::get_control87()");
|
---|
3931 | {
|
---|
3932 | unsigned RETVAL;
|
---|
3933 | dXSTARG;
|
---|
3934 |
|
---|
3935 | RETVAL = get_control87();
|
---|
3936 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
3937 | }
|
---|
3938 | XSRETURN(1);
|
---|
3939 | }
|
---|
3940 |
|
---|
3941 |
|
---|
3942 | XS(XS_OS2_set_control87)
|
---|
3943 | {
|
---|
3944 | dXSARGS;
|
---|
3945 | if (items < 0 || items > 2)
|
---|
3946 | Perl_croak(aTHX_ "Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
|
---|
3947 | {
|
---|
3948 | unsigned new;
|
---|
3949 | unsigned mask;
|
---|
3950 | unsigned RETVAL;
|
---|
3951 | dXSTARG;
|
---|
3952 |
|
---|
3953 | if (items < 1)
|
---|
3954 | new = MCW_EM;
|
---|
3955 | else {
|
---|
3956 | new = (unsigned)SvIV(ST(0));
|
---|
3957 | }
|
---|
3958 |
|
---|
3959 | if (items < 2)
|
---|
3960 | mask = MCW_EM;
|
---|
3961 | else {
|
---|
3962 | mask = (unsigned)SvIV(ST(1));
|
---|
3963 | }
|
---|
3964 |
|
---|
3965 | RETVAL = set_control87(new, mask);
|
---|
3966 | XSprePUSH; PUSHi((IV)RETVAL);
|
---|
3967 | }
|
---|
3968 | XSRETURN(1);
|
---|
3969 | }
|
---|
3970 |
|
---|
3971 | XS(XS_OS2_incrMaxFHandles) /* DosSetRelMaxFH */
|
---|
3972 | {
|
---|
3973 | dXSARGS;
|
---|
3974 | if (items < 0 || items > 1)
|
---|
3975 | Perl_croak(aTHX_ "Usage: OS2::incrMaxFHandles(delta = 0)");
|
---|
3976 | {
|
---|
3977 | LONG delta;
|
---|
3978 | ULONG RETVAL, rc;
|
---|
3979 | dXSTARG;
|
---|
3980 |
|
---|
3981 | if (items < 1)
|
---|
3982 | delta = 0;
|
---|
3983 | else
|
---|
3984 | delta = (LONG)SvIV(ST(0));
|
---|
3985 |
|
---|
3986 | if (CheckOSError(DosSetRelMaxFH(&delta, &RETVAL)))
|
---|
3987 | croak_with_os2error("OS2::incrMaxFHandles(): DosSetRelMaxFH() error");
|
---|
3988 | XSprePUSH; PUSHu((UV)RETVAL);
|
---|
3989 | }
|
---|
3990 | XSRETURN(1);
|
---|
3991 | }
|
---|
3992 |
|
---|
3993 | int
|
---|
3994 | Xs_OS2_init(pTHX)
|
---|
3995 | {
|
---|
3996 | char *file = __FILE__;
|
---|
3997 | {
|
---|
3998 | GV *gv;
|
---|
3999 |
|
---|
4000 | if (_emx_env & 0x200) { /* OS/2 */
|
---|
4001 | newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
|
---|
4002 | newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
|
---|
4003 | newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
|
---|
4004 | newXS("OS2::extLibpath", XS_Cwd_extLibpath, file);
|
---|
4005 | newXS("OS2::extLibpath_set", XS_Cwd_extLibpath_set, file);
|
---|
4006 | }
|
---|
4007 | newXS("OS2::Error", XS_OS2_Error, file);
|
---|
4008 | newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
|
---|
4009 | newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
|
---|
4010 | newXSproto("OS2::DevCap", XS_OS2_DevCap, file, ";$$");
|
---|
4011 | newXSproto("OS2::SysInfoFor", XS_OS2_SysInfoFor, file, "$;$");
|
---|
4012 | newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
|
---|
4013 | newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
|
---|
4014 | newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
|
---|
4015 | newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
|
---|
4016 | newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
|
---|
4017 | newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
|
---|
4018 | newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
|
---|
4019 | newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
|
---|
4020 | newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
|
---|
4021 | newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
|
---|
4022 | newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
|
---|
4023 | newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
|
---|
4024 | newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
|
---|
4025 | newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
|
---|
4026 | newXS("OS2::replaceModule", XS_OS2_replaceModule, file);
|
---|
4027 | newXS("OS2::perfSysCall", XS_OS2_perfSysCall, file);
|
---|
4028 | newXSproto("OS2::_control87", XS_OS2__control87, file, "$$");
|
---|
4029 | newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
|
---|
4030 | newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
|
---|
4031 | newXSproto("OS2::DLLname", XS_OS2_DLLname, file, ";$$");
|
---|
4032 | newXSproto("OS2::mytype", XS_OS2_mytype, file, ";$");
|
---|
4033 | newXSproto("OS2::mytype_set", XS_OS2_mytype_set, file, "$");
|
---|
4034 | newXSproto("OS2::_headerInfo", XS_OS2__headerInfo, file, "$$;$$");
|
---|
4035 | newXSproto("OS2::libPath", XS_OS2_libPath, file, "");
|
---|
4036 | newXSproto("OS2::Timer", XS_OS2_Timer, file, "");
|
---|
4037 | newXSproto("OS2::msCounter", XS_OS2_msCounter, file, "");
|
---|
4038 | newXSproto("OS2::ms_sleep", XS_OS2_ms_sleep, file, "$;$");
|
---|
4039 | newXSproto("OS2::_InfoTable", XS_OS2__InfoTable, file, ";$");
|
---|
4040 | newXSproto("OS2::incrMaxFHandles", XS_OS2_incrMaxFHandles, file, ";$");
|
---|
4041 | newXSproto("OS2::SysValues", XS_OS2_SysValues, file, ";$$");
|
---|
4042 | newXSproto("OS2::SysValues_set", XS_OS2_SysValues_set, file, "$$;$");
|
---|
4043 | newXSproto("OS2::Beep", XS_OS2_Beep, file, ";$$");
|
---|
4044 | gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
|
---|
4045 | GvMULTI_on(gv);
|
---|
4046 | #ifdef PERL_IS_AOUT
|
---|
4047 | sv_setiv(GvSV(gv), 1);
|
---|
4048 | #endif
|
---|
4049 | gv = gv_fetchpv("OS2::is_static", TRUE, SVt_PV);
|
---|
4050 | GvMULTI_on(gv);
|
---|
4051 | #ifdef PERL_IS_AOUT
|
---|
4052 | sv_setiv(GvSV(gv), 1);
|
---|
4053 | #endif
|
---|
4054 | gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV);
|
---|
4055 | GvMULTI_on(gv);
|
---|
4056 | sv_setiv(GvSV(gv), exe_is_aout());
|
---|
4057 | gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
|
---|
4058 | GvMULTI_on(gv);
|
---|
4059 | sv_setiv(GvSV(gv), _emx_rev);
|
---|
4060 | sv_setpv(GvSV(gv), _emx_vprt);
|
---|
4061 | SvIOK_on(GvSV(gv));
|
---|
4062 | gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
|
---|
4063 | GvMULTI_on(gv);
|
---|
4064 | sv_setiv(GvSV(gv), _emx_env);
|
---|
4065 | gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
|
---|
4066 | GvMULTI_on(gv);
|
---|
4067 | sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
|
---|
4068 | gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
|
---|
4069 | GvMULTI_on(gv);
|
---|
4070 | sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
|
---|
4071 | }
|
---|
4072 | return 0;
|
---|
4073 | }
|
---|
4074 |
|
---|
4075 | extern void _emx_init(void*);
|
---|
4076 |
|
---|
4077 | static void jmp_out_of_atexit(void);
|
---|
4078 |
|
---|
4079 | #define FORCE_EMX_INIT_CONTRACT_ARGV 1
|
---|
4080 | #define FORCE_EMX_INIT_INSTALL_ATEXIT 2
|
---|
4081 |
|
---|
4082 | static void
|
---|
4083 | my_emx_init(void *layout) {
|
---|
4084 | static volatile void *old_esp = 0; /* Cannot be on stack! */
|
---|
4085 |
|
---|
4086 | /* Can't just call emx_init(), since it moves the stack pointer */
|
---|
4087 | /* It also busts a lot of registers, so be extra careful */
|
---|
4088 | __asm__( "pushf\n"
|
---|
4089 | "pusha\n"
|
---|
4090 | "movl %%esp, %1\n"
|
---|
4091 | "push %0\n"
|
---|
4092 | "call __emx_init\n"
|
---|
4093 | "movl %1, %%esp\n"
|
---|
4094 | "popa\n"
|
---|
4095 | "popf\n" : : "r" (layout), "m" (old_esp) );
|
---|
4096 | }
|
---|
4097 |
|
---|
4098 | struct layout_table_t {
|
---|
4099 | ULONG text_base;
|
---|
4100 | ULONG text_end;
|
---|
4101 | ULONG data_base;
|
---|
4102 | ULONG data_end;
|
---|
4103 | ULONG bss_base;
|
---|
4104 | ULONG bss_end;
|
---|
4105 | ULONG heap_base;
|
---|
4106 | ULONG heap_end;
|
---|
4107 | ULONG heap_brk;
|
---|
4108 | ULONG heap_off;
|
---|
4109 | ULONG os2_dll;
|
---|
4110 | ULONG stack_base;
|
---|
4111 | ULONG stack_end;
|
---|
4112 | ULONG flags;
|
---|
4113 | ULONG reserved[2];
|
---|
4114 | char options[64];
|
---|
4115 | };
|
---|
4116 |
|
---|
4117 | static ULONG
|
---|
4118 | my_os_version() {
|
---|
4119 | static ULONG osv_res; /* Cannot be on stack! */
|
---|
4120 |
|
---|
4121 | /* Can't just call __os_version(), since it does not follow C
|
---|
4122 | calling convention: it busts a lot of registers, so be extra careful */
|
---|
4123 | __asm__( "pushf\n"
|
---|
4124 | "pusha\n"
|
---|
4125 | "call ___os_version\n"
|
---|
4126 | "movl %%eax, %0\n"
|
---|
4127 | "popa\n"
|
---|
4128 | "popf\n" : "=m" (osv_res) );
|
---|
4129 |
|
---|
4130 | return osv_res;
|
---|
4131 | }
|
---|
4132 |
|
---|
4133 | static void
|
---|
4134 | force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags)
|
---|
4135 | {
|
---|
4136 | /* Calling emx_init() will bust the top of stack: it installs an
|
---|
4137 | exception handler and puts argv data there. */
|
---|
4138 | char *oldarg, *oldenv;
|
---|
4139 | void *oldstackend, *oldstack;
|
---|
4140 | PPIB pib;
|
---|
4141 | PTIB tib;
|
---|
4142 | ULONG rc, error = 0, out;
|
---|
4143 | char buf[512];
|
---|
4144 | static struct layout_table_t layout_table;
|
---|
4145 | struct {
|
---|
4146 | char buf[48*1024]; /* _emx_init() requires 32K, cmd.exe has 64K only */
|
---|
4147 | double alignment1;
|
---|
4148 | EXCEPTIONREGISTRATIONRECORD xreg;
|
---|
4149 | } *newstack;
|
---|
4150 | char *s;
|
---|
4151 |
|
---|
4152 | layout_table.os2_dll = (ULONG)&os2_dll_fake;
|
---|
4153 | layout_table.flags = 0x02000002; /* flags: application, OMF */
|
---|
4154 |
|
---|
4155 | DosGetInfoBlocks(&tib, &pib);
|
---|
4156 | oldarg = pib->pib_pchcmd;
|
---|
4157 | oldenv = pib->pib_pchenv;
|
---|
4158 | oldstack = tib->tib_pstack;
|
---|
4159 | oldstackend = tib->tib_pstacklimit;
|
---|
4160 |
|
---|
4161 | if ( (char*)&s < (char*)oldstack + 4*1024
|
---|
4162 | || (char *)oldstackend < (char*)oldstack + 52*1024 )
|
---|
4163 | early_error("It is a lunacy to try to run EMX Perl ",
|
---|
4164 | "with less than 64K of stack;\r\n",
|
---|
4165 | " at least with non-EMX starter...\r\n");
|
---|
4166 |
|
---|
4167 | /* Minimize the damage to the stack via reducing the size of argv. */
|
---|
4168 | if (flags & FORCE_EMX_INIT_CONTRACT_ARGV) {
|
---|
4169 | pib->pib_pchcmd = "\0\0"; /* Need 3 concatenated strings */
|
---|
4170 | pib->pib_pchcmd = "\0"; /* Ended by an extra \0. */
|
---|
4171 | }
|
---|
4172 |
|
---|
4173 | newstack = alloca(sizeof(*newstack));
|
---|
4174 | /* Emulate the stack probe */
|
---|
4175 | s = ((char*)newstack) + sizeof(*newstack);
|
---|
4176 | while (s > (char*)newstack) {
|
---|
4177 | s[-1] = 0;
|
---|
4178 | s -= 4096;
|
---|
4179 | }
|
---|
4180 |
|
---|
4181 | /* Reassigning stack is documented to work */
|
---|
4182 | tib->tib_pstack = (void*)newstack;
|
---|
4183 | tib->tib_pstacklimit = (void*)((char*)newstack + sizeof(*newstack));
|
---|
4184 |
|
---|
4185 | /* Can't just call emx_init(), since it moves the stack pointer */
|
---|
4186 | my_emx_init((void*)&layout_table);
|
---|
4187 |
|
---|
4188 | /* Remove the exception handler, cannot use it - too low on the stack.
|
---|
4189 | Check whether it is inside the new stack. */
|
---|
4190 | buf[0] = 0;
|
---|
4191 | if (tib->tib_pexchain >= tib->tib_pstacklimit
|
---|
4192 | || tib->tib_pexchain < tib->tib_pstack) {
|
---|
4193 | error = 1;
|
---|
4194 | sprintf(buf,
|
---|
4195 | "panic: ExceptionHandler misplaced: not %#lx <= %#lx < %#lx\n",
|
---|
4196 | (unsigned long)tib->tib_pstack,
|
---|
4197 | (unsigned long)tib->tib_pexchain,
|
---|
4198 | (unsigned long)tib->tib_pstacklimit);
|
---|
4199 | goto finish;
|
---|
4200 | }
|
---|
4201 | if (tib->tib_pexchain != &(newstack->xreg)) {
|
---|
4202 | sprintf(buf, "ExceptionHandler misplaced: %#lx != %#lx\n",
|
---|
4203 | (unsigned long)tib->tib_pexchain,
|
---|
4204 | (unsigned long)&(newstack->xreg));
|
---|
4205 | }
|
---|
4206 | rc = DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)tib->tib_pexchain);
|
---|
4207 | if (rc)
|
---|
4208 | sprintf(buf + strlen(buf),
|
---|
4209 | "warning: DosUnsetExceptionHandler rc=%#lx=%lu\n", rc, rc);
|
---|
4210 |
|
---|
4211 | if (preg) {
|
---|
4212 | /* ExceptionRecords should be on stack, in a correct order. Sigh... */
|
---|
4213 | preg->prev_structure = 0;
|
---|
4214 | preg->ExceptionHandler = _emx_exception;
|
---|
4215 | rc = DosSetExceptionHandler(preg);
|
---|
4216 | if (rc) {
|
---|
4217 | sprintf(buf + strlen(buf),
|
---|
4218 | "warning: DosSetExceptionHandler rc=%#lx=%lu\n", rc, rc);
|
---|
4219 | DosWrite(2, buf, strlen(buf), &out);
|
---|
4220 | emx_exception_init = 1; /* Do it around spawn*() calls */
|
---|
4221 | }
|
---|
4222 | } else
|
---|
4223 | emx_exception_init = 1; /* Do it around spawn*() calls */
|
---|
4224 |
|
---|
4225 | finish:
|
---|
4226 | /* Restore the damage */
|
---|
4227 | pib->pib_pchcmd = oldarg;
|
---|
4228 | pib->pib_pchcmd = oldenv;
|
---|
4229 | tib->tib_pstacklimit = oldstackend;
|
---|
4230 | tib->tib_pstack = oldstack;
|
---|
4231 | emx_runtime_init = 1;
|
---|
4232 | if (buf[0])
|
---|
4233 | DosWrite(2, buf, strlen(buf), &out);
|
---|
4234 | if (error)
|
---|
4235 | exit(56);
|
---|
4236 | }
|
---|
4237 |
|
---|
4238 | static void
|
---|
4239 | jmp_out_of_atexit(void)
|
---|
4240 | {
|
---|
4241 | if (longjmp_at_exit)
|
---|
4242 | longjmp(at_exit_buf, 1);
|
---|
4243 | }
|
---|
4244 |
|
---|
4245 | extern void _CRT_term(void);
|
---|
4246 |
|
---|
4247 | void
|
---|
4248 | Perl_OS2_term(void **p, int exitstatus, int flags)
|
---|
4249 | {
|
---|
4250 | if (!emx_runtime_secondary)
|
---|
4251 | return;
|
---|
4252 |
|
---|
4253 | /* The principal executable is not running the same CRTL, so there
|
---|
4254 | is nobody to shutdown *this* CRTL except us... */
|
---|
4255 | if (flags & FORCE_EMX_DEINIT_EXIT) {
|
---|
4256 | if (p && !emx_exception_init)
|
---|
4257 | DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
|
---|
4258 | /* Do not run the executable's CRTL's termination routines */
|
---|
4259 | exit(exitstatus); /* Run at-exit, flush buffers, etc */
|
---|
4260 | }
|
---|
4261 | /* Run at-exit list, and jump out at the end */
|
---|
4262 | if ((flags & FORCE_EMX_DEINIT_RUN_ATEXIT) && !setjmp(at_exit_buf)) {
|
---|
4263 | longjmp_at_exit = 1;
|
---|
4264 | exit(exitstatus); /* The first pass through "if" */
|
---|
4265 | }
|
---|
4266 |
|
---|
4267 | /* Get here if we managed to jump out of exit(), or did not run atexit. */
|
---|
4268 | longjmp_at_exit = 0; /* Maybe exit() is called again? */
|
---|
4269 | #if 0 /* _atexit_n is not exported */
|
---|
4270 | if (flags & FORCE_EMX_DEINIT_RUN_ATEXIT)
|
---|
4271 | _atexit_n = 0; /* Remove the atexit() handlers */
|
---|
4272 | #endif
|
---|
4273 | /* Will segfault on program termination if we leave this dangling... */
|
---|
4274 | if (p && !emx_exception_init)
|
---|
4275 | DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
|
---|
4276 | /* Typically there is no need to do this, done from _DLL_InitTerm() */
|
---|
4277 | if (flags & FORCE_EMX_DEINIT_CRT_TERM)
|
---|
4278 | _CRT_term(); /* Flush buffers, etc. */
|
---|
4279 | /* Now it is a good time to call exit() in the caller's CRTL... */
|
---|
4280 | }
|
---|
4281 |
|
---|
4282 | #include <emx/startup.h>
|
---|
4283 |
|
---|
4284 | extern ULONG __os_version(); /* See system.doc */
|
---|
4285 |
|
---|
4286 | void
|
---|
4287 | check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg)
|
---|
4288 | {
|
---|
4289 | ULONG v_crt, v_emx, count = 0, rc = NO_ERROR, rc1, maybe_inited = 0;
|
---|
4290 | static HMTX hmtx_emx_init = NULLHANDLE;
|
---|
4291 | static int emx_init_done = 0;
|
---|
4292 |
|
---|
4293 | /* If _environ is not set, this code sits in a DLL which
|
---|
4294 | uses a CRT DLL which not compatible with the executable's
|
---|
4295 | CRT library. Some parts of the DLL are not initialized.
|
---|
4296 | */
|
---|
4297 | if (_environ != NULL)
|
---|
4298 | return; /* Properly initialized */
|
---|
4299 |
|
---|
4300 | /* It is not DOS, so we may use OS/2 API now */
|
---|
4301 | /* Some data we manipulate is static; protect ourselves from
|
---|
4302 | calling the same API from a different thread. */
|
---|
4303 | DosEnterMustComplete(&count);
|
---|
4304 |
|
---|
4305 | rc1 = DosEnterCritSec();
|
---|
4306 | if (!hmtx_emx_init)
|
---|
4307 | rc = DosCreateMutexSem(NULL, &hmtx_emx_init, 0, TRUE); /*Create owned*/
|
---|
4308 | else
|
---|
4309 | maybe_inited = 1;
|
---|
4310 |
|
---|
4311 | if (rc != NO_ERROR)
|
---|
4312 | hmtx_emx_init = NULLHANDLE;
|
---|
4313 |
|
---|
4314 | if (rc1 == NO_ERROR)
|
---|
4315 | DosExitCritSec();
|
---|
4316 | DosExitMustComplete(&count);
|
---|
4317 |
|
---|
4318 | while (maybe_inited) { /* Other thread did or is doing the same now */
|
---|
4319 | if (emx_init_done)
|
---|
4320 | return;
|
---|
4321 | rc = DosRequestMutexSem(hmtx_emx_init,
|
---|
4322 | (ULONG) SEM_INDEFINITE_WAIT); /* Timeout (none) */
|
---|
4323 | if (rc == ERROR_INTERRUPT)
|
---|
4324 | continue;
|
---|
4325 | if (rc != NO_ERROR) {
|
---|
4326 | char buf[80];
|
---|
4327 | ULONG out;
|
---|
4328 |
|
---|
4329 | sprintf(buf,
|
---|
4330 | "panic: EMX backdoor init: DosRequestMutexSem error: %lu=%#lx\n", rc, rc);
|
---|
4331 | DosWrite(2, buf, strlen(buf), &out);
|
---|
4332 | return;
|
---|
4333 | }
|
---|
4334 | DosReleaseMutexSem(hmtx_emx_init);
|
---|
4335 | return;
|
---|
4336 | }
|
---|
4337 |
|
---|
4338 | /* If the executable does not use EMX.DLL, EMX.DLL is not completely
|
---|
4339 | initialized either. Uninitialized EMX.DLL returns 0 in the low
|
---|
4340 | nibble of __os_version(). */
|
---|
4341 | v_emx = my_os_version();
|
---|
4342 |
|
---|
4343 | /* _osmajor and _osminor are normally set in _DLL_InitTerm of CRT DLL
|
---|
4344 | (=>_CRT_init=>_entry2) via a call to __os_version(), then
|
---|
4345 | reset when the EXE initialization code calls _text=>_init=>_entry2.
|
---|
4346 | The first time they are wrongly set to 0; the second time the
|
---|
4347 | EXE initialization code had already called emx_init=>initialize1
|
---|
4348 | which correctly set version_major, version_minor used by
|
---|
4349 | __os_version(). */
|
---|
4350 | v_crt = (_osmajor | _osminor);
|
---|
4351 |
|
---|
4352 | if ((_emx_env & 0x200) && !(v_emx & 0xFFFF)) { /* OS/2, EMX uninit. */
|
---|
4353 | force_init_emx_runtime( preg,
|
---|
4354 | FORCE_EMX_INIT_CONTRACT_ARGV
|
---|
4355 | | FORCE_EMX_INIT_INSTALL_ATEXIT );
|
---|
4356 | emx_wasnt_initialized = 1;
|
---|
4357 | /* Update CRTL data basing on now-valid EMX runtime data */
|
---|
4358 | if (!v_crt) { /* The only wrong data are the versions. */
|
---|
4359 | v_emx = my_os_version(); /* *Now* it works */
|
---|
4360 | *(unsigned char *)&_osmajor = v_emx & 0xFF; /* Cast out const */
|
---|
4361 | *(unsigned char *)&_osminor = (v_emx>>8) & 0xFF;
|
---|
4362 | }
|
---|
4363 | }
|
---|
4364 | emx_runtime_secondary = 1;
|
---|
4365 | /* if (flags & FORCE_EMX_INIT_INSTALL_ATEXIT) */
|
---|
4366 | atexit(jmp_out_of_atexit); /* Allow run of atexit() w/o exit() */
|
---|
4367 |
|
---|
4368 | if (env == NULL) { /* Fetch from the process info block */
|
---|
4369 | int c = 0;
|
---|
4370 | PPIB pib;
|
---|
4371 | PTIB tib;
|
---|
4372 | char *e, **ep;
|
---|
4373 |
|
---|
4374 | DosGetInfoBlocks(&tib, &pib);
|
---|
4375 | e = pib->pib_pchenv;
|
---|
4376 | while (*e) { /* Get count */
|
---|
4377 | c++;
|
---|
4378 | e = e + strlen(e) + 1;
|
---|
4379 | }
|
---|
4380 | Newx(env, c + 1, char*);
|
---|
4381 | ep = env;
|
---|
4382 | e = pib->pib_pchenv;
|
---|
4383 | while (c--) {
|
---|
4384 | *ep++ = e;
|
---|
4385 | e = e + strlen(e) + 1;
|
---|
4386 | }
|
---|
4387 | *ep = NULL;
|
---|
4388 | }
|
---|
4389 | _environ = _org_environ = env;
|
---|
4390 | emx_init_done = 1;
|
---|
4391 | if (hmtx_emx_init)
|
---|
4392 | DosReleaseMutexSem(hmtx_emx_init);
|
---|
4393 | }
|
---|
4394 |
|
---|
4395 | #define ENTRY_POINT 0x10000
|
---|
4396 |
|
---|
4397 | static int
|
---|
4398 | exe_is_aout(void)
|
---|
4399 | {
|
---|
4400 | struct layout_table_t *layout;
|
---|
4401 | if (emx_wasnt_initialized)
|
---|
4402 | return 0;
|
---|
4403 | /* Now we know that the principal executable is an EMX application
|
---|
4404 | - unless somebody did already play with delayed initialization... */
|
---|
4405 | /* With EMX applications to determine whether it is AOUT one needs
|
---|
4406 | to examine the start of the executable to find "layout" */
|
---|
4407 | if ( *(unsigned char*)ENTRY_POINT != 0x68 /* PUSH n */
|
---|
4408 | || *(unsigned char*)(ENTRY_POINT+5) != 0xe8 /* CALL */
|
---|
4409 | || *(unsigned char*)(ENTRY_POINT+10) != 0xeb /* JMP */
|
---|
4410 | || *(unsigned char*)(ENTRY_POINT+12) != 0xe8) /* CALL */
|
---|
4411 | return 0; /* ! EMX executable */
|
---|
4412 | /* Fix alignment */
|
---|
4413 | Copy((char*)(ENTRY_POINT+1), &layout, 1, struct layout_table_t*);
|
---|
4414 | return !(layout->flags & 2);
|
---|
4415 | }
|
---|
4416 |
|
---|
4417 | void
|
---|
4418 | Perl_OS2_init(char **env)
|
---|
4419 | {
|
---|
4420 | Perl_OS2_init3(env, 0, 0);
|
---|
4421 | }
|
---|
4422 |
|
---|
4423 | void
|
---|
4424 | Perl_OS2_init3(char **env, void **preg, int flags)
|
---|
4425 | {
|
---|
4426 | char *shell, *s;
|
---|
4427 | ULONG rc;
|
---|
4428 |
|
---|
4429 | _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
|
---|
4430 | MALLOC_INIT;
|
---|
4431 |
|
---|
4432 | check_emx_runtime(env, (EXCEPTIONREGISTRATIONRECORD *)preg);
|
---|
4433 |
|
---|
4434 | settmppath();
|
---|
4435 | OS2_Perl_data.xs_init = &Xs_OS2_init;
|
---|
4436 | if (perl_sh_installed) {
|
---|
4437 | int l = strlen(perl_sh_installed);
|
---|
4438 |
|
---|
4439 | Newx(PL_sh_path, l + 1, char);
|
---|
4440 | memcpy(PL_sh_path, perl_sh_installed, l + 1);
|
---|
4441 | } else if ( (shell = getenv("PERL_SH_DRIVE")) ) {
|
---|
4442 | Newx(PL_sh_path, strlen(SH_PATH) + 1, char);
|
---|
4443 | strcpy(PL_sh_path, SH_PATH);
|
---|
4444 | PL_sh_path[0] = shell[0];
|
---|
4445 | } else if ( (shell = getenv("PERL_SH_DIR")) ) {
|
---|
4446 | int l = strlen(shell), i;
|
---|
4447 |
|
---|
4448 | while (l && (shell[l-1] == '/' || shell[l-1] == '\\'))
|
---|
4449 | l--;
|
---|
4450 | Newx(PL_sh_path, l + 8, char);
|
---|
4451 | strncpy(PL_sh_path, shell, l);
|
---|
4452 | strcpy(PL_sh_path + l, "/sh.exe");
|
---|
4453 | for (i = 0; i < l; i++) {
|
---|
4454 | if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
|
---|
4455 | }
|
---|
4456 | }
|
---|
4457 | #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
|
---|
4458 | MUTEX_INIT(&start_thread_mutex);
|
---|
4459 | MUTEX_INIT(&perlos2_state_mutex);
|
---|
4460 | #endif
|
---|
4461 | os2_mytype = my_type(); /* Do it before morphing. Needed? */
|
---|
4462 | os2_mytype_ini = os2_mytype;
|
---|
4463 | Perl_os2_initial_mode = -1; /* Uninit */
|
---|
4464 |
|
---|
4465 | s = getenv("PERL_BEGINLIBPATH");
|
---|
4466 | if (s)
|
---|
4467 | rc = fill_extLibpath(0, s, NULL, 1, "PERL_BEGINLIBPATH");
|
---|
4468 | else
|
---|
4469 | rc = fill_extLibpath(0, getenv("PERL_PRE_BEGINLIBPATH"), getenv("PERL_POST_BEGINLIBPATH"), 0, "PERL_(PRE/POST)_BEGINLIBPATH");
|
---|
4470 | if (!rc) {
|
---|
4471 | s = getenv("PERL_ENDLIBPATH");
|
---|
4472 | if (s)
|
---|
4473 | rc = fill_extLibpath(1, s, NULL, 1, "PERL_ENDLIBPATH");
|
---|
4474 | else
|
---|
4475 | rc = fill_extLibpath(1, getenv("PERL_PRE_ENDLIBPATH"), getenv("PERL_POST_ENDLIBPATH"), 0, "PERL_(PRE/POST)_ENDLIBPATH");
|
---|
4476 | }
|
---|
4477 | if (rc) {
|
---|
4478 | char buf[1024];
|
---|
4479 |
|
---|
4480 | snprintf(buf, sizeof buf, "Error setting BEGIN/ENDLIBPATH: %s\n",
|
---|
4481 | os2error(rc));
|
---|
4482 | DosWrite(2, buf, strlen(buf), &rc);
|
---|
4483 | exit(2);
|
---|
4484 | }
|
---|
4485 |
|
---|
4486 | _emxload_env("PERL_EMXLOAD_SECS");
|
---|
4487 | /* Some DLLs reset FP flags on load. We may have been linked with them */
|
---|
4488 | _control87(MCW_EM, MCW_EM);
|
---|
4489 | }
|
---|
4490 |
|
---|
4491 | int
|
---|
4492 | fd_ok(int fd)
|
---|
4493 | {
|
---|
4494 | static ULONG max_fh = 0;
|
---|
4495 |
|
---|
4496 | if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
|
---|
4497 | if (fd >= max_fh) { /* Renew */
|
---|
4498 | LONG delta = 0;
|
---|
4499 |
|
---|
4500 | if (DosSetRelMaxFH(&delta, &max_fh)) /* Assume it OK??? */
|
---|
4501 | return 1;
|
---|
4502 | }
|
---|
4503 | return fd < max_fh;
|
---|
4504 | }
|
---|
4505 |
|
---|
4506 | /* Kernels up to Oct 2003 trap on (invalid) dup(max_fh); [off-by-one + double fault]. */
|
---|
4507 | int
|
---|
4508 | dup2(int from, int to)
|
---|
4509 | {
|
---|
4510 | if (fd_ok(from < to ? to : from))
|
---|
4511 | return _dup2(from, to);
|
---|
4512 | errno = EBADF;
|
---|
4513 | return -1;
|
---|
4514 | }
|
---|
4515 |
|
---|
4516 | int
|
---|
4517 | dup(int from)
|
---|
4518 | {
|
---|
4519 | if (fd_ok(from))
|
---|
4520 | return _dup(from);
|
---|
4521 | errno = EBADF;
|
---|
4522 | return -1;
|
---|
4523 | }
|
---|
4524 |
|
---|
4525 | #undef tmpnam
|
---|
4526 | #undef tmpfile
|
---|
4527 |
|
---|
4528 | char *
|
---|
4529 | my_tmpnam (char *str)
|
---|
4530 | {
|
---|
4531 | char *p = getenv("TMP"), *tpath;
|
---|
4532 |
|
---|
4533 | if (!p) p = getenv("TEMP");
|
---|
4534 | tpath = tempnam(p, "pltmp");
|
---|
4535 | if (str && tpath) {
|
---|
4536 | strcpy(str, tpath);
|
---|
4537 | return str;
|
---|
4538 | }
|
---|
4539 | return tpath;
|
---|
4540 | }
|
---|
4541 |
|
---|
4542 | FILE *
|
---|
4543 | my_tmpfile ()
|
---|
4544 | {
|
---|
4545 | struct stat s;
|
---|
4546 |
|
---|
4547 | stat(".", &s);
|
---|
4548 | if (s.st_mode & S_IWOTH) {
|
---|
4549 | return tmpfile();
|
---|
4550 | }
|
---|
4551 | return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
|
---|
4552 | grants TMP. */
|
---|
4553 | }
|
---|
4554 |
|
---|
4555 | #undef rmdir
|
---|
4556 |
|
---|
4557 | /* EMX flavors do not tolerate trailing slashes. t/op/mkdir.t has many
|
---|
4558 | trailing slashes, so we need to support this as well. */
|
---|
4559 |
|
---|
4560 | int
|
---|
4561 | my_rmdir (__const__ char *s)
|
---|
4562 | {
|
---|
4563 | char b[MAXPATHLEN];
|
---|
4564 | char *buf = b;
|
---|
4565 | STRLEN l = strlen(s);
|
---|
4566 | int rc;
|
---|
4567 |
|
---|
4568 | if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
|
---|
4569 | if (l >= sizeof b)
|
---|
4570 | Newx(buf, l + 1, char);
|
---|
4571 | strcpy(buf,s);
|
---|
4572 | while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
|
---|
4573 | l--;
|
---|
4574 | buf[l] = 0;
|
---|
4575 | s = buf;
|
---|
4576 | }
|
---|
4577 | rc = rmdir(s);
|
---|
4578 | if (b != buf)
|
---|
4579 | Safefree(buf);
|
---|
4580 | return rc;
|
---|
4581 | }
|
---|
4582 |
|
---|
4583 | #undef mkdir
|
---|
4584 |
|
---|
4585 | int
|
---|
4586 | my_mkdir (__const__ char *s, long perm)
|
---|
4587 | {
|
---|
4588 | char b[MAXPATHLEN];
|
---|
4589 | char *buf = b;
|
---|
4590 | STRLEN l = strlen(s);
|
---|
4591 | int rc;
|
---|
4592 |
|
---|
4593 | if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
|
---|
4594 | if (l >= sizeof b)
|
---|
4595 | Newx(buf, l + 1, char);
|
---|
4596 | strcpy(buf,s);
|
---|
4597 | while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
|
---|
4598 | l--;
|
---|
4599 | buf[l] = 0;
|
---|
4600 | s = buf;
|
---|
4601 | }
|
---|
4602 | rc = mkdir(s, perm);
|
---|
4603 | if (b != buf)
|
---|
4604 | Safefree(buf);
|
---|
4605 | return rc;
|
---|
4606 | }
|
---|
4607 |
|
---|
4608 | #undef flock
|
---|
4609 |
|
---|
4610 | /* This code was contributed by Rocco Caputo. */
|
---|
4611 | int
|
---|
4612 | my_flock(int handle, int o)
|
---|
4613 | {
|
---|
4614 | FILELOCK rNull, rFull;
|
---|
4615 | ULONG timeout, handle_type, flag_word;
|
---|
4616 | APIRET rc;
|
---|
4617 | int blocking, shared;
|
---|
4618 | static int use_my_flock = -1;
|
---|
4619 |
|
---|
4620 | if (use_my_flock == -1) {
|
---|
4621 | MUTEX_LOCK(&perlos2_state_mutex);
|
---|
4622 | if (use_my_flock == -1) {
|
---|
4623 | char *s = getenv("USE_PERL_FLOCK");
|
---|
4624 | if (s)
|
---|
4625 | use_my_flock = atoi(s);
|
---|
4626 | else
|
---|
4627 | use_my_flock = 1;
|
---|
4628 | }
|
---|
4629 | MUTEX_UNLOCK(&perlos2_state_mutex);
|
---|
4630 | }
|
---|
4631 | if (!(_emx_env & 0x200) || !use_my_flock)
|
---|
4632 | return flock(handle, o); /* Delegate to EMX. */
|
---|
4633 |
|
---|
4634 | /* is this a file? */
|
---|
4635 | if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
|
---|
4636 | (handle_type & 0xFF))
|
---|
4637 | {
|
---|
4638 | errno = EBADF;
|
---|
4639 | return -1;
|
---|
4640 | }
|
---|
4641 | /* set lock/unlock ranges */
|
---|
4642 | rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
|
---|
4643 | rFull.lRange = 0x7FFFFFFF;
|
---|
4644 | /* set timeout for blocking */
|
---|
4645 | timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
|
---|
4646 | /* shared or exclusive? */
|
---|
4647 | shared = (o & LOCK_SH) ? 1 : 0;
|
---|
4648 | /* do not block the unlock */
|
---|
4649 | if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
|
---|
4650 | rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
|
---|
4651 | switch (rc) {
|
---|
4652 | case 0:
|
---|
4653 | errno = 0;
|
---|
4654 | return 0;
|
---|
4655 | case ERROR_INVALID_HANDLE:
|
---|
4656 | errno = EBADF;
|
---|
4657 | return -1;
|
---|
4658 | case ERROR_SHARING_BUFFER_EXCEEDED:
|
---|
4659 | errno = ENOLCK;
|
---|
4660 | return -1;
|
---|
4661 | case ERROR_LOCK_VIOLATION:
|
---|
4662 | break; /* not an error */
|
---|
4663 | case ERROR_INVALID_PARAMETER:
|
---|
4664 | case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
|
---|
4665 | case ERROR_READ_LOCKS_NOT_SUPPORTED:
|
---|
4666 | errno = EINVAL;
|
---|
4667 | return -1;
|
---|
4668 | case ERROR_INTERRUPT:
|
---|
4669 | errno = EINTR;
|
---|
4670 | return -1;
|
---|
4671 | default:
|
---|
4672 | errno = EINVAL;
|
---|
4673 | return -1;
|
---|
4674 | }
|
---|
4675 | }
|
---|
4676 | /* lock may block */
|
---|
4677 | if (o & (LOCK_SH | LOCK_EX)) {
|
---|
4678 | /* for blocking operations */
|
---|
4679 | for (;;) {
|
---|
4680 | rc =
|
---|
4681 | DosSetFileLocks(
|
---|
4682 | handle,
|
---|
4683 | &rNull,
|
---|
4684 | &rFull,
|
---|
4685 | timeout,
|
---|
4686 | shared
|
---|
4687 | );
|
---|
4688 | switch (rc) {
|
---|
4689 | case 0:
|
---|
4690 | errno = 0;
|
---|
4691 | return 0;
|
---|
4692 | case ERROR_INVALID_HANDLE:
|
---|
4693 | errno = EBADF;
|
---|
4694 | return -1;
|
---|
4695 | case ERROR_SHARING_BUFFER_EXCEEDED:
|
---|
4696 | errno = ENOLCK;
|
---|
4697 | return -1;
|
---|
4698 | case ERROR_LOCK_VIOLATION:
|
---|
4699 | if (!blocking) {
|
---|
4700 | errno = EWOULDBLOCK;
|
---|
4701 | return -1;
|
---|
4702 | }
|
---|
4703 | break;
|
---|
4704 | case ERROR_INVALID_PARAMETER:
|
---|
4705 | case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
|
---|
4706 | case ERROR_READ_LOCKS_NOT_SUPPORTED:
|
---|
4707 | errno = EINVAL;
|
---|
4708 | return -1;
|
---|
4709 | case ERROR_INTERRUPT:
|
---|
4710 | errno = EINTR;
|
---|
4711 | return -1;
|
---|
4712 | default:
|
---|
4713 | errno = EINVAL;
|
---|
4714 | return -1;
|
---|
4715 | }
|
---|
4716 | /* give away timeslice */
|
---|
4717 | DosSleep(1);
|
---|
4718 | }
|
---|
4719 | }
|
---|
4720 |
|
---|
4721 | errno = 0;
|
---|
4722 | return 0;
|
---|
4723 | }
|
---|
4724 |
|
---|
4725 | static int
|
---|
4726 | use_my_pwent(void)
|
---|
4727 | {
|
---|
4728 | if (_my_pwent == -1) {
|
---|
4729 | char *s = getenv("USE_PERL_PWENT");
|
---|
4730 | if (s)
|
---|
4731 | _my_pwent = atoi(s);
|
---|
4732 | else
|
---|
4733 | _my_pwent = 1;
|
---|
4734 | }
|
---|
4735 | return _my_pwent;
|
---|
4736 | }
|
---|
4737 |
|
---|
4738 | #undef setpwent
|
---|
4739 | #undef getpwent
|
---|
4740 | #undef endpwent
|
---|
4741 |
|
---|
4742 | void
|
---|
4743 | my_setpwent(void)
|
---|
4744 | {
|
---|
4745 | if (!use_my_pwent()) {
|
---|
4746 | setpwent(); /* Delegate to EMX. */
|
---|
4747 | return;
|
---|
4748 | }
|
---|
4749 | pwent_cnt = 0;
|
---|
4750 | }
|
---|
4751 |
|
---|
4752 | void
|
---|
4753 | my_endpwent(void)
|
---|
4754 | {
|
---|
4755 | if (!use_my_pwent()) {
|
---|
4756 | endpwent(); /* Delegate to EMX. */
|
---|
4757 | return;
|
---|
4758 | }
|
---|
4759 | }
|
---|
4760 |
|
---|
4761 | struct passwd *
|
---|
4762 | my_getpwent (void)
|
---|
4763 | {
|
---|
4764 | if (!use_my_pwent())
|
---|
4765 | return getpwent(); /* Delegate to EMX. */
|
---|
4766 | if (pwent_cnt++)
|
---|
4767 | return 0; /* Return one entry only */
|
---|
4768 | return getpwuid(0);
|
---|
4769 | }
|
---|
4770 |
|
---|
4771 | void
|
---|
4772 | setgrent(void)
|
---|
4773 | {
|
---|
4774 | grent_cnt = 0;
|
---|
4775 | }
|
---|
4776 |
|
---|
4777 | void
|
---|
4778 | endgrent(void)
|
---|
4779 | {
|
---|
4780 | }
|
---|
4781 |
|
---|
4782 | struct group *
|
---|
4783 | getgrent (void)
|
---|
4784 | {
|
---|
4785 | if (grent_cnt++)
|
---|
4786 | return 0; /* Return one entry only */
|
---|
4787 | return getgrgid(0);
|
---|
4788 | }
|
---|
4789 |
|
---|
4790 | #undef getpwuid
|
---|
4791 | #undef getpwnam
|
---|
4792 |
|
---|
4793 | /* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */
|
---|
4794 | static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK";
|
---|
4795 |
|
---|
4796 | static struct passwd *
|
---|
4797 | passw_wrap(struct passwd *p)
|
---|
4798 | {
|
---|
4799 | char *s;
|
---|
4800 |
|
---|
4801 | if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
|
---|
4802 | return p;
|
---|
4803 | pw = *p;
|
---|
4804 | s = getenv("PW_PASSWD");
|
---|
4805 | if (!s)
|
---|
4806 | s = (char*)pw_p; /* Make match impossible */
|
---|
4807 |
|
---|
4808 | pw.pw_passwd = s;
|
---|
4809 | return &pw;
|
---|
4810 | }
|
---|
4811 |
|
---|
4812 | struct passwd *
|
---|
4813 | my_getpwuid (uid_t id)
|
---|
4814 | {
|
---|
4815 | return passw_wrap(getpwuid(id));
|
---|
4816 | }
|
---|
4817 |
|
---|
4818 | struct passwd *
|
---|
4819 | my_getpwnam (__const__ char *n)
|
---|
4820 | {
|
---|
4821 | return passw_wrap(getpwnam(n));
|
---|
4822 | }
|
---|
4823 |
|
---|
4824 | char *
|
---|
4825 | gcvt_os2 (double value, int digits, char *buffer)
|
---|
4826 | {
|
---|
4827 | double absv = value > 0 ? value : -value;
|
---|
4828 | /* EMX implementation is lousy between 0.1 and 0.0001 (uses exponents below
|
---|
4829 | 0.1), 1-digit stuff is ok below 0.001; multi-digit below 0.0001. */
|
---|
4830 | int buggy;
|
---|
4831 |
|
---|
4832 | absv *= 10000;
|
---|
4833 | buggy = (absv < 1000 && (absv >= 10 || (absv > 1 && floor(absv) != absv)));
|
---|
4834 |
|
---|
4835 | if (buggy) {
|
---|
4836 | char pat[12];
|
---|
4837 |
|
---|
4838 | sprintf(pat, "%%.%dg", digits);
|
---|
4839 | sprintf(buffer, pat, value);
|
---|
4840 | return buffer;
|
---|
4841 | }
|
---|
4842 | return gcvt (value, digits, buffer);
|
---|
4843 | }
|
---|
4844 |
|
---|
4845 | #undef fork
|
---|
4846 | int fork_with_resources()
|
---|
4847 | {
|
---|
4848 | #if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
|
---|
4849 | dTHX;
|
---|
4850 | void *ctx = PERL_GET_CONTEXT;
|
---|
4851 | #endif
|
---|
4852 | unsigned fpflag = _control87(0,0);
|
---|
4853 | int rc = fork();
|
---|
4854 |
|
---|
4855 | if (rc == 0) { /* child */
|
---|
4856 | #if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
|
---|
4857 | ALLOC_THREAD_KEY; /* Acquire the thread-local memory */
|
---|
4858 | PERL_SET_CONTEXT(ctx); /* Reinit the thread-local memory */
|
---|
4859 | #endif
|
---|
4860 |
|
---|
4861 | { /* Reload loaded-on-demand DLLs */
|
---|
4862 | struct dll_handle_t *dlls = dll_handles;
|
---|
4863 |
|
---|
4864 | while (dlls->modname) {
|
---|
4865 | char dllname[260], fail[260];
|
---|
4866 | ULONG rc;
|
---|
4867 |
|
---|
4868 | if (!dlls->handle) { /* Was not loaded */
|
---|
4869 | dlls++;
|
---|
4870 | continue;
|
---|
4871 | }
|
---|
4872 | /* It was loaded in the parent. We need to reload it. */
|
---|
4873 |
|
---|
4874 | rc = DosQueryModuleName(dlls->handle, sizeof(dllname), dllname);
|
---|
4875 | if (rc) {
|
---|
4876 | Perl_warn_nocontext("Can't find DLL name for the module `%s' by the handle %d, rc=%lu=%#lx",
|
---|
4877 | dlls->modname, (int)dlls->handle, rc, rc);
|
---|
4878 | dlls++;
|
---|
4879 | continue;
|
---|
4880 | }
|
---|
4881 | rc = DosLoadModule(fail, sizeof fail, dllname, &dlls->handle);
|
---|
4882 | if (rc)
|
---|
4883 | Perl_warn_nocontext("Can't load DLL `%s', possible problematic module `%s'",
|
---|
4884 | dllname, fail);
|
---|
4885 | dlls++;
|
---|
4886 | }
|
---|
4887 | }
|
---|
4888 |
|
---|
4889 | { /* Support message queue etc. */
|
---|
4890 | os2_mytype = my_type();
|
---|
4891 | /* Apparently, subprocesses (in particular, fork()) do not
|
---|
4892 | inherit the morphed state, so os2_mytype is the same as
|
---|
4893 | os2_mytype_ini. */
|
---|
4894 |
|
---|
4895 | if (Perl_os2_initial_mode != -1
|
---|
4896 | && Perl_os2_initial_mode != os2_mytype) {
|
---|
4897 | /* XXXX ??? */
|
---|
4898 | }
|
---|
4899 | }
|
---|
4900 | if (Perl_HAB_set)
|
---|
4901 | (void)_obtain_Perl_HAB;
|
---|
4902 | if (Perl_hmq_refcnt) {
|
---|
4903 | if (my_type() != 3)
|
---|
4904 | my_type_set(3);
|
---|
4905 | Create_HMQ(Perl_hmq_servers != 0,
|
---|
4906 | "Cannot create a message queue on fork");
|
---|
4907 | }
|
---|
4908 |
|
---|
4909 | /* We may have loaded some modules */
|
---|
4910 | _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
|
---|
4911 | }
|
---|
4912 | return rc;
|
---|
4913 | }
|
---|
4914 |
|
---|
4915 | /* APIRET APIENTRY DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal); */
|
---|
4916 |
|
---|
4917 | ULONG _THUNK_FUNCTION(Dos16GetInfoSeg)(USHORT *pGlobal, USHORT *pLocal);
|
---|
4918 |
|
---|
4919 | APIRET APIENTRY
|
---|
4920 | myDosGetInfoSeg(PGINFOSEG *pGlobal, PLINFOSEG *pLocal)
|
---|
4921 | {
|
---|
4922 | APIRET rc;
|
---|
4923 | USHORT gSel, lSel; /* Will not cross 64K boundary */
|
---|
4924 |
|
---|
4925 | rc = ((USHORT)
|
---|
4926 | (_THUNK_PROLOG (4+4);
|
---|
4927 | _THUNK_FLAT (&gSel);
|
---|
4928 | _THUNK_FLAT (&lSel);
|
---|
4929 | _THUNK_CALL (Dos16GetInfoSeg)));
|
---|
4930 | if (rc)
|
---|
4931 | return rc;
|
---|
4932 | *pGlobal = MAKEPGINFOSEG(gSel);
|
---|
4933 | *pLocal = MAKEPLINFOSEG(lSel);
|
---|
4934 | return rc;
|
---|
4935 | }
|
---|
4936 |
|
---|
4937 | static void
|
---|
4938 | GetInfoTables(void)
|
---|
4939 | {
|
---|
4940 | ULONG rc = 0;
|
---|
4941 |
|
---|
4942 | MUTEX_LOCK(&perlos2_state_mutex);
|
---|
4943 | if (!gTable)
|
---|
4944 | rc = myDosGetInfoSeg(&gTable, &lTable);
|
---|
4945 | MUTEX_UNLOCK(&perlos2_state_mutex);
|
---|
4946 | os2cp_croak(rc, "Dos16GetInfoSeg");
|
---|
4947 | }
|
---|
4948 |
|
---|
4949 | ULONG
|
---|
4950 | msCounter(void)
|
---|
4951 | { /* XXXX Is not lTable thread-specific? */
|
---|
4952 | if (!gTable)
|
---|
4953 | GetInfoTables();
|
---|
4954 | return gTable->SIS_MsCount;
|
---|
4955 | }
|
---|
4956 |
|
---|
4957 | ULONG
|
---|
4958 | InfoTable(int local)
|
---|
4959 | {
|
---|
4960 | if (!gTable)
|
---|
4961 | GetInfoTables();
|
---|
4962 | return local ? (ULONG)lTable : (ULONG)gTable;
|
---|
4963 | }
|
---|