3 #define INCL_DOSFILEMGR
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
14 #include <emx/syscalls.h>
15 #include <sys/emxload.h>
17 #include <sys/uflags.h>
20 * Various Unix compatibility functions for OS/2
31 #define PERLIO_NOT_STDIO 0
36 enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full,
37 mod_name_C_function = 0x100, mod_name_HMODULE = 0x200};
39 /* Find module name to which *this* subroutine is compiled */
40 #define module_name(how) module_name_at(&module_name_at, how)
42 static SV* module_name_at(void *pp, enum module_name_how how);
45 croak_with_os2error(char *s)
47 Perl_croak_nocontext("%s: %s", s, os2error(Perl_rc));
50 struct PMWIN_entries_t PMWIN_entries;
52 /*****************************************************************************/
53 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
61 static struct dll_handle_t dll_handles[] = {
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])
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
110 perlos2_state // see below
112 /* The following global-scope data is not yet included:
114 pthreads_states // const now?
116 thread_join_count // protected
117 thread_join_data // protected
122 Perl_OS2_init3() - should it be protected?
124 OS2_Perl_data_t OS2_Perl_data;
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; */
131 PFN po2_ExtFCN[ORD_NENTRIES]; /* Labeled by ord ORD_*. */
132 /* struct PMWIN_entries_t po2_PMWIN_entries; */
134 int po2_emx_wasnt_initialized;
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;
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? */
159 int po2_spawn_killed;
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;
171 -1, /* po2__my_pwent */
172 -1, /* po2_DOS_harderr_state */
173 -1, /* po2_DOS_suppression_state */
176 #define Perl_po2() (&perlos2_state)
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)
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)
216 const Perl_PFN * const pExtFCN = (Perl_po2()->po2_ExtFCN);
218 #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
220 typedef void (*emx_startroutine)(void *);
221 typedef void* (*pthreads_startroutine)(void *);
223 enum pthreads_state {
224 pthreads_st_none = 0,
227 pthreads_st_detached,
230 pthreads_st_exited_waited,
232 const char * const pthreads_states[] = {
239 "exited, then waited on",
242 enum pthread_exists { pthread_not_existant = -0xff };
245 pthreads_state_string(enum pthreads_state state)
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;
252 return pthreads_states[state];
258 enum pthreads_state state;
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;
268 pthread_join(perl_os_thread tid, void **status)
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");
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);
286 case pthreads_st_waited:
287 MUTEX_UNLOCK(&start_thread_mutex);
288 Perl_croak_nocontext("join with a thread with a waiter");
290 case pthreads_st_norun:
292 int state = (int)thread_join_data[tid].status;
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));
301 case pthreads_st_run:
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);
311 MUTEX_UNLOCK(&start_thread_mutex);
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));
324 pthreads_startroutine sub;
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.
335 pthread_startit(void *arg1)
337 /* Thread is already started, we need to transfer control only */
338 pthr_startit args = *(pthr_startit *)arg1;
339 int tid = pthread_self();
344 /* Can't croak, the setjmp() is not in scope... */
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);
353 /* Until args.sub resets it, makes debugging Perl_malloc() work: */
355 if (tid >= thread_join_count) {
356 int oc = thread_join_count;
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);
363 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
366 if (thread_join_data[tid].state != pthreads_st_none) {
367 /* Can't croak, the setjmp() is not in scope... */
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);
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;
390 case pthreads_st_detached:
391 thread_join_data[tid].state = pthreads_st_none;
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 */
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));
409 MUTEX_UNLOCK(&start_thread_mutex);
413 pthread_create(perl_os_thread *tidp, const pthread_attr_t *attr,
414 void *(*start_routine)(void*), void *arg)
419 args.sub = (void*)start_routine;
421 args.ctx = PERL_GET_CONTEXT;
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);
429 *tidp = pthread_not_existant;
430 MUTEX_UNLOCK(&start_thread_mutex);
433 MUTEX_LOCK(&start_thread_mutex); /* Wait for init to proceed */
434 MUTEX_UNLOCK(&start_thread_mutex);
439 pthread_detach(perl_os_thread tid)
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");
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");
454 case pthreads_st_run:
455 thread_join_data[tid].state = pthreads_st_detached;
456 MUTEX_UNLOCK(&start_thread_mutex);
458 case pthreads_st_exited:
459 MUTEX_UNLOCK(&start_thread_mutex);
460 COND_SIGNAL(&thread_join_data[tid].cond);
462 case pthreads_st_detached:
463 MUTEX_UNLOCK(&start_thread_mutex);
464 Perl_warn_nocontext("detach on an already detached thread");
466 case pthreads_st_norun:
468 int state = (int)thread_join_data[tid].status;
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));
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));
486 /* This is a very bastardized version; may be OK due to edge trigger of Wait */
488 os2_cond_wait(perl_cond *c, perl_mutex *m)
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)
500 if (m) MUTEX_LOCK(m);
505 static int exe_is_aout(void);
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;
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},
551 /* At least some of these do not work by name, since they need
552 WIN32 instead of WIN... */
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
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},
644 loadModule(const char *modname, int fail)
646 HMODULE h = (HMODULE)dlopen(modname, 0);
649 Perl_croak_nocontext("Error loading module '%s': %s",
654 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
663 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
664 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
667 return (pib->pib_ultype);
671 my_type_set(int type)
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;
685 loadByOrdinal(enum entries_ordinals ord, int fail)
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) {
695 if (!loadOrdinals[ord].dll->handle) {
696 if (loadOrdinals[ord].dll->requires_pm && my_type() < 2) { /* FS */
697 char *s = getenv("PERL_ASIF_PM");
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. */
705 if (CheckOSError(DosOpenMutexSem("\\SEM32\\PMDRAG.SEM",
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);
712 MUTEX_LOCK(&perlos2_state_mutex);
713 loadOrdinals[ord].dll->handle
714 = loadModule(loadOrdinals[ord].dll->modname, fail);
715 MUTEX_UNLOCK(&perlos2_state_mutex);
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;
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);
734 if ((long)ExtFCN[ord] == -1)
735 Perl_croak_nocontext("panic queryaddr");
740 init_PMWIN_entries(void)
744 for (i = ORD_WinInitialize; i <= ORD_WinCancelShutdown; i++)
745 ((PFN*)&PMWIN_entries)[i - ORD_WinInitialize] = loadByOrdinal(i, 1);
748 /*****************************************************/
749 /* socket forwarders without linking with tcpip DLLs */
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), ())
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))
761 DeclVoidFuncByORD(endhostent, ORD_ENDHOSTENT, (void), ())
762 DeclVoidFuncByORD(endnetent, ORD_ENDNETENT, (void), ())
763 DeclVoidFuncByORD(endprotoent, ORD_ENDPROTOENT, (void), ())
764 DeclVoidFuncByORD(endservent, ORD_ENDSERVENT, (void), ())
767 static const signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
769 #define QSS_INI_BUFFER 1024
771 ULONG (*pDosVerifyPidTid) (PID pid, TID tid);
774 get_sysinfo(ULONG pid, ULONG flags)
777 ULONG rc, buf_len = QSS_INI_BUFFER;
781 if (!pidtid_lookup) {
783 *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0);
785 if (pDosVerifyPidTid) { /* Warp3 or later */
786 /* Up to some fixpak QuerySysState() kills the system if a non-existent
788 if (CheckOSError(pDosVerifyPidTid(pid, 1)))
792 New(1322, 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);
804 psi = (PQTOPLEVEL)pbuffer;
805 if (psi && pid && psi->procdata && pid != psi->procdata->pid) {
807 Perl_croak_nocontext("panic: wrong pid in sysinfo");
812 #define PRIO_ERR 0x1111
822 psi = get_sysinfo(pid, QSS_PROCESS);
825 prio = psi->procdata->threads->priority;
831 setpriority(int which, int pid, int val)
833 ULONG rc, prio = sys_prio(pid);
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,
841 (32 - val) % 32 - (prio & 0xFF),
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,
854 if ( ((32 - val) % 32) == 0 ) return 0;
855 return CheckOSError(DosSetPriority((pid < 0)
856 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
865 getpriority(int which /* ignored */, int pid)
869 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
871 if (ret == PRIO_ERR) {
874 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
877 /*****************************************************************************/
883 spawn_sighandler(int sig)
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.
894 sig = SIGKILL; /* Try harder. */
895 kill(spawn_pid, sig);
900 result(pTHX_ int flag, int pid)
903 Signal_t (*ihand)(); /* place to save signal during system() */
904 Signal_t (*qhand)(); /* place to save signal during system() */
910 if (pid < 0 || flag != 0)
916 ihand = rsignal(SIGINT, &spawn_sighandler);
917 qhand = rsignal(SIGQUIT, &spawn_sighandler);
919 r = wait4pid(pid, &status, 0);
920 } while (r == -1 && errno == EINTR);
921 rsignal(SIGINT, ihand);
922 rsignal(SIGQUIT, qhand);
924 PL_statusvalue = (U16)status;
927 return status & 0xFFFF;
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;
935 return PL_statusvalue;
949 file_type(char *path)
954 if (!(_emx_env & 0x200))
955 Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
956 if (CheckOSError(DosQueryAppType(path, &apptype))) {
958 case ERROR_FILE_NOT_FOUND:
959 case ERROR_PATH_NOT_FOUND:
961 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
963 default: /* Found, but not an
964 executable, or some other
972 /* Spawn/exec a program, revert to shell if needed. */
973 /* global PL_Argv[] contains arguments. */
975 extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *,
976 EXCEPTIONREGISTRATIONRECORD *,
981 do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
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;
992 int new_stderr = -1, nostderr = 0;
1000 if (really && !*(real_name = SvPV(really, n_a)))
1004 if (strEQ(PL_Argv[0],"/bin/sh"))
1005 PL_Argv[0] = PL_sh_path;
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 */
1018 if (_emx_env & 0x200) { /* OS/2. */
1019 int type = file_type(real_name);
1021 if (type == -1) { /* Not found */
1026 else if (type == -2) { /* Not an EXE */
1031 else if (type == -3) { /* Is a directory? */
1032 /* Special-case this */
1034 int l = strlen(real_name);
1036 if (l + 5 <= sizeof tbuf) {
1037 strcpy(tbuf, real_name);
1038 strcpy(tbuf + l, ".exe");
1039 type = file_type(tbuf);
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)
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",
1061 case FAPPTYP_NOTWINDOWCOMPAT:
1063 if (os2_mytype != 0) { /* not full screen */
1064 if (flag == P_NOWAIT)
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",
1072 case FAPPTYP_NOTSPEC:
1073 /* Let the shell handle this... */
1075 buf = ""; /* Pacify a warning */
1076 file = 0; /* Pacify a warning */
1084 new_stderr = dup(2); /* Preserve stderr */
1085 if (new_stderr == -1) {
1093 fl_stderr = fcntl(2, F_GETFD);
1097 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
1101 rc = result(aTHX_ trueflag, spawnvp(flag,real_name,PL_Argv));
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));
1115 if (rc < 0 && pass == 1) {
1117 if (real_name == PL_Argv[0]) {
1120 if (err == ENOENT || err == ENOEXEC) {
1121 /* No such file, or is a script. */
1122 /* Try adding script extensions to the file name, and
1124 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
1128 SV *scrsv = sv_2mortal(newSVpv(scr, 0));
1129 SV *bufsv = sv_newmortal();
1132 scr = SvPV(scrsv, n_a); /* free()ed later */
1134 file = PerlIO_open(scr, "r");
1139 buf = sv_gets(bufsv, file, 0 /* No append */);
1141 buf = ""; /* XXX Needed? */
1142 if (!buf[0]) { /* Empty... */
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 */
1156 } else { /* Restore */
1157 SvCUR_set(scrsv, SvCUR(scrsv) - 4);
1161 if (PerlIO_close(file) != 0) { /* Failure */
1163 if (ckWARN(WARN_EXEC))
1164 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s",
1165 scr, Strerror(errno));
1166 buf = ""; /* Not #! */
1169 if (buf[0] == '#') {
1172 } else if (buf[0] == 'e') {
1173 if (strnEQ(buf, "extproc", 7)
1176 } else if (buf[0] == 'E') {
1177 if (strnEQ(buf, "EXTPROC", 7)
1182 buf = ""; /* Not #! */
1190 /* Do better than pdksh: allow a few args,
1191 strip trailing whitespace. */
1201 while (*s && !isSPACE(*s))
1208 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Too many args on %.*s line of \"%s\"",
1209 s1 - buf, buf, scr);
1213 /* Can jump from far, buf/file invalid if force_shell: */
1217 const char *exec_args[2];
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;
1231 shell = getenv("OS2_SHELL");
1232 if (inicmd) { /* No spaces at start! */
1234 while (*s && !isSPACE(*s)) {
1236 inicmd = NULL; /* Cannot use */
1244 /* Dosish shells will choke on slashes
1245 in paths, fortunately, this is
1246 important for zeroth arg only. */
1253 /* If EXECSHELL is set, we do not set */
1256 shell = ((_emx_env & 0x200)
1258 : "c:/command.com");
1259 nargs = shell_opt ? 2 : 1; /* shell file args */
1260 exec_args[0] = shell;
1261 exec_args[1] = shell_opt;
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;
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... */
1275 PL_Argv[0] = inicmd;
1276 PL_Argv[1] = Nullch;
1277 nargs = 2; /* shell -c */
1280 while (a[1]) /* Get to the end */
1282 a++; /* Copy finil NULL too */
1283 while (a >= PL_Argv) {
1284 *(a + nargs) = *a; /* PL_Argv was preallocated to be
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);
1295 /* Not found: restore errno */
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]);
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]);
1313 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
1314 char *no_dir = strrchr(PL_Argv[0], '/');
1316 /* Do as pdksh port does: if not found with /, try without
1319 PL_Argv[0] = no_dir + 1;
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));
1330 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
1331 && ((trueflag & 0xFF) == P_WAIT))
1335 if (new_stderr != -1) { /* How can we use error codes? */
1336 dup2(new_stderr, 2);
1338 fcntl(2, F_SETFD, fl_stderr);
1339 } else if (nostderr)
1344 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
1346 do_spawn3(pTHX_ char *cmd, int execf, int flag)
1350 char *shell, *copt, *news = NULL;
1351 int rc, seenspace = 0, mergestderr = 0;
1354 if ((shell = getenv("EMXSHELL")) != NULL)
1356 else if ((shell = getenv("SHELL")) != NULL)
1358 else if ((shell = getenv("COMSPEC")) != NULL)
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. */
1371 while (*cmd && isSPACE(*cmd))
1374 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
1375 STRLEN l = strlen(PL_sh_path);
1377 New(1302, news, strlen(cmd) - 7 + l + 1, char);
1378 strcpy(news, PL_sh_path);
1379 strcpy(news + l, cmd + 7);
1383 /* save an extra exec if possible */
1384 /* see if there are shell metacharacters in it */
1386 if (*cmd == '.' && isSPACE(cmd[1]))
1389 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
1392 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
1396 for (s = cmd; *s; s++) {
1397 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
1398 if (*s == '\n' && s[1] == '\0') {
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]) ) {
1408 while (*t && isSPACE(*t))
1413 break; /* Allow 2>&1 as the last thing */
1416 /* We do not convert this to do_spawn_ve since shell
1417 should be smart enough to start itself gloriously. */
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);
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);
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));
1444 } else if (*s == ' ' || *s == '\t') {
1449 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
1450 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
1451 PL_Cmd = savepvn(cmd, s-cmd);
1453 for (s = PL_Cmd; *s;) {
1454 while (*s && isSPACE(*s)) s++;
1457 while (*s && !isSPACE(*s)) s++;
1463 rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
1472 /* Array spawn/exec. */
1474 os2_aspawn4(pTHX_ SV *really, register SV **vmark, register SV **vsp, int execing)
1476 register SV **mark = (SV **)vmark;
1477 register SV **sp = (SV **)vsp;
1480 int flag = P_WAIT, flag_set = 0;
1484 New(1301,PL_Argv, sp - mark + 3, char*);
1487 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
1489 flag = SvIVx(*mark);
1494 while (++mark <= sp) {
1496 *a++ = SvPVx(*mark, n_a);
1502 if ( flag_set && (a == PL_Argv + 1)
1503 && !really && !execing ) { /* One arg? */
1504 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
1506 rc = do_spawn_ve(aTHX_ really, flag,
1507 (execing ? EXECF_EXEC : EXECF_SPAWN), NULL, 0);
1516 os2_do_aspawn(pTHX_ SV *really, register SV **vmark, register SV **vsp)
1518 return os2_aspawn4(aTHX_ really, vmark, vsp, 0);
1523 Perl_do_aexec(pTHX_ SV* really, SV** vmark, SV** vsp)
1525 return os2_aspawn4(aTHX_ really, vmark, vsp, 1);
1529 os2_do_spawn(pTHX_ char *cmd)
1531 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
1535 do_spawn_nowait(pTHX_ char *cmd)
1537 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
1541 Perl_do_exec(pTHX_ char *cmd)
1543 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
1548 os2exec(pTHX_ char *cmd)
1550 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
1554 my_syspopen(pTHX_ char *cmd, char *mode)
1558 register I32 this, that, newfd;
1561 int fh_fl = 0; /* Pacify the warning */
1563 /* `this' is what we use in the parent, `that' in the child. */
1564 this = (*mode == 'w');
1568 taint_proper("Insecure %s%s", "EXEC");
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]);
1581 newfd = dup(*mode == 'r'); /* Preserve std* */
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) {
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');
1598 /* Where is `this' and newfd now? */
1599 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1601 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1602 pid = do_spawn_nowait(aTHX_ cmd);
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. */
1608 fcntl(*mode == 'r', F_SETFD, fh_fl);
1610 fcntl(*mode == 'r', F_SETFD, fh_fl);
1611 if (p[that] == (*mode == 'r'))
1617 if (p[that] < p[this]) { /* Make fh as small as possible */
1618 dup2(p[this], p[that]);
1622 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1623 (void)SvUPGRADE(sv,SVt_IV);
1625 PL_forkprocess = pid;
1626 return PerlIO_fdopen(p[this], mode);
1628 #else /* USE_POPEN */
1634 res = popen(cmd, mode);
1636 char *shell = getenv("EMXSHELL");
1638 my_setenv("EMXSHELL", PL_sh_path);
1639 res = popen(cmd, mode);
1640 my_setenv("EMXSHELL", shell);
1642 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1643 (void)SvUPGRADE(sv,SVt_IV);
1644 SvIVX(sv) = -1; /* A cooky. */
1647 #endif /* USE_POPEN */
1651 /******************************************************************/
1657 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1663 /*******************************************************************/
1664 /* not implemented in EMX 0.9d */
1666 char * ctermid(char *s) { return 0; }
1668 #ifdef MYTTYNAME /* was not in emx0.9a */
1669 void * ttyname(x) { return 0; }
1672 /*****************************************************************************/
1673 /* not implemented in C Set++ */
1676 int setuid(x) { errno = EINVAL; return -1; }
1677 int setgid(x) { errno = EINVAL; return -1; }
1680 /*****************************************************************************/
1681 /* stat() hack for char/block device */
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 */
1692 #define OS2_STAT_SPECIAL (os2_stat_system | os2_stat_archived | os2_stat_hidden)
1695 massage_os2_attr(struct stat *st)
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)))
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);
1710 /* First attempt used DosQueryFSAttach which crashed the system when
1711 used with 5.001. Now just look for /dev/. */
1713 os2_stat(const char *name, struct stat *st)
1715 static int ino = SHRT_MAX;
1716 STRLEN l = strlen(name);
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);
1727 massage_os2_attr(st);
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);
1741 os2_fstat(int handle, struct stat *st)
1743 int s = fstat(handle, st);
1747 massage_os2_attr(st);
1753 os2_chmod (const char *name, int pmode) /* Modelled after EMX src/lib/io/chmod.c */
1757 if (!(pmode & os2_stat_force))
1758 return chmod(name, pmode);
1760 attr = __chmod (name, 0, 0); /* Get attributes */
1763 if (pmode & S_IWRITE)
1764 attr &= ~FILE_READONLY;
1766 attr |= FILE_READONLY;
1768 attr &= ~(FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM);
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;
1777 rc = __chmod (name, 1, attr);
1778 if (rc >= 0) rc = 0;
1784 #ifdef USE_PERL_SBRK
1786 /* SBRK() emulation, mostly moved to malloc.c. */
1789 sys_alloc(int size) {
1791 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1793 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1796 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1800 #endif /* USE_PERL_SBRK */
1804 const char *tmppath = TMPPATH1;
1809 char *p = getenv("TMP"), *tpath;
1812 if (!p) p = getenv("TEMP");
1813 if (!p) p = getenv("TMPDIR");
1816 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1820 strcpy(tpath + len + 1, TMPPATH1);
1827 XS(XS_File__Copy_syscopy)
1830 if (items < 2 || items > 3)
1831 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1834 char * src = (char *)SvPV(ST(0),n_a);
1835 char * dst = (char *)SvPV(ST(1),n_a);
1843 flag = (unsigned long)SvIV(ST(2));
1846 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1847 XSprePUSH; PUSHi((IV)RETVAL);
1852 /* APIRET APIENTRY DosReplaceModule (PCSZ pszOld, PCSZ pszNew, PCSZ pszBackup); */
1854 DeclOSFuncByORD(ULONG,replaceModule,ORD_DosReplaceModule,
1855 (char *old, char *new, char *backup), (old, new, backup))
1857 XS(XS_OS2_replaceModule); /* prototype to pass -Wmissing-prototypes */
1858 XS(XS_OS2_replaceModule)
1861 if (items < 1 || items > 3)
1862 Perl_croak(aTHX_ "Usage: OS2::replaceModule(target [, source [, backup]])");
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));
1868 if (!replaceModule(target, source, backup))
1869 croak_with_os2error("replaceModule() error");
1874 /* APIRET APIENTRY DosPerfSysCall(ULONG ulCommand, ULONG ulParm1,
1875 ULONG ulParm2, ULONG ulParm3); */
1877 DeclOSFuncByORD(ULONG,perfSysCall,ORD_DosPerfSysCall,
1878 (ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3),
1879 (ulCommand, ulParm1, ulParm2, ulParm3))
1881 #ifndef CMD_KI_RDCNT
1882 # define CMD_KI_RDCNT 0x63
1884 #ifndef CMD_KI_GETQTY
1885 # define CMD_KI_GETQTY 0x41
1887 #ifndef QSV_NUMPROCESSORS
1888 # define QSV_NUMPROCESSORS 26
1891 typedef unsigned long long myCPUUTIL[4]; /* time/idle/busy/intr */
1895 perfSysCall(ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3)
1900 croak_with_os2error("perfSysCall() error");
1908 if (DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, (PVOID)&res, sizeof(res)))
1909 return 1; /* Old system? */
1913 XS(XS_OS2_perfSysCall); /* prototype to pass -Wmissing-prototypes */
1914 XS(XS_OS2_perfSysCall)
1917 if (items < 0 || items > 4)
1918 Perl_croak(aTHX_ "Usage: OS2::perfSysCall(ulCommand = CMD_KI_RDCNT, ulParm1= 0, ulParm2= 0, ulParm3= 0)");
1922 ULONG RETVAL, ulCommand, ulParm1, ulParm2, ulParm3, res;
1924 int total = 0, tot2 = 0;
1927 ulCommand = CMD_KI_RDCNT;
1929 ulCommand = (ULONG)SvUV(ST(0));
1933 total = (ulCommand == CMD_KI_RDCNT ? numprocessors() : 0);
1934 ulParm1 = (total ? (ULONG)u : 0);
1936 if (total > C_ARRAY_LENGTH(u))
1937 croak("Unexpected number of processors: %d", total);
1939 ulParm1 = (ULONG)SvUV(ST(1));
1943 tot2 = (ulCommand == CMD_KI_GETQTY);
1944 ulParm2 = (tot2 ? (ULONG)&res : 0);
1946 ulParm2 = (ULONG)SvUV(ST(2));
1952 ulParm3 = (ULONG)SvUV(ST(3));
1955 RETVAL = perfSysCall(ulCommand, ulParm1, ulParm2, ulParm3);
1957 croak_with_os2error("perfSysCall() error");
1961 if (GIMME_V != G_ARRAY) {
1962 PUSHn(u[0][0]); /* Total ticks on the first processor */
1965 for (i=0; i < total; i++)
1966 for (j=0; j < 4; j++)
1967 PUSHs(sv_2mortal(newSVnv(u[i][j])));
1978 #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */
1979 #include "patchlevel.h"
1980 #undef PERL_PATCHLEVEL_H_IMPLICIT
1983 mod2fname(pTHX_ SV *sv)
1985 int pos = 6, len, avlen;
1986 unsigned int sum = 0;
1990 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
1992 if (SvTYPE(sv) != SVt_PVAV)
1993 Perl_croak_nocontext("Not array reference given to mod2fname");
1995 avlen = av_len((AV*)sv);
1997 Perl_croak_nocontext("Empty array reference given to mod2fname");
1999 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
2000 strncpy(fname, s, 8);
2002 if (len < 6) pos = len;
2004 sum = 33 * sum + *(s++); /* Checksumming first chars to
2005 * get the capitalization into c.s. */
2008 while (avlen >= 0) {
2009 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
2011 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
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. */
2020 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
2022 # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
2023 # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
2025 sum += COMPATIBLE_VERSION_SUM;
2027 fname[pos] = 'A' + (sum % 26);
2028 fname[pos + 1] = 'A' + (sum / 26 % 26);
2029 fname[pos + 2] = '\0';
2030 return (char *)fname;
2033 XS(XS_DynaLoader_mod2fname)
2037 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
2043 RETVAL = mod2fname(aTHX_ sv);
2044 sv_setpv(TARG, RETVAL);
2045 XSprePUSH; PUSHTARG;
2056 int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
2058 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
2062 sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
2063 s = os2error_buf + strlen(os2error_buf);
2066 if (DosGetMessage(NULL, 0, s, sizeof(os2error_buf) - 1 - (s-os2error_buf),
2067 rc, "OSO001.MSG", &len)) {
2071 sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
2072 s = os2error_buf + strlen(os2error_buf);
2075 case PMERR_INVALID_HWND:
2076 name = "PMERR_INVALID_HWND";
2078 case PMERR_INVALID_HMQ:
2079 name = "PMERR_INVALID_HMQ";
2081 case PMERR_CALL_FROM_WRONG_THREAD:
2082 name = "PMERR_CALL_FROM_WRONG_THREAD";
2084 case PMERR_NO_MSG_QUEUE:
2085 name = "PMERR_NO_MSG_QUEUE";
2087 case PMERR_NOT_IN_A_PM_SESSION:
2088 name = "PMERR_NOT_IN_A_PM_SESSION";
2091 sprintf(s, "%s%s[No description found in OSO001.MSG]",
2092 name, (*name ? "=" : ""));
2095 if (len && s[len - 1] == '\n')
2097 if (len && s[len - 1] == '\r')
2099 if (len && s[len - 1] == '.')
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);
2106 return os2error_buf;
2116 CroakWinError(int die, char *name)
2120 croak_with_os2error(name ? name : "Win* API call");
2124 dllname2buffer(pTHX_ char *buf, STRLEN l)
2130 dll = module_name(mod_name_full);
2135 return (ll >= l ? "???" : buf);
2139 execname2buffer(char *buf, STRLEN l, char *oname)
2141 char *p, *orig = oname, ok = oname != NULL;
2143 if (_execname(buf, l) != 0) {
2144 if (!oname || strlen(oname) >= l)
2154 if (ok && *oname != '/' && *oname != '\\')
2156 } else if (ok && tolower(*oname) != tolower(*p))
2161 if (ok) { /* orig matches the real name. Use orig: */
2162 strcpy(buf, orig); /* _execname() is always uppercased */
2176 char buf[300], *p = execname2buffer(buf, sizeof buf, PL_origargv[0]);
2184 Perl_OS2_handler_install(void *handler, enum Perlos2_handler how)
2189 case Perlos2_handler_mangle:
2190 perllib_mangle_installed = (char *(*)(char *s, unsigned int l))handler;
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);
2197 case Perlos2_handler_perllib_from:
2198 s = (char *)handler;
2199 s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_from");
2203 case Perlos2_handler_perllib_to:
2204 s = (char *)handler;
2205 s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_to");
2208 strcpy(mangle_ret, newp);
2219 /* Returns a malloc()ed copy */
2221 dir_subst(char *s, unsigned int l, char *b, unsigned int bl, enum dir_subst_e flags, char *msg)
2223 char *from, *to = b, *e = b; /* `to' assignment: shut down the warning */
2224 STRLEN froml = 0, tol = 0, rest = 0; /* froml: likewise */
2226 if (l >= 2 && s[0] == '~') {
2229 from = "installprefix"; break;
2231 from = "dll"; break;
2233 from = "exe"; break;
2236 froml = l + 1; /* Will not match */
2240 froml = strlen(from) + 1;
2241 if (l >= froml && strnicmp(s + 2, from + 1, froml - 2) == 0) {
2247 tol = strlen(INSTALL_PREFIX);
2249 if (flags & dir_subst_fatal)
2250 Perl_croak_nocontext("INSTALL_PREFIX too long: `%s'", INSTALL_PREFIX);
2254 memcpy(b, INSTALL_PREFIX, tol + 1);
2259 if (flags & dir_subst_fatal) {
2262 to = dllname2buffer(aTHX_ b, bl);
2263 } else { /* No Perl present yet */
2264 HMODULE self = find_myself();
2265 APIRET rc = DosQueryModuleName(self, bl, b);
2277 if (flags & dir_subst_fatal) {
2280 to = execname2buffer(b, bl, PL_origargv[0]);
2282 to = execname2buffer(b, bl, NULL);
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);
2295 s += froml; l -= froml;
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);
2312 if (l && s[0] != '/' && s[0] != '\\' && s[0] != ';')
2315 } /* Else: copy as is */
2316 if (l && (flags & dir_subst_pathlike)) {
2319 while ( i < l - 2 && s[i] != ';') /* May have ~char after `;' */
2321 if (i < l - 2) { /* Found */
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);
2334 e = dir_subst(s + l, rest, e + l, bl - (e + l - b), flags, msg);
2342 perllib_mangle_with(char *s, unsigned int l, char *from, unsigned int froml, char *to, unsigned int tol)
2348 if (l < froml || strnicmp(from, s, froml) != 0)
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);
2359 perllib_mangle(char *s, unsigned int l)
2363 if (perllib_mangle_installed && (name = perllib_mangle_installed(s,l)))
2365 if (!newp && !notfound) {
2366 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
2367 STRINGIFY(PERL_VERSION) STRINGIFY(PERL_SUBVERSION)
2370 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
2371 STRINGIFY(PERL_VERSION) "_PREFIX");
2373 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) "_PREFIX");
2375 newp = getenv(name = "PERLLIB_PREFIX");
2380 while (*newp && !isSPACE(*newp) && *newp != ';')
2381 newp++; /* Skip old name. */
2383 s = dir_subst(oldp, oldl, b, sizeof b, dir_subst_fatal, name);
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);
2398 if (l < oldl || strnicmp(oldp, s, oldl) != 0)
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);
2407 Perl_hab_GET() /* Needed if perl.h cannot be included */
2409 return perl_hab_GET();
2413 Create_HMQ(int serve, char *message) /* Assumes morphing */
2415 unsigned fpflag = _control87(0,0);
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);
2423 SAVEINT(rmq_cnt); /* Allow catch()ing. */
2425 _exit(188); /* Panic can try to create a window. */
2426 CroakWinError(1, message ? message : "Cannot create a message queue");
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 */
2434 #define REGISTERMQ_WILL_SERVE 1
2435 #define REGISTERMQ_IMEDIATE_UNMORPH 2
2438 Perl_Register_MQ(int serve)
2440 if (Perl_hmq_refcnt <= 0) {
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 */
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;
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);
2464 } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
2465 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
2467 if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH))
2468 Perl_morph_refcnt++;
2473 Perl_Serve_Messages(int force)
2478 if (Perl_hmq_servers > 0 && !force)
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)) {
2484 if (msg.msg == WM_QUIT)
2485 Perl_croak_nocontext("QUITing...");
2486 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
2492 Perl_Process_Messages(int force, I32 *cntp)
2496 if (Perl_hmq_servers > 0 && !force)
2498 if (Perl_hmq_refcnt <= 0)
2499 Perl_croak_nocontext("No message queue");
2500 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
2503 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
2504 if (msg.msg == WM_DESTROY)
2506 if (msg.msg == WM_CREATE)
2509 Perl_croak_nocontext("QUITing...");
2513 Perl_Deregister_MQ(int serve)
2515 if (serve & REGISTERMQ_WILL_SERVE)
2518 if (--Perl_hmq_refcnt <= 0) {
2519 unsigned fpflag = _control87(0,0);
2521 init_PMWIN_entries(); /* To be extra safe */
2522 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
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. */
2533 DosGetInfoBlocks(&tib, &pib);
2534 if (pib->pib_ultype == 3) /* 3 is PM */
2535 pib->pib_ultype = Perl_os2_initial_mode;
2537 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
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
2548 #undef chdir /* Was _chdir2. */
2549 #define sys_chdir(p) (chdir(p) == 0)
2550 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
2556 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
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));
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;
2575 XS(XS_OS2_Errors2Drive)
2579 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
2583 int suppress = SvOK(sv);
2584 char *s = suppress ? SvPV(sv, n_a) : NULL;
2585 char drive = (s ? *s : 0);
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),
2594 Perl_croak_nocontext("DosSuppressPopUps(%c) failed: %s", drive,
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;
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 */
2614 ULONG priority = 0, nesting; /* Shut down the warnings */
2620 if (!(_emx_env & 0x200)) /* DOS */
2621 return !_sleep2(ms);
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");
2629 if (ms >= switch_priority)
2630 switch_priority = 0;
2631 if (switch_priority) {
2632 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
2633 switch_priority = 0;
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.
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
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;
2653 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
2657 if ((badrc = DosAsyncTimer(ms,
2658 (HSEM) hevEvent1, /* Semaphore to post */
2659 &htimerEvent1))) /* Timer handler (returned) */
2660 e = "DosAsyncTimer";
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);
2668 if (switch_priority)
2669 rc = DosExitMustComplete(&nesting); /* Ignore errors */
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);
2678 if (e) ; /* Do nothing */
2679 else if (badrc == ERROR_INTERRUPT)
2682 e = "DosWaitEventSem";
2683 if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
2684 e = "DosCloseEventSem";
2688 os2cp_croak(badrc, e);
2692 XS(XS_OS2_ms_sleep) /* for testing only... */
2697 if (items > 2 || items < 1)
2698 Perl_croak_nocontext("Usage: OS2::ms_sleep(wait_ms [, high_priority_limit])");
2700 lim = items > 1 ? SvUV(ST(1)) : ms + 1;
2701 async_mssleep(ms, lim);
2705 ULONG (*pDosTmrQueryFreq) (PULONG);
2706 ULONG (*pDosTmrQueryTime) (unsigned long long *);
2712 unsigned long long count;
2716 Perl_croak_nocontext("Usage: OS2::Timer()");
2718 *(PFN*)&pDosTmrQueryFreq = loadByOrdinal(ORD_DosTmrQueryFreq, 0);
2719 *(PFN*)&pDosTmrQueryTime = loadByOrdinal(ORD_DosTmrQueryTime, 0);
2720 MUTEX_LOCK(&perlos2_state_mutex);
2722 if (CheckOSError(pDosTmrQueryFreq(&freq)))
2723 croak_with_os2error("DosTmrQueryFreq");
2724 MUTEX_UNLOCK(&perlos2_state_mutex);
2726 if (CheckOSError(pDosTmrQueryTime(&count)))
2727 croak_with_os2error("DosTmrQueryTime");
2731 XSprePUSH; PUSHn(((NV)count)/freq);
2736 XS(XS_OS2_msCounter)
2741 Perl_croak_nocontext("Usage: OS2::msCounter()");
2745 XSprePUSH; PUSHu(msCounter());
2750 XS(XS_OS2__InfoTable)
2756 Perl_croak_nocontext("Usage: OS2::_infoTable([isLocal])");
2758 is_local = (int)SvIV(ST(0));
2762 XSprePUSH; PUSHu(InfoTable(is_local));
2767 static const char * const dc_fields[] = {
2776 "HORIZONTAL_RESOLUTION",
2777 "VERTICAL_RESOLUTION",
2781 "SMALL_CHAR_HEIGHT",
2785 "COLOR_TABLE_SUPPORT",
2787 "FOREGROUND_MIX_SUPPORT",
2788 "BACKGROUND_MIX_SUPPORT",
2789 "VIO_LOADABLE_FONTS",
2790 "WINDOW_BYTE_ALIGNMENT",
2798 "GRAPHICS_VECTOR_SUBSET",
2800 "ADDITIONAL_GRAPHICS",
2803 "GRAPHICS_CHAR_WIDTH",
2804 "GRAPHICS_CHAR_HEIGHT",
2805 "HORIZONTAL_FONT_RES",
2806 "VERTICAL_FONT_RES",
2809 "DEVICE_POLYSET_POINTS",
2813 DevCap_dc, DevCap_hwnd
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);
2827 Perl_croak_nocontext("Usage: OS2::DevCap()");
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;
2833 DEVOPENSTRUC doStruc= {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
2834 ULONG rc1 = NO_ERROR;
2836 static volatile int devcap_loaded;
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);
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 */
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");
2863 if (CheckWinError(pDevQueryCaps(hScreenDC,
2864 CAPS_FAMILY, /* W3 documented caps */
2865 CAPS_DEVICE_POLYSET_POINTS
2869 if (!items && CheckWinError(pDevCloseDC(hScreenDC)))
2870 Perl_warn_nocontext("DevCloseDC() failed: %s", os2error(Perl_rc));
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]);
2882 XSRETURN(2 * (CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1));
2885 LONG (*pWinQuerySysValue) (HWND hwndDesktop, LONG iSysValue);
2886 BOOL (*pWinSetSysValue) (HWND hwndDesktop, LONG iSysValue, LONG lValue);
2888 const char * const sv_keys[] = {
2940 "DESKTOPWORKAREAYTOP",
2941 "DESKTOPWORKAREAYBOTTOM",
2942 "DESKTOPWORKAREAXRIGHT",
2943 "DESKTOPWORKAREAXLEFT",
2953 "MENUROLLDOWNDELAY",
2956 "TASKLISTMOUSEACCESS",
2986 "PRINTSCREEN", /* 97, the last one on one of the DDK header */
2998 /* In recent DDK the limit is 108 */
3001 XS(XS_OS2_SysValues)
3005 Perl_croak_nocontext("Usage: OS2::SysValues(which = -1, hwndDesktop = HWND_DESKTOP)");
3007 int i = 0, j = 0, which = -1;
3008 HWND hwnd = HWND_DESKTOP;
3009 static volatile int sv_loaded;
3013 *(PFN*)&pWinQuerySysValue = loadByOrdinal(ORD_WinQuerySysValue, 0);
3018 hwnd = (HWND)SvIV(ST(1));
3020 which = (int)SvIV(ST(0));
3022 EXTEND(SP,2*C_ARRAY_LENGTH(sv_keys));
3023 while (i < C_ARRAY_LENGTH(sv_keys)) {
3025 RETVAL = pWinQuerySysValue(hwnd, i);
3027 && !(sv_keys[i][0] >= '0' && sv_keys[i][0] <= '9'
3028 && i <= SV_PRINTSCREEN) ) {
3031 if (i > SV_PRINTSCREEN)
3032 break; /* May be not present on older systems */
3033 croak_with_os2error("SysValues():");
3037 ST(j) = sv_newmortal();
3038 sv_setpv(ST(j++), sv_keys[i]);
3039 ST(j) = sv_newmortal();
3040 sv_setiv(ST(j++), RETVAL);
3048 RETVAL = pWinQuerySysValue(hwnd, which);
3052 croak_with_os2error("SysValues():");
3054 XSprePUSH; PUSHi((IV)RETVAL);
3059 XS(XS_OS2_SysValues_set)
3062 if (items < 2 || items > 3)
3063 Perl_croak_nocontext("Usage: OS2::SysValues_set(which, val, hwndDesktop = HWND_DESKTOP)");
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;
3071 *(PFN*)&pWinSetSysValue = loadByOrdinal(ORD_WinSetSysValue, 0);
3076 hwnd = (HWND)SvIV(ST(2));
3077 if (CheckWinError(pWinSetSysValue(hwnd, which, val)))
3078 croak_with_os2error("SysValues_set()");
3083 #define QSV_MAX_WARP3 QSV_MAX_COMP_LENGTH
3085 static const char * const si_fields[] = {
3087 "MAX_TEXT_SESSIONS",
3091 "DYN_PRI_VARIATION",
3109 "FOREGROUND_FS_SESSION",
3110 "FOREGROUND_PROCESS", /* Warp 3 toolkit defines up to this */
3115 "VIRTUALADDRESSLIMIT",
3116 "INT10ENABLED", /* From $TOOLKIT-ddk\DDK\video\rel\os2c\include\base\os2\bsedos.h */
3123 Perl_croak_nocontext("Usage: OS2::SysInfo()");
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;
3130 if (CheckOSError(DosQuerySysInfo(1L, /* Request documented system */
3131 last, /* info for Warp 3 */
3134 croak_with_os2error("DosQuerySysInfo() failed");
3135 while (last++ <= C_ARRAY_LENGTH(si)) {
3136 if (CheckOSError(DosQuerySysInfo(last, last, /* One entry only */
3139 if (Perl_rc != ERROR_INVALID_PARAMETER)
3140 croak_with_os2error("DosQuerySysInfo() failed");
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]);
3157 XS(XS_OS2_SysInfoFor)
3160 int count = (items == 2 ? (int)SvIV(ST(1)) : 1);
3162 if (items < 1 || items > 2)
3163 Perl_croak_nocontext("Usage: OS2::SysInfoFor(id[,count])");
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 */
3169 int start = (int)SvIV(ST(0));
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,
3177 croak_with_os2error("DosQuerySysInfo() failed");
3180 ST(i) = sv_newmortal();
3181 sv_setiv(ST(i), si[i]);
3188 XS(XS_OS2_BootDrive)
3192 Perl_croak_nocontext("Usage: OS2::BootDrive()");
3194 ULONG si[1] = {0}; /* System Information Data Buffer */
3195 APIRET rc = NO_ERROR; /* Return code */
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;
3212 if (items > 2) /* Defaults as for WinAlarm(ERROR) */
3213 Perl_croak_nocontext("Usage: OS2::Beep(freq = 440, ms = 100)");
3215 ULONG freq = (items > 0 ? (ULONG)SvUV(ST(0)) : 440);
3216 ULONG ms = (items > 1 ? (ULONG)SvUV(ST(1)) : 100);
3219 if (CheckOSError(DosBeep(freq, ms)))
3220 croak_with_os2error("SysValues_set()");
3231 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
3233 bool serve = SvOK(ST(0));
3234 unsigned long pmq = perl_hmq_GET(serve);
3237 XSprePUSH; PUSHi((IV)pmq);
3242 XS(XS_OS2_UnMorphPM)
3246 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
3248 bool serve = SvOK(ST(0));
3250 perl_hmq_UNSET(serve);
3255 XS(XS_OS2_Serve_Messages)
3259 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
3261 bool force = SvOK(ST(0));
3262 unsigned long cnt = Perl_Serve_Messages(force);
3265 XSprePUSH; PUSHi((IV)cnt);
3270 XS(XS_OS2_Process_Messages)
3273 if (items < 1 || items > 2)
3274 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
3276 bool force = SvOK(ST(0));
3284 (void)SvIV(sv); /* Force SvIVX */
3286 Perl_croak_nocontext("Can't upgrade count to IV");
3288 cnt = Perl_Process_Messages(force, &cntr);
3291 cnt = Perl_Process_Messages(force, NULL);
3293 XSprePUSH; PUSHi((IV)cnt);
3298 XS(XS_Cwd_current_drive)
3302 Perl_croak_nocontext("Usage: Cwd::current_drive()");
3307 RETVAL = current_drive();
3308 sv_setpvn(TARG, (char *)&RETVAL, 1);
3309 XSprePUSH; PUSHTARG;
3314 XS(XS_Cwd_sys_chdir)
3318 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
3321 char * path = (char *)SvPV(ST(0),n_a);
3324 RETVAL = sys_chdir(path);
3325 ST(0) = boolSV(RETVAL);
3326 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3331 XS(XS_Cwd_change_drive)
3335 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
3338 char d = (char)*SvPV(ST(0),n_a);
3341 RETVAL = change_drive(d);
3342 ST(0) = boolSV(RETVAL);
3343 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3348 XS(XS_Cwd_sys_is_absolute)
3352 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
3355 char * path = (char *)SvPV(ST(0),n_a);
3358 RETVAL = sys_is_absolute(path);
3359 ST(0) = boolSV(RETVAL);
3360 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3365 XS(XS_Cwd_sys_is_rooted)
3369 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
3372 char * path = (char *)SvPV(ST(0),n_a);
3375 RETVAL = sys_is_rooted(path);
3376 ST(0) = boolSV(RETVAL);
3377 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3382 XS(XS_Cwd_sys_is_relative)
3386 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
3389 char * path = (char *)SvPV(ST(0),n_a);
3392 RETVAL = sys_is_relative(path);
3393 ST(0) = boolSV(RETVAL);
3394 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3403 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
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));
3419 XS(XS_Cwd_sys_abspath)
3423 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path = '.', dir = NULL)");
3426 char * path = items ? (char *)SvPV(ST(0),n_a) : ".";
3427 char * dir, *s, *t, *e;
3436 dir = (char *)SvPV(ST(1),n_a);
3438 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
3442 if (_abspath(p, path, MAXPATHLEN) == 0) {
3448 /* Absolute with drive: */
3449 if ( sys_is_absolute(path) ) {
3450 if (_abspath(p, path, MAXPATHLEN) == 0) {
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];
3460 /* Need to prepend the drive. */
3463 Copy(path, p1 + 2, strlen(path) + 1, char);
3465 if (_abspath(p, p1, MAXPATHLEN) == 0) {
3470 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
3476 /* Either path is relative, or starts with a drive letter. */
3477 /* If the path starts with a drive letter, then dir is
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
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())) {
3491 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
3492 RETVAL = p; goto done;
3494 RETVAL = NULL; goto done;
3498 /* Need to prepend the absolute path of dir. */
3499 char p1[MAXPATHLEN];
3501 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
3504 if (p1[ l - 1 ] != '/') {
3508 Copy(path, p1 + l, strlen(path) + 1, char);
3509 if (_abspath(p, p1, MAXPATHLEN) == 0) {
3523 /* Backslashes are already converted to slashes. */
3524 /* Remove trailing slashes */
3526 while (l > 0 && RETVAL[l-1] == '/')
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);
3534 /* Do not worry about multibyte chars here, this would contradict the
3535 eventual UTFization, and currently most other places break too... */
3537 if (s[0] == t[-1] && s[0] == '/')
3538 s++; /* Skip duplicate / */
3544 SvCUR_set(sv, t - SvPVX(sv));
3546 #ifndef INCOMPLETE_TAINTS
3548 SvTAINTED_on(ST(0));
3553 typedef APIRET (*PELP)(PSZ path, ULONG type);
3555 /* Kernels after 2000/09/15 understand this too: */
3556 #ifndef LIBPATHSTRICT
3557 # define LIBPATHSTRICT 3
3561 ExtLIBPATH(ULONG ord, PSZ path, IV type, int fatal)
3564 PFN f = loadByOrdinal(ord, fatal); /* if fatal: load or die! */
3566 if (!f) /* Impossible with fatal */
3571 what = BEGIN_LIBPATH;
3573 what = LIBPATHSTRICT;
3574 return (*(PELP)f)(path, what);
3577 #define extLibpath(to,type, fatal) \
3578 (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type), fatal)) ? NULL : (to) )
3580 #define extLibpath_set(p,type, fatal) \
3581 (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type), fatal)))
3584 early_error(char *msg1, char *msg2, char *msg3)
3585 { /* Buffer overflow detected; there is very little we can do... */
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);
3594 XS(XS_Cwd_extLibpath)
3597 if (items < 0 || items > 1)
3598 Perl_croak_nocontext("Usage: OS2::extLibpath(type = 0)");
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");
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;
3627 XS(XS_Cwd_extLibpath_set)
3630 if (items < 1 || items > 2)
3631 Perl_croak_nocontext("Usage: OS2::extLibpath_set(s, type = 0)");
3634 char * s = (char *)SvPV(ST(0),n_a);
3645 RETVAL = extLibpath_set(s, type, 1); /* Make errors fatal */
3646 ST(0) = boolSV(RETVAL);
3647 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3653 fill_extLibpath(int type, char *pre, char *post, int replace, char *msg)
3655 char buf[2048], *to = buf, buf1[300], *s;
3662 pre = dir_subst(pre, strlen(pre), buf1, sizeof buf1, dir_subst_pathlike, msg);
3664 return ERROR_INVALID_PARAMETER;
3666 if (l >= sizeof(buf)/2)
3667 return ERROR_BUFFER_OVERFLOW;
3671 *s = '\\'; /* Be extra causious */
3673 if (!l || to[l-1] != ';')
3679 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
3680 rc = ExtLIBPATH(ORD_DosQueryExtLibpath, to, type, 0); /* Do not croak */
3683 if (to[0] == 1 && to[1] == 0)
3684 return ERROR_INVALID_PARAMETER;
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] != ';')
3693 post = dir_subst(post, strlen(post), buf1, sizeof buf1, dir_subst_pathlike, msg);
3695 return ERROR_INVALID_PARAMETER;
3697 if (l + to - buf >= sizeof(buf) - 1)
3698 return ERROR_BUFFER_OVERFLOW;
3702 *s = '\\'; /* Be extra causious */
3703 memcpy(to, post, l);
3704 if (!l || to[l-1] != ';')
3709 rc = ExtLIBPATH(ORD_DosSetExtLibpath, buf, type, 0); /* Do not croak */
3713 /* Input: Address, BufLen
3715 DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
3716 ULONG * Offset, ULONG Address);
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))
3725 module_name_at(void *pp, enum module_name_how how)
3728 char buf[MAXPATHLEN];
3731 ULONG obj, offset, rc, addr = (ULONG)pp;
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");
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);
3743 if ( how != mod_name_shortname
3744 && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) )
3745 return &PL_sv_undef;
3751 return newSVpv(buf, 0);
3755 module_name_of_cv(SV *cv, enum module_name_how how)
3757 if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv))) {
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");
3766 return module_name_at(CvXSUB(SvRV(cv)), how);
3773 Perl_croak(aTHX_ "Usage: OS2::DLLname( [ how, [\\&xsub] ] )");
3779 how = mod_name_full;
3781 how = (int)SvIV(ST(0));
3784 RETVAL = module_name(how);
3786 RETVAL = module_name_of_cv(ST(1), how);
3793 DeclOSFuncByORD(INT, _Dos32QueryHeaderInfo, ORD_Dos32QueryHeaderInfo,
3794 (ULONG r1, ULONG r2, PVOID buf, ULONG szbuf, ULONG fnum),
3795 (r1, r2, buf, szbuf, fnum))
3797 XS(XS_OS2__headerInfo)
3800 if (items > 4 || items < 2)
3801 Perl_croak(aTHX_ "Usage: OS2::_headerInfo(req,size[,handle,[offset]])");
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);
3809 Perl_croak(aTHX_ "OS2::_headerInfo(): unexpected size: %d", (int)size);
3810 ST(0) = newSVpvn("",0);
3811 SvGROW(ST(0), size + 1);
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);
3823 #define DQHI_QUERYLIBPATHSIZE 4
3824 #define DQHI_QUERYLIBPATH 5
3830 Perl_croak(aTHX_ "Usage: OS2::libPath()");
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,
3840 ST(0) = newSVpvn("",0);
3841 SvGROW(ST(0), size + 1);
3844 /* We should be careful: apparently, this entry point does not
3845 pay attention to the size argument, so may overwrite
3847 if (!_Dos32QueryHeaderInfo(0, 0, SvPV(ST(0), n_a), size,
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);
3857 #define get_control87() _control87(0,0)
3858 #define set_control87 _control87
3860 XS(XS_OS2__control87)
3864 Perl_croak(aTHX_ "Usage: OS2::_control87(new,mask)");
3866 unsigned new = (unsigned)SvIV(ST(0));
3867 unsigned mask = (unsigned)SvIV(ST(1));
3871 RETVAL = _control87(new, mask);
3872 XSprePUSH; PUSHi((IV)RETVAL);
3882 if (items < 0 || items > 1)
3883 Perl_croak(aTHX_ "Usage: OS2::mytype([which])");
3885 which = (int)SvIV(ST(0));
3892 RETVAL = os2_mytype; /* Reset after fork */
3895 RETVAL = os2_mytype_ini; /* Before any fork */
3898 RETVAL = Perl_os2_initial_mode; /* Before first morphing */
3901 RETVAL = my_type(); /* Morphed type */
3904 Perl_croak(aTHX_ "OS2::mytype(which): unknown which=%d", which);
3906 XSprePUSH; PUSHi((IV)RETVAL);
3912 XS(XS_OS2_mytype_set)
3918 type = (int)SvIV(ST(0));
3920 Perl_croak(aTHX_ "Usage: OS2::mytype_set(type)");
3926 XS(XS_OS2_get_control87)
3930 Perl_croak(aTHX_ "Usage: OS2::get_control87()");
3935 RETVAL = get_control87();
3936 XSprePUSH; PUSHi((IV)RETVAL);
3942 XS(XS_OS2_set_control87)
3945 if (items < 0 || items > 2)
3946 Perl_croak(aTHX_ "Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
3956 new = (unsigned)SvIV(ST(0));
3962 mask = (unsigned)SvIV(ST(1));
3965 RETVAL = set_control87(new, mask);
3966 XSprePUSH; PUSHi((IV)RETVAL);
3971 XS(XS_OS2_incrMaxFHandles) /* DosSetRelMaxFH */
3974 if (items < 0 || items > 1)
3975 Perl_croak(aTHX_ "Usage: OS2::incrMaxFHandles(delta = 0)");
3984 delta = (LONG)SvIV(ST(0));
3986 if (CheckOSError(DosSetRelMaxFH(&delta, &RETVAL)))
3987 croak_with_os2error("OS2::incrMaxFHandles(): DosSetRelMaxFH() error");
3988 XSprePUSH; PUSHu((UV)RETVAL);
3996 char *file = __FILE__;
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);
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);
4047 sv_setiv(GvSV(gv), 1);
4049 gv = gv_fetchpv("OS2::is_static", TRUE, SVt_PV);
4052 sv_setiv(GvSV(gv), 1);
4054 gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV);
4056 sv_setiv(GvSV(gv), exe_is_aout());
4057 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
4059 sv_setiv(GvSV(gv), _emx_rev);
4060 sv_setpv(GvSV(gv), _emx_vprt);
4062 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
4064 sv_setiv(GvSV(gv), _emx_env);
4065 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
4067 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
4068 gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
4070 sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
4075 extern void _emx_init(void*);
4077 static void jmp_out_of_atexit(void);
4079 #define FORCE_EMX_INIT_CONTRACT_ARGV 1
4080 #define FORCE_EMX_INIT_INSTALL_ATEXIT 2
4083 my_emx_init(void *layout) {
4084 static volatile void *old_esp = 0; /* Cannot be on stack! */
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 */
4095 "popf\n" : : "r" (layout), "m" (old_esp) );
4098 struct layout_table_t {
4119 static ULONG osv_res; /* Cannot be on stack! */
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 */
4125 "call ___os_version\n"
4128 "popf\n" : "=m" (osv_res) );
4134 force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags)
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;
4142 ULONG rc, error = 0, out;
4144 static struct layout_table_t layout_table;
4146 char buf[48*1024]; /* _emx_init() requires 32K, cmd.exe has 64K only */
4148 EXCEPTIONREGISTRATIONRECORD xreg;
4152 layout_table.os2_dll = (ULONG)&os2_dll_fake;
4153 layout_table.flags = 0x02000002; /* flags: application, OMF */
4155 DosGetInfoBlocks(&tib, &pib);
4156 oldarg = pib->pib_pchcmd;
4157 oldenv = pib->pib_pchenv;
4158 oldstack = tib->tib_pstack;
4159 oldstackend = tib->tib_pstacklimit;
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");
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. */
4173 newstack = alloca(sizeof(*newstack));
4174 /* Emulate the stack probe */
4175 s = ((char*)newstack) + sizeof(*newstack);
4176 while (s > (char*)newstack) {
4181 /* Reassigning stack is documented to work */
4182 tib->tib_pstack = (void*)newstack;
4183 tib->tib_pstacklimit = (void*)((char*)newstack + sizeof(*newstack));
4185 /* Can't just call emx_init(), since it moves the stack pointer */
4186 my_emx_init((void*)&layout_table);
4188 /* Remove the exception handler, cannot use it - too low on the stack.
4189 Check whether it is inside the new stack. */
4191 if (tib->tib_pexchain >= tib->tib_pstacklimit
4192 || tib->tib_pexchain < tib->tib_pstack) {
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);
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));
4206 rc = DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)tib->tib_pexchain);
4208 sprintf(buf + strlen(buf),
4209 "warning: DosUnsetExceptionHandler rc=%#lx=%lu\n", rc, rc);
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);
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 */
4223 emx_exception_init = 1; /* Do it around spawn*() calls */
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;
4233 DosWrite(2, buf, strlen(buf), &out);
4239 jmp_out_of_atexit(void)
4241 if (longjmp_at_exit)
4242 longjmp(at_exit_buf, 1);
4245 extern void _CRT_term(void);
4248 Perl_OS2_term(void **p, int exitstatus, int flags)
4250 if (!emx_runtime_secondary)
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 */
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" */
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 */
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... */
4282 #include <emx/startup.h>
4284 extern ULONG __os_version(); /* See system.doc */
4287 check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg)
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;
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.
4297 if (_environ != NULL)
4298 return; /* Properly initialized */
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);
4305 rc1 = DosEnterCritSec();
4307 rc = DosCreateMutexSem(NULL, &hmtx_emx_init, 0, TRUE); /*Create owned*/
4312 hmtx_emx_init = NULLHANDLE;
4314 if (rc1 == NO_ERROR)
4316 DosExitMustComplete(&count);
4318 while (maybe_inited) { /* Other thread did or is doing the same now */
4321 rc = DosRequestMutexSem(hmtx_emx_init,
4322 (ULONG) SEM_INDEFINITE_WAIT); /* Timeout (none) */
4323 if (rc == ERROR_INTERRUPT)
4325 if (rc != NO_ERROR) {
4330 "panic: EMX backdoor init: DosRequestMutexSem error: %lu=%#lx\n", rc, rc);
4331 DosWrite(2, buf, strlen(buf), &out);
4334 DosReleaseMutexSem(hmtx_emx_init);
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();
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
4350 v_crt = (_osmajor | _osminor);
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;
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() */
4368 if (env == NULL) { /* Fetch from the process info block */
4374 DosGetInfoBlocks(&tib, &pib);
4375 e = pib->pib_pchenv;
4376 while (*e) { /* Get count */
4378 e = e + strlen(e) + 1;
4380 New(1307, env, c + 1, char*);
4382 e = pib->pib_pchenv;
4385 e = e + strlen(e) + 1;
4389 _environ = _org_environ = env;
4392 DosReleaseMutexSem(hmtx_emx_init);
4395 #define ENTRY_POINT 0x10000
4400 struct layout_table_t *layout;
4401 if (emx_wasnt_initialized)
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 */
4413 Copy((char*)(ENTRY_POINT+1), &layout, 1, struct layout_table_t*);
4414 return !(layout->flags & 2);
4418 Perl_OS2_init(char **env)
4420 Perl_OS2_init3(env, 0, 0);
4424 Perl_OS2_init3(char **env, void **preg, int flags)
4429 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
4432 check_emx_runtime(env, (EXCEPTIONREGISTRATIONRECORD *)preg);
4435 OS2_Perl_data.xs_init = &Xs_OS2_init;
4436 if (perl_sh_installed) {
4437 int l = strlen(perl_sh_installed);
4439 New(1304, 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 New(1304, 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;
4448 while (l && (shell[l-1] == '/' || shell[l-1] == '\\'))
4450 New(1304, 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] = '/';
4457 #if defined(USE_5005THREADS) || defined(USE_ITHREADS)
4458 MUTEX_INIT(&start_thread_mutex);
4459 MUTEX_INIT(&perlos2_state_mutex);
4461 os2_mytype = my_type(); /* Do it before morphing. Needed? */
4462 os2_mytype_ini = os2_mytype;
4463 Perl_os2_initial_mode = -1; /* Uninit */
4465 s = getenv("PERL_BEGINLIBPATH");
4467 rc = fill_extLibpath(0, s, NULL, 1, "PERL_BEGINLIBPATH");
4469 rc = fill_extLibpath(0, getenv("PERL_PRE_BEGINLIBPATH"), getenv("PERL_POST_BEGINLIBPATH"), 0, "PERL_(PRE/POST)_BEGINLIBPATH");
4471 s = getenv("PERL_ENDLIBPATH");
4473 rc = fill_extLibpath(1, s, NULL, 1, "PERL_ENDLIBPATH");
4475 rc = fill_extLibpath(1, getenv("PERL_PRE_ENDLIBPATH"), getenv("PERL_POST_ENDLIBPATH"), 0, "PERL_(PRE/POST)_ENDLIBPATH");
4480 snprintf(buf, sizeof buf, "Error setting BEGIN/ENDLIBPATH: %s\n",
4482 DosWrite(2, buf, strlen(buf), &rc);
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);
4494 static ULONG max_fh = 0;
4496 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
4497 if (fd >= max_fh) { /* Renew */
4500 if (DosSetRelMaxFH(&delta, &max_fh)) /* Assume it OK??? */
4506 /* Kernels up to Oct 2003 trap on (invalid) dup(max_fh); [off-by-one + double fault]. */
4508 dup2(int from, int to)
4510 if (fd_ok(from < to ? to : from))
4511 return _dup2(from, to);
4529 my_tmpnam (char *str)
4531 char *p = getenv("TMP"), *tpath;
4533 if (!p) p = getenv("TEMP");
4534 tpath = tempnam(p, "pltmp");
4548 if (s.st_mode & S_IWOTH) {
4551 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
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. */
4561 my_rmdir (__const__ char *s)
4565 STRLEN l = strlen(s);
4568 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
4570 New(1305, buf, l + 1, char);
4572 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
4586 my_mkdir (__const__ char *s, long perm)
4590 STRLEN l = strlen(s);
4593 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
4595 New(1305, buf, l + 1, char);
4597 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
4602 rc = mkdir(s, perm);
4610 /* This code was contributed by Rocco Caputo. */
4612 my_flock(int handle, int o)
4614 FILELOCK rNull, rFull;
4615 ULONG timeout, handle_type, flag_word;
4617 int blocking, shared;
4618 static int use_my_flock = -1;
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");
4625 use_my_flock = atoi(s);
4629 MUTEX_UNLOCK(&perlos2_state_mutex);
4631 if (!(_emx_env & 0x200) || !use_my_flock)
4632 return flock(handle, o); /* Delegate to EMX. */
4634 /* is this a file? */
4635 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
4636 (handle_type & 0xFF))
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);
4655 case ERROR_INVALID_HANDLE:
4658 case ERROR_SHARING_BUFFER_EXCEEDED:
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:
4668 case ERROR_INTERRUPT:
4676 /* lock may block */
4677 if (o & (LOCK_SH | LOCK_EX)) {
4678 /* for blocking operations */
4692 case ERROR_INVALID_HANDLE:
4695 case ERROR_SHARING_BUFFER_EXCEEDED:
4698 case ERROR_LOCK_VIOLATION:
4700 errno = EWOULDBLOCK;
4704 case ERROR_INVALID_PARAMETER:
4705 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
4706 case ERROR_READ_LOCKS_NOT_SUPPORTED:
4709 case ERROR_INTERRUPT:
4716 /* give away timeslice */
4728 if (_my_pwent == -1) {
4729 char *s = getenv("USE_PERL_PWENT");
4731 _my_pwent = atoi(s);
4745 if (!use_my_pwent()) {
4746 setpwent(); /* Delegate to EMX. */
4755 if (!use_my_pwent()) {
4756 endpwent(); /* Delegate to EMX. */
4764 if (!use_my_pwent())
4765 return getpwent(); /* Delegate to EMX. */
4767 return 0; /* Return one entry only */
4786 return 0; /* Return one entry only */
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";
4796 static struct passwd *
4797 passw_wrap(struct passwd *p)
4801 if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
4804 s = getenv("PW_PASSWD");
4806 s = (char*)pw_p; /* Make match impossible */
4813 my_getpwuid (uid_t id)
4815 return passw_wrap(getpwuid(id));
4819 my_getpwnam (__const__ char *n)
4821 return passw_wrap(getpwnam(n));
4825 gcvt_os2 (double value, int digits, char *buffer)
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. */
4833 buggy = (absv < 1000 && (absv >= 10 || (absv > 1 && floor(absv) != absv)));
4838 sprintf(pat, "%%.%dg", digits);
4839 sprintf(buffer, pat, value);
4842 return gcvt (value, digits, buffer);
4846 int fork_with_resources()
4848 #if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
4850 void *ctx = PERL_GET_CONTEXT;
4852 unsigned fpflag = _control87(0,0);
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 */
4861 { /* Reload loaded-on-demand DLLs */
4862 struct dll_handle_t *dlls = dll_handles;
4864 while (dlls->modname) {
4865 char dllname[260], fail[260];
4868 if (!dlls->handle) { /* Was not loaded */
4872 /* It was loaded in the parent. We need to reload it. */
4874 rc = DosQueryModuleName(dlls->handle, sizeof(dllname), dllname);
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);
4881 rc = DosLoadModule(fail, sizeof fail, dllname, &dlls->handle);
4883 Perl_warn_nocontext("Can't load DLL `%s', possible problematic module `%s'",
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
4895 if (Perl_os2_initial_mode != -1
4896 && Perl_os2_initial_mode != os2_mytype) {
4901 (void)_obtain_Perl_HAB;
4902 if (Perl_hmq_refcnt) {
4905 Create_HMQ(Perl_hmq_servers != 0,
4906 "Cannot create a message queue on fork");
4909 /* We may have loaded some modules */
4910 _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
4915 /* APIRET APIENTRY DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal); */
4917 ULONG _THUNK_FUNCTION(Dos16GetInfoSeg)(USHORT *pGlobal, USHORT *pLocal);
4920 myDosGetInfoSeg(PGINFOSEG *pGlobal, PLINFOSEG *pLocal)
4923 USHORT gSel, lSel; /* Will not cross 64K boundary */
4926 (_THUNK_PROLOG (4+4);
4927 _THUNK_FLAT (&gSel);
4928 _THUNK_FLAT (&lSel);
4929 _THUNK_CALL (Dos16GetInfoSeg)));
4932 *pGlobal = MAKEPGINFOSEG(gSel);
4933 *pLocal = MAKEPLINFOSEG(lSel);
4942 MUTEX_LOCK(&perlos2_state_mutex);
4944 rc = myDosGetInfoSeg(&gTable, &lTable);
4945 MUTEX_UNLOCK(&perlos2_state_mutex);
4946 os2cp_croak(rc, "Dos16GetInfoSeg");
4951 { /* XXXX Is not lTable thread-specific? */
4954 return gTable->SIS_MsCount;
4958 InfoTable(int local)
4962 return local ? (ULONG)lTable : (ULONG)gTable;