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 Newxz(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 = CheckOSError(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 Newx(pbuffer, buf_len, char);
793 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
794 rc = QuerySysState(flags, pid, pbuffer, buf_len);
795 while (rc == ERROR_BUFFER_OVERFLOW) {
796 Renew(pbuffer, buf_len *= 2, char);
797 rc = QuerySysState(flags, pid, pbuffer, buf_len);
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... */
1143 struct stat statbuf;
1145 /* Special case: maybe from -Zexe build, so
1146 there is an executable around (contrary to
1147 documentation, DosQueryAppType sometimes (?)
1148 does not append ".exe", so we could have
1149 reached this place). */
1150 sv_catpv(scrsv, ".exe");
1151 PL_Argv[0] = scr = SvPV(scrsv, n_a); /* Reload */
1152 if (PerlLIO_stat(scr,&statbuf) >= 0
1153 && !S_ISDIR(statbuf.st_mode)) { /* Found */
1157 } else { /* Restore */
1158 SvCUR_set(scrsv, SvCUR(scrsv) - 4);
1162 if (PerlIO_close(file) != 0) { /* Failure */
1164 if (ckWARN(WARN_EXEC))
1165 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s",
1166 scr, Strerror(errno));
1167 buf = ""; /* Not #! */
1170 if (buf[0] == '#') {
1173 } else if (buf[0] == 'e') {
1174 if (strEQs(buf, "extproc")
1177 } else if (buf[0] == 'E') {
1178 if (strEQs(buf, "EXTPROC")
1183 buf = ""; /* Not #! */
1191 /* Do better than pdksh: allow a few args,
1192 strip trailing whitespace. */
1202 while (*s && !isSPACE(*s))
1209 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Too many args on %.*s line of \"%s\"",
1210 s1 - buf, buf, scr);
1214 /* Can jump from far, buf/file invalid if force_shell: */
1218 const char *exec_args[2];
1221 || (!buf[0] && file)) { /* File without magic */
1222 /* In fact we tried all what pdksh would
1223 try. There is no point in calling
1224 pdksh, we may just emulate its logic. */
1225 char *shell = getenv("EXECSHELL");
1226 char *shell_opt = NULL;
1232 shell = getenv("OS2_SHELL");
1233 if (inicmd) { /* No spaces at start! */
1235 while (*s && !isSPACE(*s)) {
1237 inicmd = NULL; /* Cannot use */
1245 /* Dosish shells will choke on slashes
1246 in paths, fortunately, this is
1247 important for zeroth arg only. */
1254 /* If EXECSHELL is set, we do not set */
1257 shell = ((_emx_env & 0x200)
1259 : "c:/command.com");
1260 nargs = shell_opt ? 2 : 1; /* shell file args */
1261 exec_args[0] = shell;
1262 exec_args[1] = shell_opt;
1264 if (nargs == 2 && inicmd) {
1265 /* Use the original cmd line */
1266 /* XXXX This is good only until we refuse
1267 quoted arguments... */
1268 PL_Argv[0] = inicmd;
1271 } else if (!buf[0] && inicmd) { /* No file */
1272 /* Start with the original cmdline. */
1273 /* XXXX This is good only until we refuse
1274 quoted arguments... */
1276 PL_Argv[0] = inicmd;
1278 nargs = 2; /* shell -c */
1281 while (a[1]) /* Get to the end */
1283 a++; /* Copy finil NULL too */
1284 while (a >= PL_Argv) {
1285 *(a + nargs) = *a; /* PL_Argv was preallocated to be
1289 while (--nargs >= 0) /* XXXX Discard const... */
1290 PL_Argv[nargs] = (char*)argsp[nargs];
1291 /* Enable pathless exec if #! (as pdksh). */
1292 pass = (buf[0] == '#' ? 2 : 3);
1296 /* Not found: restore errno */
1299 } else if (errno == ENOEXEC) { /* Cannot transfer `real_name' via shell. */
1300 if (rc < 0 && ckWARN(WARN_EXEC))
1301 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s script `%s' with ARGV[0] being `%s'",
1302 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
1303 ? "spawn" : "exec"),
1304 real_name, PL_Argv[0]);
1306 } else if (errno == ENOENT) { /* Cannot transfer `real_name' via shell. */
1307 if (rc < 0 && ckWARN(WARN_EXEC))
1308 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s `%s' with ARGV[0] being `%s' (looking for executables only, not found)",
1309 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
1310 ? "spawn" : "exec"),
1311 real_name, PL_Argv[0]);
1314 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
1315 char *no_dir = strrchr(PL_Argv[0], '/');
1317 /* Do as pdksh port does: if not found with /, try without
1320 PL_Argv[0] = no_dir + 1;
1325 if (rc < 0 && ckWARN(WARN_EXEC))
1326 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s\n",
1327 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
1328 ? "spawn" : "exec"),
1329 real_name, Strerror(errno));
1331 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
1332 && ((trueflag & 0xFF) == P_WAIT))
1336 if (new_stderr != -1) { /* How can we use error codes? */
1337 dup2(new_stderr, 2);
1339 fcntl(2, F_SETFD, fl_stderr);
1340 } else if (nostderr)
1345 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
1347 do_spawn3(pTHX_ char *cmd, int execf, int flag)
1351 char *shell, *copt, *news = NULL;
1352 int rc, seenspace = 0, mergestderr = 0;
1355 if ((shell = getenv("EMXSHELL")) != NULL)
1357 else if ((shell = getenv("SHELL")) != NULL)
1359 else if ((shell = getenv("COMSPEC")) != NULL)
1364 /* Consensus on perl5-porters is that it is _very_ important to
1365 have a shell which will not change between computers with the
1366 same architecture, to avoid "action on a distance".
1367 And to have simple build, this shell should be sh. */
1372 while (*cmd && isSPACE(*cmd))
1375 if (strEQs(cmd,"/bin/sh") && isSPACE(cmd[7])) {
1376 STRLEN l = strlen(PL_sh_path);
1378 Newx(news, strlen(cmd) - 7 + l + 1, char);
1379 strcpy(news, PL_sh_path);
1380 strcpy(news + l, cmd + 7);
1384 /* save an extra exec if possible */
1385 /* see if there are shell metacharacters in it */
1387 if (*cmd == '.' && isSPACE(cmd[1]))
1390 if (strEQs(cmd,"exec") && isSPACE(cmd[4]))
1393 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
1397 for (s = cmd; *s; s++) {
1398 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
1399 if (*s == '\n' && s[1] == '\0') {
1402 } else if (*s == '\\' && !seenspace) {
1403 continue; /* Allow backslashes in names */
1404 } else if (*s == '>' && s >= cmd + 3
1405 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
1406 && isSPACE(s[-2]) ) {
1409 while (*t && isSPACE(*t))
1414 break; /* Allow 2>&1 as the last thing */
1417 /* We do not convert this to do_spawn_ve since shell
1418 should be smart enough to start itself gloriously. */
1420 if (execf == EXECF_TRUEEXEC)
1421 rc = execl(shell,shell,copt,cmd,(char*)0);
1422 else if (execf == EXECF_EXEC)
1423 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
1424 else if (execf == EXECF_SPAWN_NOWAIT)
1425 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
1426 else if (execf == EXECF_SPAWN_BYFLAG)
1427 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
1429 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
1430 if (execf == EXECF_SYNC)
1431 rc = spawnl(P_WAIT,shell,shell,copt,cmd,(char*)0);
1433 rc = result(aTHX_ P_WAIT,
1434 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
1435 if (rc < 0 && ckWARN(WARN_EXEC))
1436 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
1437 (execf == EXECF_SPAWN ? "spawn" : "exec"),
1438 shell, Strerror(errno));
1445 } else if (*s == ' ' || *s == '\t') {
1450 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
1451 Newx(PL_Argv, (s - cmd + 11) / 2, char*);
1452 PL_Cmd = savepvn(cmd, s-cmd);
1454 for (s = PL_Cmd; *s;) {
1455 while (*s && isSPACE(*s)) s++;
1458 while (*s && !isSPACE(*s)) s++;
1464 rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
1473 #define ASPAWN_WAIT 0
1474 #define ASPAWN_EXEC 1
1475 #define ASPAWN_NOWAIT 2
1477 /* Array spawn/exec. */
1479 os2_aspawn_4(pTHX_ SV *really, SV **args, I32 cnt, int execing)
1481 SV **argp = (SV **)args;
1482 SV **last = argp + cnt;
1485 int flag = P_WAIT, flag_set = 0;
1489 Newx(PL_Argv, cnt + 3, char*); /* 3 extra to expand #! */
1492 if (cnt > 1 && SvNIOKp(*argp) && !SvPOKp(*argp)) {
1493 flag = SvIVx(*argp);
1498 while (++argp < last) {
1500 *a++ = SvPVx(*argp, n_a);
1506 if ( flag_set && (a == PL_Argv + 1)
1507 && !really && execing == ASPAWN_WAIT ) { /* One arg? */
1508 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
1510 const int execf[3] = {EXECF_SPAWN, EXECF_EXEC, EXECF_SPAWN_NOWAIT};
1512 rc = do_spawn_ve(aTHX_ really, flag, execf[execing], NULL, 0);
1522 os2_do_aspawn(pTHX_ SV *really, SV **vmark, SV **vsp)
1524 return os2_aspawn_4(aTHX_ really, vmark + 1, vsp - vmark, ASPAWN_WAIT);
1529 Perl_do_aexec(pTHX_ SV* really, SV** vmark, SV** vsp)
1531 return os2_aspawn_4(aTHX_ really, vmark + 1, vsp - vmark, ASPAWN_EXEC);
1535 os2_do_spawn(pTHX_ char *cmd)
1537 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
1541 do_spawn_nowait(pTHX_ char *cmd)
1543 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
1547 Perl_do_exec(pTHX_ const char *cmd)
1549 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
1554 os2exec(pTHX_ char *cmd)
1556 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
1560 my_syspopen4(pTHX_ char *cmd, char *mode, I32 cnt, SV** args)
1564 I32 this, that, newfd;
1567 int fh_fl = 0; /* Pacify the warning */
1569 /* `this' is what we use in the parent, `that' in the child. */
1570 this = (*mode == 'w');
1574 taint_proper("Insecure %s%s", "EXEC");
1578 /* Now we need to spawn the child. */
1579 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1580 int new = dup(p[this]);
1587 newfd = dup(*mode == 'r'); /* Preserve std* */
1589 /* This cannot happen due to fh being bad after pipe(), since
1590 pipe() should have created fh 0 and 1 even if they were
1591 initially closed. But we closed p[this] before. */
1592 if (errno != EBADF) {
1599 fh_fl = fcntl(*mode == 'r', F_GETFD);
1600 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1601 dup2(p[that], *mode == 'r');
1604 /* Where is `this' and newfd now? */
1605 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1607 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1608 if (cnt) { /* Args: "Real cmd", before first arg, the last, execing */
1609 pid = os2_aspawn_4(aTHX_ NULL, args, cnt, ASPAWN_NOWAIT);
1611 pid = do_spawn_nowait(aTHX_ cmd);
1613 close(*mode == 'r'); /* It was closed initially */
1614 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1615 dup2(newfd, *mode == 'r'); /* Return std* back. */
1617 fcntl(*mode == 'r', F_SETFD, fh_fl);
1619 fcntl(*mode == 'r', F_SETFD, fh_fl);
1620 if (p[that] == (*mode == 'r'))
1626 if (p[that] < p[this]) { /* Make fh as small as possible */
1627 dup2(p[this], p[that]);
1631 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1632 (void)SvUPGRADE(sv,SVt_IV);
1634 PL_forkprocess = pid;
1635 return PerlIO_fdopen(p[this], mode);
1637 #else /* USE_POPEN */
1643 Perl_croak(aTHX_ "List form of piped open not implemented");
1646 res = popen(cmd, mode);
1648 char *shell = getenv("EMXSHELL");
1650 my_setenv("EMXSHELL", PL_sh_path);
1651 res = popen(cmd, mode);
1652 my_setenv("EMXSHELL", shell);
1654 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1655 (void)SvUPGRADE(sv,SVt_IV);
1656 SvIVX(sv) = -1; /* A cooky. */
1659 #endif /* USE_POPEN */
1664 my_syspopen(pTHX_ char *cmd, char *mode)
1666 return my_syspopen4(aTHX_ cmd, mode, 0, NULL);
1669 /******************************************************************/
1675 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1681 /*******************************************************************/
1682 /* not implemented in EMX 0.9d */
1684 char * ctermid(char *s) { return 0; }
1686 #ifdef MYTTYNAME /* was not in emx0.9a */
1687 void * ttyname(x) { return 0; }
1690 /*****************************************************************************/
1691 /* not implemented in C Set++ */
1694 int setuid(x) { errno = EINVAL; return -1; }
1695 int setgid(x) { errno = EINVAL; return -1; }
1698 /*****************************************************************************/
1699 /* stat() hack for char/block device */
1703 enum os2_stat_extra { /* EMX 0.9d fix 4 defines up to 0100000 */
1704 os2_stat_archived = 0x1000000, /* 0100000000 */
1705 os2_stat_hidden = 0x2000000, /* 0200000000 */
1706 os2_stat_system = 0x4000000, /* 0400000000 */
1707 os2_stat_force = 0x8000000, /* Do not ignore flags on chmod */
1710 #define OS2_STAT_SPECIAL (os2_stat_system | os2_stat_archived | os2_stat_hidden)
1713 massage_os2_attr(struct stat *st)
1715 if ( ((st->st_mode & S_IFMT) != S_IFREG
1716 && (st->st_mode & S_IFMT) != S_IFDIR)
1717 || !(st->st_attr & (FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM)))
1720 if ( st->st_attr & FILE_ARCHIVED )
1721 st->st_mode |= (os2_stat_archived | os2_stat_force);
1722 if ( st->st_attr & FILE_HIDDEN )
1723 st->st_mode |= (os2_stat_hidden | os2_stat_force);
1724 if ( st->st_attr & FILE_SYSTEM )
1725 st->st_mode |= (os2_stat_system | os2_stat_force);
1728 /* First attempt used DosQueryFSAttach which crashed the system when
1729 used with 5.001. Now just look for /dev/. */
1731 os2_stat(const char *name, struct stat *st)
1733 static int ino = SHRT_MAX;
1734 STRLEN l = strlen(name);
1736 if ( ( l < 8 || l > 9) || strnicmp(name, "/dev/", 5) != 0
1737 || ( stricmp(name + 5, "con") != 0
1738 && stricmp(name + 5, "tty") != 0
1739 && stricmp(name + 5, "nul") != 0
1740 && stricmp(name + 5, "null") != 0) ) {
1741 int s = stat(name, st);
1745 massage_os2_attr(st);
1749 memset(st, 0, sizeof *st);
1750 st->st_mode = S_IFCHR|0666;
1751 MUTEX_LOCK(&perlos2_state_mutex);
1752 st->st_ino = (ino-- & 0x7FFF);
1753 MUTEX_UNLOCK(&perlos2_state_mutex);
1759 os2_fstat(int handle, struct stat *st)
1761 int s = fstat(handle, st);
1765 massage_os2_attr(st);
1771 os2_chmod (const char *name, int pmode) /* Modelled after EMX src/lib/io/chmod.c */
1775 if (!(pmode & os2_stat_force))
1776 return chmod(name, pmode);
1778 attr = __chmod (name, 0, 0); /* Get attributes */
1781 if (pmode & S_IWRITE)
1782 attr &= ~FILE_READONLY;
1784 attr |= FILE_READONLY;
1786 attr &= ~(FILE_ARCHIVED | FILE_HIDDEN | FILE_SYSTEM);
1788 if ( pmode & os2_stat_archived )
1789 attr |= FILE_ARCHIVED;
1790 if ( pmode & os2_stat_hidden )
1791 attr |= FILE_HIDDEN;
1792 if ( pmode & os2_stat_system )
1793 attr |= FILE_SYSTEM;
1795 rc = __chmod (name, 1, attr);
1796 if (rc >= 0) rc = 0;
1802 #ifdef USE_PERL_SBRK
1804 /* SBRK() emulation, mostly moved to malloc.c. */
1807 sys_alloc(int size) {
1809 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1811 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1814 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1818 #endif /* USE_PERL_SBRK */
1822 const char *tmppath = TMPPATH1;
1827 char *p = getenv("TMP"), *tpath;
1830 if (!p) p = getenv("TEMP");
1831 if (!p) p = getenv("TMPDIR");
1834 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1838 strcpy(tpath + len + 1, TMPPATH1);
1845 XS(XS_File__Copy_syscopy)
1848 if (items < 2 || items > 3)
1849 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1852 char * src = (char *)SvPV(ST(0),n_a);
1853 char * dst = (char *)SvPV(ST(1),n_a);
1861 flag = (unsigned long)SvIV(ST(2));
1864 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1865 XSprePUSH; PUSHi((IV)RETVAL);
1870 /* APIRET APIENTRY DosReplaceModule (PCSZ pszOld, PCSZ pszNew, PCSZ pszBackup); */
1872 DeclOSFuncByORD(ULONG,replaceModule,ORD_DosReplaceModule,
1873 (char *old, char *new, char *backup), (old, new, backup))
1875 XS(XS_OS2_replaceModule); /* prototype to pass -Wmissing-prototypes */
1876 XS(XS_OS2_replaceModule)
1879 if (items < 1 || items > 3)
1880 Perl_croak(aTHX_ "Usage: OS2::replaceModule(target [, source [, backup]])");
1882 char * target = (char *)SvPV_nolen(ST(0));
1883 char * source = (items < 2) ? NULL : (char *)SvPV_nolen(ST(1));
1884 char * backup = (items < 3) ? NULL : (char *)SvPV_nolen(ST(2));
1886 if (!replaceModule(target, source, backup))
1887 croak_with_os2error("replaceModule() error");
1892 /* APIRET APIENTRY DosPerfSysCall(ULONG ulCommand, ULONG ulParm1,
1893 ULONG ulParm2, ULONG ulParm3); */
1895 DeclOSFuncByORD(ULONG,perfSysCall,ORD_DosPerfSysCall,
1896 (ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3),
1897 (ulCommand, ulParm1, ulParm2, ulParm3))
1899 #ifndef CMD_KI_RDCNT
1900 # define CMD_KI_RDCNT 0x63
1902 #ifndef CMD_KI_GETQTY
1903 # define CMD_KI_GETQTY 0x41
1905 #ifndef QSV_NUMPROCESSORS
1906 # define QSV_NUMPROCESSORS 26
1909 typedef unsigned long long myCPUUTIL[4]; /* time/idle/busy/intr */
1913 perfSysCall(ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3)
1918 croak_with_os2error("perfSysCall() error");
1926 if (DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, (PVOID)&res, sizeof(res)))
1927 return 1; /* Old system? */
1931 XS(XS_OS2_perfSysCall); /* prototype to pass -Wmissing-prototypes */
1932 XS(XS_OS2_perfSysCall)
1935 if (items < 0 || items > 4)
1936 Perl_croak(aTHX_ "Usage: OS2::perfSysCall(ulCommand = CMD_KI_RDCNT, ulParm1= 0, ulParm2= 0, ulParm3= 0)");
1940 ULONG RETVAL, ulCommand, ulParm1, ulParm2, ulParm3, res;
1942 int total = 0, tot2 = 0;
1945 ulCommand = CMD_KI_RDCNT;
1947 ulCommand = (ULONG)SvUV(ST(0));
1951 total = (ulCommand == CMD_KI_RDCNT ? numprocessors() : 0);
1952 ulParm1 = (total ? (ULONG)u : 0);
1954 if (total > C_ARRAY_LENGTH(u))
1955 croak("Unexpected number of processors: %d", total);
1957 ulParm1 = (ULONG)SvUV(ST(1));
1961 tot2 = (ulCommand == CMD_KI_GETQTY);
1962 ulParm2 = (tot2 ? (ULONG)&res : 0);
1964 ulParm2 = (ULONG)SvUV(ST(2));
1970 ulParm3 = (ULONG)SvUV(ST(3));
1973 RETVAL = perfSysCall(ulCommand, ulParm1, ulParm2, ulParm3);
1975 croak_with_os2error("perfSysCall() error");
1980 if (GIMME_V != G_ARRAY) {
1981 PUSHn(u[0][0]); /* Total ticks on the first processor */
1984 EXTEND(SP, 4*total);
1985 for (i=0; i < total; i++)
1986 for (j=0; j < 4; j++)
1987 PUSHs(sv_2mortal(newSVnv(u[i][j])));
1998 #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */
1999 #include "patchlevel.h"
2000 #undef PERL_PATCHLEVEL_H_IMPLICIT
2003 mod2fname(pTHX_ SV *sv)
2005 int pos = 6, len, avlen;
2006 unsigned int sum = 0;
2010 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
2012 if (SvTYPE(sv) != SVt_PVAV)
2013 Perl_croak_nocontext("Not array reference given to mod2fname");
2015 avlen = av_tindex((AV*)sv);
2017 Perl_croak_nocontext("Empty array reference given to mod2fname");
2019 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
2020 strncpy(fname, s, 8);
2022 if (len < 6) pos = len;
2024 sum = 33 * sum + *(s++); /* Checksumming first chars to
2025 * get the capitalization into c.s. */
2028 while (avlen >= 0) {
2029 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
2031 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
2035 /* We always load modules as *specific* DLLs, and with the full name.
2036 When loading a specific DLL by its full name, one cannot get a
2037 different DLL, even if a DLL with the same basename is loaded already.
2038 Thus there is no need to include the version into the mangling scheme. */
2040 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
2042 # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
2043 # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
2045 sum += COMPATIBLE_VERSION_SUM;
2047 fname[pos] = 'A' + (sum % 26);
2048 fname[pos + 1] = 'A' + (sum / 26 % 26);
2049 fname[pos + 2] = '\0';
2050 return (char *)fname;
2053 XS(XS_DynaLoader_mod2fname)
2057 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
2063 RETVAL = mod2fname(aTHX_ sv);
2064 sv_setpv(TARG, RETVAL);
2065 XSprePUSH; PUSHTARG;
2076 int number = SvTRUE(get_sv("OS2::nsyserror", GV_ADD));
2078 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
2082 sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
2083 s = os2error_buf + strlen(os2error_buf);
2086 if (DosGetMessage(NULL, 0, s, sizeof(os2error_buf) - 1 - (s-os2error_buf),
2087 rc, "OSO001.MSG", &len)) {
2091 sprintf(os2error_buf, "SYS%04d=%#x: ", rc, rc);
2092 s = os2error_buf + strlen(os2error_buf);
2095 case PMERR_INVALID_HWND:
2096 name = "PMERR_INVALID_HWND";
2098 case PMERR_INVALID_HMQ:
2099 name = "PMERR_INVALID_HMQ";
2101 case PMERR_CALL_FROM_WRONG_THREAD:
2102 name = "PMERR_CALL_FROM_WRONG_THREAD";
2104 case PMERR_NO_MSG_QUEUE:
2105 name = "PMERR_NO_MSG_QUEUE";
2107 case PMERR_NOT_IN_A_PM_SESSION:
2108 name = "PMERR_NOT_IN_A_PM_SESSION";
2110 case PMERR_INVALID_ATOM:
2111 name = "PMERR_INVALID_ATOM";
2113 case PMERR_INVALID_HATOMTBL:
2114 name = "PMERR_INVALID_HATOMTMB";
2116 case PMERR_INVALID_INTEGER_ATOM:
2117 name = "PMERR_INVALID_INTEGER_ATOM";
2119 case PMERR_INVALID_ATOM_NAME:
2120 name = "PMERR_INVALID_ATOM_NAME";
2122 case PMERR_ATOM_NAME_NOT_FOUND:
2123 name = "PMERR_ATOM_NAME_NOT_FOUND";
2126 sprintf(s, "%s%s[No description found in OSO001.MSG]",
2127 name, (*name ? "=" : ""));
2130 if (len && s[len - 1] == '\n')
2132 if (len && s[len - 1] == '\r')
2134 if (len && s[len - 1] == '.')
2136 if (len >= 10 && number && strnEQ(s, os2error_buf, 7)
2137 && s[7] == ':' && s[8] == ' ')
2138 /* Some messages start with SYSdddd:, some not */
2139 Move(s + 9, s, (len -= 9) + 1, char);
2141 return os2error_buf;
2151 CroakWinError(int die, char *name)
2155 croak_with_os2error(name ? name : "Win* API call");
2159 dllname2buffer(pTHX_ char *buf, STRLEN l)
2165 dll = module_name(mod_name_full);
2170 return (ll >= l ? "???" : buf);
2174 execname2buffer(char *buf, STRLEN l, char *oname)
2176 char *p, *orig = oname, ok = oname != NULL;
2178 if (_execname(buf, l) != 0) {
2179 if (!oname || strlen(oname) >= l)
2189 if (ok && *oname != '/' && *oname != '\\')
2191 } else if (ok && tolower(*oname) != tolower(*p))
2196 if (ok) { /* orig matches the real name. Use orig: */
2197 strcpy(buf, orig); /* _execname() is always uppercased */
2211 char buf[300], *p = execname2buffer(buf, sizeof buf, PL_origargv[0]);
2219 Perl_OS2_handler_install(void *handler, enum Perlos2_handler how)
2224 case Perlos2_handler_mangle:
2225 perllib_mangle_installed = (char *(*)(char *s, unsigned int l))handler;
2227 case Perlos2_handler_perl_sh:
2228 s = (char *)handler;
2229 s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perl_sh");
2230 perl_sh_installed = savepv(s);
2232 case Perlos2_handler_perllib_from:
2233 s = (char *)handler;
2234 s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_from");
2238 case Perlos2_handler_perllib_to:
2239 s = (char *)handler;
2240 s = dir_subst(s, strlen(s), b, sizeof b, 0, "handler_perllib_to");
2243 strcpy(mangle_ret, newp);
2254 /* Returns a malloc()ed copy */
2256 dir_subst(char *s, unsigned int l, char *b, unsigned int bl, enum dir_subst_e flags, char *msg)
2258 char *from, *to = b, *e = b; /* `to' assignment: shut down the warning */
2259 STRLEN froml = 0, tol = 0, rest = 0; /* froml: likewise */
2261 if (l >= 2 && s[0] == '~') {
2264 from = "installprefix"; break;
2266 from = "dll"; break;
2268 from = "exe"; break;
2271 froml = l + 1; /* Will not match */
2275 froml = strlen(from) + 1;
2276 if (l >= froml && strnicmp(s + 2, from + 1, froml - 2) == 0) {
2282 tol = strlen(INSTALL_PREFIX);
2284 if (flags & dir_subst_fatal)
2285 Perl_croak_nocontext("INSTALL_PREFIX too long: `%s'", INSTALL_PREFIX);
2289 memcpy(b, INSTALL_PREFIX, tol + 1);
2294 if (flags & dir_subst_fatal) {
2297 to = dllname2buffer(aTHX_ b, bl);
2298 } else { /* No Perl present yet */
2299 HMODULE self = find_myself();
2300 APIRET rc = DosQueryModuleName(self, bl, b);
2312 if (flags & dir_subst_fatal) {
2315 to = execname2buffer(b, bl, PL_origargv[0]);
2317 to = execname2buffer(b, bl, NULL);
2323 e = strrchr(to, '/');
2324 if (!e && (flags & dir_subst_fatal))
2325 Perl_croak_nocontext("%s: Can't parse EXE/DLL name: '%s'", msg, to);
2330 s += froml; l -= froml;
2336 while (l >= 3 && (s[0] == '/' || s[0] == '\\')
2337 && s[1] == '.' && s[2] == '.'
2338 && (l == 3 || s[3] == '/' || s[3] == '\\' || s[3] == ';')) {
2339 e = strrchr(b, '/');
2340 if (!e && (flags & dir_subst_fatal))
2341 Perl_croak_nocontext("%s: Error stripping dirs from EXE/DLL/INSTALLDIR name", msg);
2347 if (l && s[0] != '/' && s[0] != '\\' && s[0] != ';')
2350 } /* Else: copy as is */
2351 if (l && (flags & dir_subst_pathlike)) {
2354 while ( i < l - 2 && s[i] != ';') /* May have ~char after `;' */
2356 if (i < l - 2) { /* Found */
2361 if (e + l >= b + bl) {
2362 if (flags & dir_subst_fatal)
2363 Perl_croak_nocontext("%s: name `%s%s' too long", msg, b, s);
2369 e = dir_subst(s + l, rest, e + l, bl - (e + l - b), flags, msg);
2377 perllib_mangle_with(char *s, unsigned int l, char *from, unsigned int froml, char *to, unsigned int tol)
2383 if (l < froml || strnicmp(from, s, froml) != 0)
2385 if (l + tol - froml > STATIC_FILE_LENGTH || tol > STATIC_FILE_LENGTH)
2386 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
2387 if (to && to != mangle_ret)
2388 memcpy(mangle_ret, to, tol);
2389 strcpy(mangle_ret + tol, s + froml);
2394 perllib_mangle(char *s, unsigned int l)
2398 if (perllib_mangle_installed && (name = perllib_mangle_installed(s,l)))
2400 if (!newp && !notfound) {
2401 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
2402 STRINGIFY(PERL_VERSION) STRINGIFY(PERL_SUBVERSION)
2405 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION)
2406 STRINGIFY(PERL_VERSION) "_PREFIX");
2408 newp = getenv(name = "PERLLIB_" STRINGIFY(PERL_REVISION) "_PREFIX");
2410 newp = getenv(name = "PERLLIB_PREFIX");
2415 while (*newp && !isSPACE(*newp) && *newp != ';')
2416 newp++; /* Skip old name. */
2418 s = dir_subst(oldp, oldl, b, sizeof b, dir_subst_fatal, name);
2421 while (*newp && (isSPACE(*newp) || *newp == ';'))
2422 newp++; /* Skip whitespace. */
2423 Perl_OS2_handler_install((void *)newp, Perlos2_handler_perllib_to);
2424 if (newl == 0 || oldl == 0)
2425 Perl_croak_nocontext("Malformed %s", name);
2433 if (l < oldl || strnicmp(oldp, s, oldl) != 0)
2435 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH)
2436 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
2437 strcpy(mangle_ret + newl, s + oldl);
2442 Perl_hab_GET() /* Needed if perl.h cannot be included */
2444 return perl_hab_GET();
2448 Create_HMQ(int serve, char *message) /* Assumes morphing */
2450 unsigned fpflag = _control87(0,0);
2452 init_PMWIN_entries();
2453 /* 64 messages if before OS/2 3.0, ignored otherwise */
2454 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
2458 SAVEINT(rmq_cnt); /* Allow catch()ing. */
2460 _exit(188); /* Panic can try to create a window. */
2461 CroakWinError(1, message ? message : "Cannot create a message queue");
2464 (*PMWIN_entries.CancelShutdown)(Perl_hmq, !serve);
2465 /* We may have loaded some modules */
2466 _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
2469 #define REGISTERMQ_WILL_SERVE 1
2470 #define REGISTERMQ_IMEDIATE_UNMORPH 2
2473 Perl_Register_MQ(int serve)
2475 if (Perl_hmq_refcnt <= 0) {
2479 Perl_hmq_refcnt = 0; /* Be extra safe */
2480 DosGetInfoBlocks(&tib, &pib);
2481 if (!Perl_morph_refcnt) {
2482 Perl_os2_initial_mode = pib->pib_ultype;
2483 /* Try morphing into a PM application. */
2484 if (pib->pib_ultype != 3) /* 2 is VIO */
2485 pib->pib_ultype = 3; /* 3 is PM */
2487 Create_HMQ(-1, /* We do CancelShutdown ourselves */
2488 "Cannot create a message queue, or morph to a PM application");
2489 if ((serve & REGISTERMQ_IMEDIATE_UNMORPH)) {
2490 if (!Perl_morph_refcnt && Perl_os2_initial_mode != 3)
2491 pib->pib_ultype = Perl_os2_initial_mode;
2494 if (serve & REGISTERMQ_WILL_SERVE) {
2495 if ( Perl_hmq_servers <= 0 /* Safe to inform us on shutdown, */
2496 && Perl_hmq_refcnt > 0 ) /* this was switched off before... */
2497 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
2499 } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
2500 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
2502 if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH))
2503 Perl_morph_refcnt++;
2508 Perl_Serve_Messages(int force)
2513 if (Perl_hmq_servers > 0 && !force)
2515 if (Perl_hmq_refcnt <= 0)
2516 Perl_croak_nocontext("No message queue");
2517 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
2519 if (msg.msg == WM_QUIT)
2520 Perl_croak_nocontext("QUITing...");
2521 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
2527 Perl_Process_Messages(int force, I32 *cntp)
2531 if (Perl_hmq_servers > 0 && !force)
2533 if (Perl_hmq_refcnt <= 0)
2534 Perl_croak_nocontext("No message queue");
2535 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
2538 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
2539 if (msg.msg == WM_DESTROY)
2541 if (msg.msg == WM_CREATE)
2544 Perl_croak_nocontext("QUITing...");
2548 Perl_Deregister_MQ(int serve)
2550 if (serve & REGISTERMQ_WILL_SERVE)
2553 if (--Perl_hmq_refcnt <= 0) {
2554 unsigned fpflag = _control87(0,0);
2556 init_PMWIN_entries(); /* To be extra safe */
2557 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
2559 /* We may have (un)loaded some modules */
2560 _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
2561 } else if ((serve & REGISTERMQ_WILL_SERVE) && Perl_hmq_servers <= 0)
2562 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1); /* Last server exited */
2563 if (!(serve & REGISTERMQ_IMEDIATE_UNMORPH) && (--Perl_morph_refcnt <= 0)) {
2564 /* Try morphing back from a PM application. */
2568 DosGetInfoBlocks(&tib, &pib);
2569 if (pib->pib_ultype == 3) /* 3 is PM */
2570 pib->pib_ultype = Perl_os2_initial_mode;
2572 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
2577 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
2578 && ((path)[2] == '/' || (path)[2] == '\\'))
2579 #define sys_is_rooted _fnisabs
2580 #define sys_is_relative _fnisrel
2581 #define current_drive _getdrive
2583 #undef chdir /* Was _chdir2. */
2584 #define sys_chdir(p) (chdir(p) == 0)
2585 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
2591 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
2593 int arg1 = SvIV(ST(0));
2594 int arg2 = SvIV(ST(1));
2595 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
2596 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
2597 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
2600 if (CheckOSError(DosError(a)))
2601 Perl_croak_nocontext("DosError(%d) failed: %s", a, os2error(Perl_rc));
2602 ST(0) = sv_newmortal();
2603 if (DOS_harderr_state >= 0)
2604 sv_setiv(ST(0), DOS_harderr_state);
2605 DOS_harderr_state = RETVAL;
2610 XS(XS_OS2_Errors2Drive)
2614 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
2618 int suppress = SvOK(sv);
2619 char *s = suppress ? SvPV(sv, n_a) : NULL;
2620 char drive = (s ? *s : 0);
2623 if (suppress && !isALPHA(drive))
2624 Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
2625 if (CheckOSError(DosSuppressPopUps((suppress
2626 ? SPU_ENABLESUPPRESSION
2627 : SPU_DISABLESUPPRESSION),
2629 Perl_croak_nocontext("DosSuppressPopUps(%c) failed: %s", drive,
2631 ST(0) = sv_newmortal();
2632 if (DOS_suppression_state > 0)
2633 sv_setpvn(ST(0), &DOS_suppression_state, 1);
2634 else if (DOS_suppression_state == 0)
2636 DOS_suppression_state = drive;
2642 async_mssleep(ULONG ms, int switch_priority) {
2643 /* This is similar to DosSleep(), but has 8ms granularity in time-critical
2644 threads even on Warp3. */
2645 HEV hevEvent1 = 0; /* Event semaphore handle */
2646 HTIMER htimerEvent1 = 0; /* Timer handle */
2647 APIRET rc = NO_ERROR; /* Return code */
2649 ULONG priority = 0, nesting; /* Shut down the warnings */
2655 if (!(_emx_env & 0x200)) /* DOS */
2656 return !_sleep2(ms);
2658 os2cp_croak(DosCreateEventSem(NULL, /* Unnamed */
2659 &hevEvent1, /* Handle of semaphore returned */
2660 DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
2661 FALSE), /* Semaphore is in RESET state */
2662 "DosCreateEventSem");
2664 if (ms >= switch_priority)
2665 switch_priority = 0;
2666 if (switch_priority) {
2667 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
2668 switch_priority = 0;
2670 /* In Warp3, to switch scheduling to 8ms step, one needs to do
2671 DosAsyncTimer() in time-critical thread. On laters versions,
2672 more and more cases of wait-for-something are covered.
2674 It turns out that on Warp3fp42 it is the priority at the time
2675 of DosAsyncTimer() which matters. Let's hope that this works
2676 with later versions too... XXXX
2678 priority = (tib->tib_ptib2->tib2_ulpri);
2679 if ((priority & 0xFF00) == 0x0300) /* already time-critical */
2680 switch_priority = 0;
2681 /* Make us time-critical. Just modifying TIB is not enough... */
2682 /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/
2683 /* We do not want to run at high priority if a signal causes us
2684 to longjmp() out of this section... */
2685 if (DosEnterMustComplete(&nesting))
2686 switch_priority = 0;
2688 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
2692 if ((badrc = DosAsyncTimer(ms,
2693 (HSEM) hevEvent1, /* Semaphore to post */
2694 &htimerEvent1))) /* Timer handler (returned) */
2695 e = "DosAsyncTimer";
2697 if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300) {
2698 /* Nobody switched priority while we slept... Ignore errors... */
2699 /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */
2700 if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0)))
2701 rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0);
2703 if (switch_priority)
2704 rc = DosExitMustComplete(&nesting); /* Ignore errors */
2706 /* The actual blocking call is made with "normal" priority. This way we
2707 should not bother with DosSleep(0) etc. to compensate for us interrupting
2708 higher-priority threads. The goal is to prohibit the system spending too
2709 much time halt()ing, not to run us "no matter what". */
2710 if (!e) /* Wait for AsyncTimer event */
2711 badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT);
2713 if (e) ; /* Do nothing */
2714 else if (badrc == ERROR_INTERRUPT)
2717 e = "DosWaitEventSem";
2718 if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
2719 e = "DosCloseEventSem";
2723 os2cp_croak(badrc, e);
2727 XS(XS_OS2_ms_sleep) /* for testing only... */
2732 if (items > 2 || items < 1)
2733 Perl_croak_nocontext("Usage: OS2::ms_sleep(wait_ms [, high_priority_limit])");
2735 lim = items > 1 ? SvUV(ST(1)) : ms + 1;
2736 async_mssleep(ms, lim);
2740 ULONG (*pDosTmrQueryFreq) (PULONG);
2741 ULONG (*pDosTmrQueryTime) (unsigned long long *);
2747 unsigned long long count;
2751 Perl_croak_nocontext("Usage: OS2::Timer()");
2753 *(PFN*)&pDosTmrQueryFreq = loadByOrdinal(ORD_DosTmrQueryFreq, 0);
2754 *(PFN*)&pDosTmrQueryTime = loadByOrdinal(ORD_DosTmrQueryTime, 0);
2755 MUTEX_LOCK(&perlos2_state_mutex);
2757 if (CheckOSError(pDosTmrQueryFreq(&freq)))
2758 croak_with_os2error("DosTmrQueryFreq");
2759 MUTEX_UNLOCK(&perlos2_state_mutex);
2761 if (CheckOSError(pDosTmrQueryTime(&count)))
2762 croak_with_os2error("DosTmrQueryTime");
2766 XSprePUSH; PUSHn(((NV)count)/freq);
2771 XS(XS_OS2_msCounter)
2776 Perl_croak_nocontext("Usage: OS2::msCounter()");
2780 XSprePUSH; PUSHu(msCounter());
2785 XS(XS_OS2__InfoTable)
2791 Perl_croak_nocontext("Usage: OS2::_infoTable([isLocal])");
2793 is_local = (int)SvIV(ST(0));
2797 XSprePUSH; PUSHu(InfoTable(is_local));
2802 static const char * const dc_fields[] = {
2811 "HORIZONTAL_RESOLUTION",
2812 "VERTICAL_RESOLUTION",
2816 "SMALL_CHAR_HEIGHT",
2820 "COLOR_TABLE_SUPPORT",
2822 "FOREGROUND_MIX_SUPPORT",
2823 "BACKGROUND_MIX_SUPPORT",
2824 "VIO_LOADABLE_FONTS",
2825 "WINDOW_BYTE_ALIGNMENT",
2833 "GRAPHICS_VECTOR_SUBSET",
2835 "ADDITIONAL_GRAPHICS",
2838 "GRAPHICS_CHAR_WIDTH",
2839 "GRAPHICS_CHAR_HEIGHT",
2840 "HORIZONTAL_FONT_RES",
2841 "VERTICAL_FONT_RES",
2844 "DEVICE_POLYSET_POINTS",
2848 DevCap_dc, DevCap_hwnd
2851 HDC (*pWinOpenWindowDC) (HWND hwnd);
2852 HMF (*pDevCloseDC) (HDC hdc);
2853 HDC (*pDevOpenDC) (HAB hab, LONG lType, PCSZ pszToken, LONG lCount,
2854 PDEVOPENDATA pdopData, HDC hdcComp);
2855 BOOL (*pDevQueryCaps) (HDC hdc, LONG lStart, LONG lCount, PLONG alArray);
2862 Perl_croak_nocontext("Usage: OS2::DevCap()");
2864 /* Device Capabilities Data Buffer (10 extra w.r.t. Warp 4.5) */
2865 LONG si[CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1];
2866 int i = 0, j = 0, how = DevCap_dc;
2868 DEVOPENSTRUC doStruc= {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
2869 ULONG rc1 = NO_ERROR;
2871 static volatile int devcap_loaded;
2873 if (!devcap_loaded) {
2874 *(PFN*)&pWinOpenWindowDC = loadByOrdinal(ORD_WinOpenWindowDC, 0);
2875 *(PFN*)&pDevOpenDC = loadByOrdinal(ORD_DevOpenDC, 0);
2876 *(PFN*)&pDevCloseDC = loadByOrdinal(ORD_DevCloseDC, 0);
2877 *(PFN*)&pDevQueryCaps = loadByOrdinal(ORD_DevQueryCaps, 0);
2883 if (!items) { /* Get device contents from PM */
2884 hScreenDC = pDevOpenDC(perl_hab_GET(), OD_MEMORY, (PSZ)"*", 0,
2885 (PDEVOPENDATA)&doStruc, NULLHANDLE);
2886 if (CheckWinError(hScreenDC))
2887 croak_with_os2error("DevOpenDC() failed");
2888 } else if (how == DevCap_dc)
2889 hScreenDC = (HDC)SvIV(ST(0));
2890 else { /* DevCap_hwnd */
2892 Perl_croak(aTHX_ "Getting a window's device context without a message queue would lock PM");
2893 hwnd = (HWND)SvIV(ST(0));
2894 hScreenDC = pWinOpenWindowDC(hwnd); /* No need to DevCloseDC() */
2895 if (CheckWinError(hScreenDC))
2896 croak_with_os2error("WinOpenWindowDC() failed");
2898 if (CheckWinError(pDevQueryCaps(hScreenDC,
2899 CAPS_FAMILY, /* W3 documented caps */
2900 CAPS_DEVICE_POLYSET_POINTS
2905 EXTEND(SP,2*(CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1));
2906 while (i < CAPS_DEVICE_POLYSET_POINTS - CAPS_FAMILY + 1) {
2907 ST(j) = sv_newmortal();
2908 sv_setpv(ST(j++), dc_fields[i]);
2909 ST(j) = sv_newmortal();
2910 sv_setiv(ST(j++), si[i]);
2913 i = CAPS_DEVICE_POLYSET_POINTS + 1;
2914 while (i < CAPS_DEVICE_POLYSET_POINTS + 11) { /* Just in case... */
2917 if (CheckWinError(pDevQueryCaps(hScreenDC, i, 1, &l)))
2920 ST(j) = sv_newmortal();
2921 sv_setiv(ST(j++), i);
2922 ST(j) = sv_newmortal();
2923 sv_setiv(ST(j++), l);
2927 if (!items && CheckWinError(pDevCloseDC(hScreenDC)))
2928 Perl_warn_nocontext("DevCloseDC() failed: %s", os2error(Perl_rc));
2930 Perl_rc = rc1, croak_with_os2error("DevQueryCaps() failed");
2935 LONG (*pWinQuerySysValue) (HWND hwndDesktop, LONG iSysValue);
2936 BOOL (*pWinSetSysValue) (HWND hwndDesktop, LONG iSysValue, LONG lValue);
2938 const char * const sv_keys[] = {
2990 "DESKTOPWORKAREAYTOP",
2991 "DESKTOPWORKAREAYBOTTOM",
2992 "DESKTOPWORKAREAXRIGHT",
2993 "DESKTOPWORKAREAXLEFT",
3003 "MENUROLLDOWNDELAY",
3006 "TASKLISTMOUSEACCESS",
3036 "PRINTSCREEN", /* 97, the last one on one of the DDK header */
3048 /* In recent DDK the limit is 108 */
3051 XS(XS_OS2_SysValues)
3055 Perl_croak_nocontext("Usage: OS2::SysValues(which = -1, hwndDesktop = HWND_DESKTOP)");
3057 int i = 0, j = 0, which = -1;
3058 HWND hwnd = HWND_DESKTOP;
3059 static volatile int sv_loaded;
3063 *(PFN*)&pWinQuerySysValue = loadByOrdinal(ORD_WinQuerySysValue, 0);
3068 hwnd = (HWND)SvIV(ST(1));
3070 which = (int)SvIV(ST(0));
3072 EXTEND(SP,2*C_ARRAY_LENGTH(sv_keys));
3073 while (i < C_ARRAY_LENGTH(sv_keys)) {
3075 RETVAL = pWinQuerySysValue(hwnd, i);
3077 && !(sv_keys[i][0] >= '0' && sv_keys[i][0] <= '9'
3078 && i <= SV_PRINTSCREEN) ) {
3081 if (i > SV_PRINTSCREEN)
3082 break; /* May be not present on older systems */
3083 croak_with_os2error("SysValues():");
3087 ST(j) = sv_newmortal();
3088 sv_setpv(ST(j++), sv_keys[i]);
3089 ST(j) = sv_newmortal();
3090 sv_setiv(ST(j++), RETVAL);
3098 RETVAL = pWinQuerySysValue(hwnd, which);
3102 croak_with_os2error("SysValues():");
3104 XSprePUSH; PUSHi((IV)RETVAL);
3109 XS(XS_OS2_SysValues_set)
3112 if (items < 2 || items > 3)
3113 Perl_croak_nocontext("Usage: OS2::SysValues_set(which, val, hwndDesktop = HWND_DESKTOP)");
3115 int which = (int)SvIV(ST(0));
3116 LONG val = (LONG)SvIV(ST(1));
3117 HWND hwnd = HWND_DESKTOP;
3118 static volatile int svs_loaded;
3121 *(PFN*)&pWinSetSysValue = loadByOrdinal(ORD_WinSetSysValue, 0);
3126 hwnd = (HWND)SvIV(ST(2));
3127 if (CheckWinError(pWinSetSysValue(hwnd, which, val)))
3128 croak_with_os2error("SysValues_set()");
3133 #define QSV_MAX_WARP3 QSV_MAX_COMP_LENGTH
3135 static const char * const si_fields[] = {
3137 "MAX_TEXT_SESSIONS",
3141 "DYN_PRI_VARIATION",
3159 "FOREGROUND_FS_SESSION",
3160 "FOREGROUND_PROCESS", /* Warp 3 toolkit defines up to this */
3165 "VIRTUALADDRESSLIMIT",
3166 "INT10ENABLED", /* From $TOOLKIT-ddk\DDK\video\rel\os2c\include\base\os2\bsedos.h */
3173 Perl_croak_nocontext("Usage: OS2::SysInfo()");
3175 /* System Information Data Buffer (10 extra w.r.t. Warp 4.5) */
3176 ULONG si[C_ARRAY_LENGTH(si_fields) + 10];
3177 APIRET rc = NO_ERROR; /* Return code */
3178 int i = 0, j = 0, last = QSV_MAX_WARP3;
3180 if (CheckOSError(DosQuerySysInfo(1L, /* Request documented system */
3181 last, /* info for Warp 3 */
3184 croak_with_os2error("DosQuerySysInfo() failed");
3185 while (++last <= C_ARRAY_LENGTH(si)) {
3186 if (CheckOSError(DosQuerySysInfo(last, last, /* One entry only */
3189 if (Perl_rc != ERROR_INVALID_PARAMETER)
3190 croak_with_os2error("DosQuerySysInfo() failed");
3194 last--; /* Count of successfully processed offsets */
3197 ST(j) = sv_newmortal();
3198 if (i < C_ARRAY_LENGTH(si_fields))
3199 sv_setpv(ST(j++), si_fields[i]);
3201 sv_setiv(ST(j++), i + 1);
3202 ST(j) = sv_newmortal();
3203 sv_setuv(ST(j++), si[i]);
3210 XS(XS_OS2_SysInfoFor)
3213 int count = (items == 2 ? (int)SvIV(ST(1)) : 1);
3215 if (items < 1 || items > 2)
3216 Perl_croak_nocontext("Usage: OS2::SysInfoFor(id[,count])");
3218 /* System Information Data Buffer (10 extra w.r.t. Warp 4.5) */
3219 ULONG si[C_ARRAY_LENGTH(si_fields) + 10];
3220 APIRET rc = NO_ERROR; /* Return code */
3222 int start = (int)SvIV(ST(0));
3224 if (count > C_ARRAY_LENGTH(si) || count <= 0)
3225 Perl_croak(aTHX_ "unexpected count %d for OS2::SysInfoFor()", count);
3226 if (CheckOSError(DosQuerySysInfo(start,
3230 croak_with_os2error("DosQuerySysInfo() failed");
3233 ST(i) = sv_newmortal();
3234 sv_setiv(ST(i), si[i]);
3241 XS(XS_OS2_BootDrive)
3245 Perl_croak_nocontext("Usage: OS2::BootDrive()");
3247 ULONG si[1] = {0}; /* System Information Data Buffer */
3248 APIRET rc = NO_ERROR; /* Return code */
3252 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
3253 (PVOID)si, sizeof(si))))
3254 croak_with_os2error("DosQuerySysInfo() failed");
3255 c = 'a' - 1 + si[0];
3256 sv_setpvn(TARG, &c, 1);
3257 XSprePUSH; PUSHTARG;
3265 if (items > 2) /* Defaults as for WinAlarm(ERROR) */
3266 Perl_croak_nocontext("Usage: OS2::Beep(freq = 440, ms = 100)");
3268 ULONG freq = (items > 0 ? (ULONG)SvUV(ST(0)) : 440);
3269 ULONG ms = (items > 1 ? (ULONG)SvUV(ST(1)) : 100);
3272 if (CheckOSError(DosBeep(freq, ms)))
3273 croak_with_os2error("SysValues_set()");
3284 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
3286 bool serve = SvOK(ST(0));
3287 unsigned long pmq = perl_hmq_GET(serve);
3290 XSprePUSH; PUSHi((IV)pmq);
3295 XS(XS_OS2_UnMorphPM)
3299 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
3301 bool serve = SvOK(ST(0));
3303 perl_hmq_UNSET(serve);
3308 XS(XS_OS2_Serve_Messages)
3312 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
3314 bool force = SvOK(ST(0));
3315 unsigned long cnt = Perl_Serve_Messages(force);
3318 XSprePUSH; PUSHi((IV)cnt);
3323 XS(XS_OS2_Process_Messages)
3326 if (items < 1 || items > 2)
3327 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
3329 bool force = SvOK(ST(0));
3337 (void)SvIV(sv); /* Force SvIVX */
3339 Perl_croak_nocontext("Can't upgrade count to IV");
3341 cnt = Perl_Process_Messages(force, &cntr);
3344 cnt = Perl_Process_Messages(force, NULL);
3346 XSprePUSH; PUSHi((IV)cnt);
3351 XS(XS_Cwd_current_drive)
3355 Perl_croak_nocontext("Usage: Cwd::current_drive()");
3360 RETVAL = current_drive();
3361 sv_setpvn(TARG, (char *)&RETVAL, 1);
3362 XSprePUSH; PUSHTARG;
3367 XS(XS_Cwd_sys_chdir)
3371 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
3374 char * path = (char *)SvPV(ST(0),n_a);
3377 RETVAL = sys_chdir(path);
3378 ST(0) = boolSV(RETVAL);
3379 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3384 XS(XS_Cwd_change_drive)
3388 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
3391 char d = (char)*SvPV(ST(0),n_a);
3394 RETVAL = change_drive(d);
3395 ST(0) = boolSV(RETVAL);
3396 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3401 XS(XS_Cwd_sys_is_absolute)
3405 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
3408 char * path = (char *)SvPV(ST(0),n_a);
3411 RETVAL = sys_is_absolute(path);
3412 ST(0) = boolSV(RETVAL);
3413 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3418 XS(XS_Cwd_sys_is_rooted)
3422 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
3425 char * path = (char *)SvPV(ST(0),n_a);
3428 RETVAL = sys_is_rooted(path);
3429 ST(0) = boolSV(RETVAL);
3430 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3435 XS(XS_Cwd_sys_is_relative)
3439 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
3442 char * path = (char *)SvPV(ST(0),n_a);
3445 RETVAL = sys_is_relative(path);
3446 ST(0) = boolSV(RETVAL);
3447 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3456 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
3461 /* Can't use TARG, since tainting behaves differently */
3462 RETVAL = _getcwd2(p, MAXPATHLEN);
3463 ST(0) = sv_newmortal();
3464 sv_setpv(ST(0), RETVAL);
3465 SvTAINTED_on(ST(0));
3470 XS(XS_Cwd_sys_abspath)
3474 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path = '.', dir = NULL)");
3477 char * path = items ? (char *)SvPV(ST(0),n_a) : ".";
3478 char * dir, *s, *t, *e;
3487 dir = (char *)SvPV(ST(1),n_a);
3489 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
3493 if (_abspath(p, path, MAXPATHLEN) == 0) {
3499 /* Absolute with drive: */
3500 if ( sys_is_absolute(path) ) {
3501 if (_abspath(p, path, MAXPATHLEN) == 0) {
3506 } else if (path[0] == '/' || path[0] == '\\') {
3507 /* Rooted, but maybe on different drive. */
3508 if (isALPHA(dir[0]) && dir[1] == ':' ) {
3509 char p1[MAXPATHLEN];
3511 /* Need to prepend the drive. */
3514 Copy(path, p1 + 2, strlen(path) + 1, char);
3516 if (_abspath(p, p1, MAXPATHLEN) == 0) {
3521 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
3527 /* Either path is relative, or starts with a drive letter. */
3528 /* If the path starts with a drive letter, then dir is
3530 a/b) it is absolute/x:relative on the same drive.
3531 c) path is on current drive, and dir is rooted
3532 In all the cases it is safe to drop the drive part
3534 if ( !sys_is_relative(path) ) {
3535 if ( ( ( sys_is_absolute(dir)
3536 || (isALPHA(dir[0]) && dir[1] == ':'
3537 && strnicmp(dir, path,1) == 0))
3538 && strnicmp(dir, path,1) == 0)
3539 || ( !(isALPHA(dir[0]) && dir[1] == ':')
3540 && toupper(path[0]) == current_drive())) {
3542 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
3543 RETVAL = p; goto done;
3545 RETVAL = NULL; goto done;
3549 /* Need to prepend the absolute path of dir. */
3550 char p1[MAXPATHLEN];
3552 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
3555 if (p1[ l - 1 ] != '/') {
3559 Copy(path, p1 + l, strlen(path) + 1, char);
3560 if (_abspath(p, p1, MAXPATHLEN) == 0) {
3574 /* Backslashes are already converted to slashes. */
3575 /* Remove trailing slashes */
3577 while (l > 0 && RETVAL[l-1] == '/')
3579 ST(0) = sv_newmortal();
3580 sv_setpvn( sv = (SV*)ST(0), RETVAL, l);
3581 /* Remove duplicate slashes, skipping the first three, which
3582 may be parts of a server-based path */
3583 s = t = 3 + SvPV_force(sv, n_a);
3585 /* Do not worry about multibyte chars here, this would contradict the
3586 eventual UTFization, and currently most other places break too... */
3588 if (s[0] == t[-1] && s[0] == '/')
3589 s++; /* Skip duplicate / */
3595 SvCUR_set(sv, t - SvPVX(sv));
3598 SvTAINTED_on(ST(0));
3602 typedef APIRET (*PELP)(PSZ path, ULONG type);
3604 /* Kernels after 2000/09/15 understand this too: */
3605 #ifndef LIBPATHSTRICT
3606 # define LIBPATHSTRICT 3
3610 ExtLIBPATH(ULONG ord, PSZ path, IV type, int fatal)
3613 PFN f = loadByOrdinal(ord, fatal); /* if fatal: load or die! */
3615 if (!f) /* Impossible with fatal */
3620 what = BEGIN_LIBPATH;
3622 what = LIBPATHSTRICT;
3623 return (*(PELP)f)(path, what);
3626 #define extLibpath(to,type, fatal) \
3627 (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type), fatal)) ? NULL : (to) )
3629 #define extLibpath_set(p,type, fatal) \
3630 (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type), fatal)))
3633 early_error(char *msg1, char *msg2, char *msg3)
3634 { /* Buffer overflow detected; there is very little we can do... */
3637 DosWrite(2, msg1, strlen(msg1), &rc);
3638 DosWrite(2, msg2, strlen(msg2), &rc);
3639 DosWrite(2, msg3, strlen(msg3), &rc);
3640 DosExit(EXIT_PROCESS, 2);
3643 XS(XS_Cwd_extLibpath)
3646 if (items < 0 || items > 1)
3647 Perl_croak_nocontext("Usage: OS2::extLibpath(type = 0)");
3662 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
3663 RETVAL = extLibpath(to, type, 1); /* Make errors fatal */
3664 if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0)
3665 Perl_croak_nocontext("panic OS2::extLibpath parameter");
3667 if (l >= sizeof(to))
3668 early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `",
3669 to, "'\r\n"); /* Will not return */
3670 sv_setpv(TARG, RETVAL);
3671 XSprePUSH; PUSHTARG;
3676 XS(XS_Cwd_extLibpath_set)
3679 if (items < 1 || items > 2)
3680 Perl_croak_nocontext("Usage: OS2::extLibpath_set(s, type = 0)");
3683 char * s = (char *)SvPV(ST(0),n_a);
3694 RETVAL = extLibpath_set(s, type, 1); /* Make errors fatal */
3695 ST(0) = boolSV(RETVAL);
3696 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
3702 fill_extLibpath(int type, char *pre, char *post, int replace, char *msg)
3704 char buf[2048], *to = buf, buf1[300], *s;
3711 pre = dir_subst(pre, strlen(pre), buf1, sizeof buf1, dir_subst_pathlike, msg);
3713 return ERROR_INVALID_PARAMETER;
3715 if (l >= sizeof(buf)/2)
3716 return ERROR_BUFFER_OVERFLOW;
3720 *s = '\\'; /* Be extra cautious */
3722 if (!l || to[l-1] != ';')
3728 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
3729 rc = ExtLIBPATH(ORD_DosQueryExtLibpath, to, type, 0); /* Do not croak */
3732 if (to[0] == 1 && to[1] == 0)
3733 return ERROR_INVALID_PARAMETER;
3735 if (buf + sizeof(buf) - 1 <= to) /* Buffer overflow */
3736 early_error("Buffer overflow while getting BEGIN/ENDLIBPATH: `",
3737 buf, "'\r\n"); /* Will not return */
3738 if (to > buf && to[-1] != ';')
3742 post = dir_subst(post, strlen(post), buf1, sizeof buf1, dir_subst_pathlike, msg);
3744 return ERROR_INVALID_PARAMETER;
3746 if (l + to - buf >= sizeof(buf) - 1)
3747 return ERROR_BUFFER_OVERFLOW;
3751 *s = '\\'; /* Be extra cautious */
3752 memcpy(to, post, l);
3753 if (!l || to[l-1] != ';')
3758 rc = ExtLIBPATH(ORD_DosSetExtLibpath, buf, type, 0); /* Do not croak */
3762 /* Input: Address, BufLen
3764 DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
3765 ULONG * Offset, ULONG Address);
3768 DeclOSFuncByORD(APIRET, _DosQueryModFromEIP,ORD_DosQueryModFromEIP,
3769 (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
3770 ULONG * Offset, ULONG Address),
3771 (hmod, obj, BufLen, Buf, Offset, Address))
3774 module_name_at(void *pp, enum module_name_how how)
3777 char buf[MAXPATHLEN];
3780 ULONG obj, offset, rc, addr = (ULONG)pp;
3782 if (how & mod_name_HMODULE) {
3783 if ((how & ~mod_name_HMODULE) == mod_name_shortname)
3784 Perl_croak(aTHX_ "Can't get short module name from a handle");
3786 how &= ~mod_name_HMODULE;
3787 } else if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, addr))
3788 return &PL_sv_undef;
3789 if (how == mod_name_handle)
3790 return newSVuv(mod);
3792 if ( how != mod_name_shortname
3793 && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) )
3794 return &PL_sv_undef;
3800 return newSVpv(buf, 0);
3804 module_name_of_cv(SV *cv, enum module_name_how how)
3806 if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv))) {
3809 if (how & mod_name_C_function)
3810 return module_name_at((void*)SvIV(cv), how & ~mod_name_C_function);
3811 else if (how & mod_name_HMODULE)
3812 return module_name_at((void*)SvIV(cv), how);
3813 Perl_croak(aTHX_ "Not an XSUB reference");
3815 return module_name_at(CvXSUB(SvRV(cv)), how);
3822 Perl_croak(aTHX_ "Usage: OS2::DLLname( [ how, [\\&xsub] ] )");
3828 how = mod_name_full;
3830 how = (int)SvIV(ST(0));
3833 RETVAL = module_name(how);
3835 RETVAL = module_name_of_cv(ST(1), how);
3842 DeclOSFuncByORD(INT, _Dos32QueryHeaderInfo, ORD_Dos32QueryHeaderInfo,
3843 (ULONG r1, ULONG r2, PVOID buf, ULONG szbuf, ULONG fnum),
3844 (r1, r2, buf, szbuf, fnum))
3846 XS(XS_OS2__headerInfo)
3849 if (items > 4 || items < 2)
3850 Perl_croak(aTHX_ "Usage: OS2::_headerInfo(req,size[,handle,[offset]])");
3852 ULONG req = (ULONG)SvIV(ST(0));
3853 STRLEN size = (STRLEN)SvIV(ST(1)), n_a;
3854 ULONG handle = (items >= 3 ? (ULONG)SvIV(ST(2)) : 0);
3855 ULONG offset = (items >= 4 ? (ULONG)SvIV(ST(3)) : 0);
3858 Perl_croak(aTHX_ "OS2::_headerInfo(): unexpected size: %d", (int)size);
3859 ST(0) = newSVpvs("");
3860 SvGROW(ST(0), size + 1);
3863 if (!_Dos32QueryHeaderInfo(handle, offset, SvPV(ST(0), n_a), size, req))
3864 Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
3865 req, size, handle, offset, os2error(Perl_rc));
3866 SvCUR_set(ST(0), size);
3872 #define DQHI_QUERYLIBPATHSIZE 4
3873 #define DQHI_QUERYLIBPATH 5
3879 Perl_croak(aTHX_ "Usage: OS2::libPath()");
3884 if (!_Dos32QueryHeaderInfo(0, 0, &size, sizeof(size),
3885 DQHI_QUERYLIBPATHSIZE))
3886 Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
3887 DQHI_QUERYLIBPATHSIZE, sizeof(size), 0, 0,
3889 ST(0) = newSVpvs("");
3890 SvGROW(ST(0), size + 1);
3893 /* We should be careful: apparently, this entry point does not
3894 pay attention to the size argument, so may overwrite
3896 if (!_Dos32QueryHeaderInfo(0, 0, SvPV(ST(0), n_a), size,
3898 Perl_croak(aTHX_ "OS2::_headerInfo(%ld,%ld,%ld,%ld) error: %s",
3899 DQHI_QUERYLIBPATH, size, 0, 0, os2error(Perl_rc));
3900 SvCUR_set(ST(0), size);
3906 #define get_control87() _control87(0,0)
3907 #define set_control87 _control87
3909 XS(XS_OS2__control87)
3913 Perl_croak(aTHX_ "Usage: OS2::_control87(new,mask)");
3915 unsigned new = (unsigned)SvIV(ST(0));
3916 unsigned mask = (unsigned)SvIV(ST(1));
3920 RETVAL = _control87(new, mask);
3921 XSprePUSH; PUSHi((IV)RETVAL);
3931 if (items < 0 || items > 1)
3932 Perl_croak(aTHX_ "Usage: OS2::mytype([which])");
3934 which = (int)SvIV(ST(0));
3941 RETVAL = os2_mytype; /* Reset after fork */
3944 RETVAL = os2_mytype_ini; /* Before any fork */
3947 RETVAL = Perl_os2_initial_mode; /* Before first morphing */
3950 RETVAL = my_type(); /* Morphed type */
3953 Perl_croak(aTHX_ "OS2::mytype(which): unknown which=%d", which);
3955 XSprePUSH; PUSHi((IV)RETVAL);
3961 XS(XS_OS2_mytype_set)
3967 type = (int)SvIV(ST(0));
3969 Perl_croak(aTHX_ "Usage: OS2::mytype_set(type)");
3975 XS(XS_OS2_get_control87)
3979 Perl_croak(aTHX_ "Usage: OS2::get_control87()");
3984 RETVAL = get_control87();
3985 XSprePUSH; PUSHi((IV)RETVAL);
3991 XS(XS_OS2_set_control87)
3994 if (items < 0 || items > 2)
3995 Perl_croak(aTHX_ "Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
4005 new = (unsigned)SvIV(ST(0));
4011 mask = (unsigned)SvIV(ST(1));
4014 RETVAL = set_control87(new, mask);
4015 XSprePUSH; PUSHi((IV)RETVAL);
4020 XS(XS_OS2_incrMaxFHandles) /* DosSetRelMaxFH */
4023 if (items < 0 || items > 1)
4024 Perl_croak(aTHX_ "Usage: OS2::incrMaxFHandles(delta = 0)");
4033 delta = (LONG)SvIV(ST(0));
4035 if (CheckOSError(DosSetRelMaxFH(&delta, &RETVAL)))
4036 croak_with_os2error("OS2::incrMaxFHandles(): DosSetRelMaxFH() error");
4037 XSprePUSH; PUSHu((UV)RETVAL);
4042 /* wait>0: force wait, wait<0: force nowait;
4043 if restore, save/restore flags; otherwise flags are in oflags.
4045 Returns 1 if connected, 0 if not (due to nowait); croaks on error. */
4047 connectNPipe(ULONG hpipe, int wait, ULONG restore, ULONG oflags)
4049 ULONG ret = ERROR_INTERRUPT, rc, flags;
4051 if (restore && wait)
4052 os2cp_croak(DosQueryNPHState(hpipe, &oflags), "DosQueryNPHState()");
4053 /* DosSetNPHState fails if more bits than NP_NOWAIT|NP_READMODE_MESSAGE */
4054 oflags &= (NP_NOWAIT | NP_READMODE_MESSAGE);
4055 flags = (oflags & ~NP_NOWAIT) | (wait > 0 ? NP_WAIT : NP_NOWAIT);
4056 /* We know (o)flags unless wait == 0 && restore */
4057 if (wait && (flags != oflags))
4058 os2cp_croak(DosSetNPHState(hpipe, flags), "DosSetNPHState()");
4059 while (ret == ERROR_INTERRUPT)
4060 ret = DosConnectNPipe(hpipe);
4061 (void)CheckOSError(ret);
4062 if (restore && wait && (flags != oflags))
4063 os2cp_croak(DosSetNPHState(hpipe, oflags), "DosSetNPHState() back");
4064 /* We know flags unless wait == 0 && restore */
4065 if ( ((wait || restore) ? (flags & NP_NOWAIT) : 1)
4066 && (ret == ERROR_PIPE_NOT_CONNECTED) )
4067 return 0; /* normal return value */
4068 if (ret == NO_ERROR)
4070 croak_with_os2error("DosConnectNPipe()");
4073 /* With a lot of manual editing:
4075 DosCreateNPipe(PCSZ pszName, OUTLIST HPIPE hpipe, ULONG ulOpenMode, int connect = 1, int count = 1, ULONG ulInbufLength = 8192, ULONG ulOutbufLength = ulInbufLength, ULONG ulPipeMode = count | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE, ULONG ulTimeout = 0)
4079 pszName, &hpipe, ulOpenMode, ulPipeMode, ulInbufLength, ulOutbufLength, ulTimeout
4081 if (CheckOSError(RETVAL))
4082 croak_with_os2error("OS2::mkpipe() error");
4084 XS(XS_OS2_pipe); /* prototype to pass -Wmissing-prototypes */
4088 if (items < 2 || items > 8)
4089 Perl_croak(aTHX_ "Usage: OS2::pipe(pszName, ulOpenMode, connect= 1, count= 1, ulInbufLength= 8192, ulOutbufLength= ulInbufLength, ulPipeMode= count | NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE, ulTimeout= 0)");
4092 PCSZ pszName = ( SvOK(ST(0)) ? (PCSZ)SvPV_nolen(ST(0)) : NULL );
4094 SV *OpenMode = ST(1);
4096 int connect = 0, count, message_r = 0, message = 0, b = 0;
4097 ULONG ulInbufLength, ulOutbufLength, ulPipeMode, ulTimeout, rc;
4099 char *s, buf[10], *s1, *perltype = NULL;
4103 if (!pszName || !*pszName)
4104 Perl_croak(aTHX_ "OS2::pipe(): empty pipe name");
4105 s = SvPV(OpenMode, len);
4106 if (memEQs(s, len, "wait")) { /* DosWaitNPipe() */
4107 ULONG ms = 0xFFFFFFFF, ret = ERROR_INTERRUPT; /* Indefinite */
4110 timeout = (double)SvNV(ST(2));
4111 ms = timeout * 1000;
4113 ms = 0xFFFFFFFF; /* Indefinite */
4114 else if (timeout && !ms)
4116 } else if (items > 3)
4117 Perl_croak(aTHX_ "OS2::pipe(): too many arguments for wait-for-connect: %ld", (long)items);
4119 while (ret == ERROR_INTERRUPT)
4120 ret = DosWaitNPipe(pszName, ms); /* XXXX Update ms? */
4121 os2cp_croak(ret, "DosWaitNPipe()");
4124 if (memEQs(s, len, "call")) { /* DosCallNPipe() */
4125 ULONG ms = 0xFFFFFFFF, got; /* Indefinite */
4129 STRLEN ll = sizeof(buf);
4132 if (items < 3 || items > 5)
4133 Perl_croak(aTHX_ "usage: OS2::pipe(pszName, 'call', write [, timeout= 0xFFFFFFFF, buffsize = 8192])");
4136 timeout = (double)SvNV(ST(3));
4137 ms = timeout * 1000;
4139 ms = 0xFFFFFFFF; /* Indefinite */
4140 else if (timeout && !ms)
4144 STRLEN lll = SvUV(ST(4));
4145 SV *sv = NEWSV(914, lll);
4152 os2cp_croak(DosCallNPipe(pszName, s, l, b, ll, &got, ms),
4154 XSRETURN_PVN(b, got);
4157 if (len && len <= 3 && !(*s >= '0' && *s <= '9')) {
4160 r = strchr(s, 'r') != 0;
4161 w = strchr(s, 'w') != 0;
4162 R = strchr(s, 'R') != 0;
4163 W = strchr(s, 'W') != 0;
4164 b = strchr(s, 'b') != 0;
4165 if (r + w + R + W + b != len || (r && R) || (w && W))
4166 Perl_croak(aTHX_ "OS2::pipe(): unknown OpenMode argument: `%s'", s);
4167 if ((r || R) && (w || W))
4168 ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_DUPLEX;
4170 ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_INBOUND;
4172 ulOpenMode = NP_INHERIT | NP_NOWRITEBEHIND | NP_ACCESS_OUTBOUND;
4174 message = message_r = 1;
4178 Perl_croak(aTHX_ "OS2::pipe(): can't have message read mode for non-message pipes");
4180 ulOpenMode = (ULONG)SvUV(OpenMode); /* ST(1) */
4182 if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX
4183 || (ulOpenMode & 0x3) == NP_ACCESS_INBOUND )
4185 if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX )
4187 if ( (ulOpenMode & 0x3) == NP_ACCESS_OUTBOUND )
4192 if ( (ulOpenMode & 0x3) == NP_ACCESS_DUPLEX )
4194 else if ( (ulOpenMode & 0x3) == NP_ACCESS_OUTBOUND )
4200 connect = -1; /* no wait */
4201 else if (SvTRUE(ST(2))) {
4202 s = SvPV(ST(2), len);
4203 if (memEQs(s, len, "nowait"))
4204 connect = -1; /* no wait */
4205 else if (memEQs(s, len, "wait"))
4206 connect = 1; /* wait */
4208 Perl_croak(aTHX_ "OS2::pipe(): unknown connect argument: `%s'", s);
4214 count = (int)SvIV(ST(3));
4217 ulInbufLength = 8192;
4219 ulInbufLength = (ULONG)SvUV(ST(4));
4222 ulOutbufLength = ulInbufLength;
4224 ulOutbufLength = (ULONG)SvUV(ST(5));
4226 if (count < -1 || count == 0 || count >= 255)
4227 Perl_croak(aTHX_ "OS2::pipe(): count should be -1 or between 1 and 254: %ld", (long)count);
4229 count = 255; /* Unlimited */
4233 ulPipeMode |= (NP_WAIT
4234 | (message ? NP_TYPE_MESSAGE : NP_TYPE_BYTE)
4235 | (message_r ? NP_READMODE_MESSAGE : NP_READMODE_BYTE));
4237 ulPipeMode |= (ULONG)SvUV(ST(6));
4242 timeout = (double)SvNV(ST(7));
4243 ulTimeout = timeout * 1000;
4245 ulTimeout = 0xFFFFFFFF; /* Indefinite */
4246 else if (timeout && !ulTimeout)
4249 RETVAL = DosCreateNPipe(pszName, &hpipe, ulOpenMode, ulPipeMode, ulInbufLength, ulOutbufLength, ulTimeout);
4250 if (CheckOSError(RETVAL))
4251 croak_with_os2error("OS2::pipe(): DosCreateNPipe() error");
4254 connectNPipe(hpipe, connect, 1, 0); /* XXXX wait, retval */
4255 hpipe = __imphandle(hpipe);
4257 perlio = PerlIO_fdopen(hpipe, buf);
4258 ST(0) = sv_newmortal();
4260 GV *gv = newGVgen("OS2::pipe");
4261 if ( do_open6(gv, perltype, strlen(perltype), perlio, NULL, 0) )
4262 sv_setsv(ST(0), sv_bless(newRV((SV*)gv), gv_stashpv("IO::Handle",1)));
4264 ST(0) = &PL_sv_undef;
4270 XS(XS_OS2_pipeCntl); /* prototype to pass -Wmissing-prototypes */
4274 if (items < 2 || items > 3)
4275 Perl_croak(aTHX_ "Usage: OS2::pipeCntl(pipe, op [, wait])");
4278 PerlIO *perlio = IoIFP(sv_2io(ST(0)));
4279 IV fn = PerlIO_fileno(perlio);
4280 HPIPE hpipe = (HPIPE)fn;
4282 char *s = SvPV(ST(1), len);
4283 int wait = 0, disconnect = 0, connect = 0, message = -1, query = 0;
4284 int peek = 0, state = 0, info = 0;
4287 Perl_croak(aTHX_ "OS2::pipeCntl(): not a pipe");
4289 wait = (SvTRUE(ST(2)) ? 1 : -1);
4293 if (strEQ(s, "byte"))
4295 else if (strEQ(s, "peek"))
4297 else if (strEQ(s, "info"))
4303 if (strEQ(s, "reset"))
4304 disconnect = connect = 1;
4305 else if (strEQ(s, "state"))
4311 if (strEQ(s, "connect"))
4313 else if (strEQ(s, "message"))
4319 if (!strEQ(s, "readstate"))
4324 if (!strEQ(s, "disconnect"))
4330 Perl_croak(aTHX_ "OS2::pipeCntl(): unknown argument: `%s'", s);
4334 if (items == 3 && !connect)
4335 Perl_croak(aTHX_ "OS2::pipeCntl(): no wait argument for `%s'", s);
4337 XSprePUSH; /* Do not need arguments any more */
4339 os2cp_croak(DosDisConnectNPipe(hpipe), "OS2::pipeCntl(): DosDisConnectNPipe()");
4340 PerlIO_clearerr(perlio);
4343 if (!connectNPipe(hpipe, wait , 1, 0))
4349 os2cp_croak(DosQueryNPHState(hpipe, &flags), "DosQueryNPHState()");
4352 if (peek || state || info) {
4353 ULONG BytesRead, PipeState;
4354 AVAILDATA BytesAvail;
4356 os2cp_croak( DosPeekNPipe(hpipe, NULL, 0, &BytesRead, &BytesAvail,
4357 &PipeState), "DosPeekNPipe() for state");
4361 /* Bytes (available/in-message) */
4362 mPUSHi(BytesAvail.cbpipe);
4363 mPUSHi(BytesAvail.cbmessage);
4367 ID of the (remote) computer
4369 instances (max/actual)
4371 struct pipe_info_t {
4372 ULONG id; /* char id[4]; */
4378 os2cp_croak( DosQueryNPipeInfo(hpipe, 1, &b.pInfo, sizeof(b) - STRUCT_OFFSET(struct pipe_info_t, pInfo)),
4379 "DosQueryNPipeInfo(1)");
4380 os2cp_croak( DosQueryNPipeInfo(hpipe, 2, &b.id, sizeof(b.id)),
4381 "DosQueryNPipeInfo(2)");
4382 size = b.pInfo.cbName;
4383 /* Trailing 0 is included in cbName - undocumented; so
4384 one should always extract with Z* */
4385 if (size) /* name length 254 or less */
4388 size = strlen(b.pInfo.szName);
4390 mPUSHp(b.pInfo.szName, size);
4392 mPUSHi(b.pInfo.cbOut);
4393 mPUSHi(b.pInfo.cbIn);
4394 mPUSHi(b.pInfo.cbMaxInst);
4395 mPUSHi(b.pInfo.cbCurInst);
4397 } else if (BytesAvail.cbpipe == 0) {
4400 SV *tmp = NEWSV(914, BytesAvail.cbpipe);
4401 char *s = SvPVX(tmp);
4404 os2cp_croak( DosPeekNPipe(hpipe, s, BytesAvail.cbpipe, &BytesRead,
4405 &BytesAvail, &PipeState), "DosPeekNPipe()");
4406 SvCUR_set(tmp, BytesRead);
4409 XSprePUSH; PUSHs(tmp);
4414 ULONG oflags, flags;
4416 os2cp_croak(DosQueryNPHState(hpipe, &oflags), "DosQueryNPHState()");
4417 /* DosSetNPHState fails if more bits than NP_NOWAIT|NP_READMODE_MESSAGE */
4418 oflags &= (NP_NOWAIT | NP_READMODE_MESSAGE);
4419 flags = (oflags & NP_NOWAIT)
4420 | (message ? NP_READMODE_MESSAGE : NP_READMODE_BYTE);
4421 if (flags != oflags)
4422 os2cp_croak(DosSetNPHState(hpipe, flags), "DosSetNPHState()");
4430 DosOpen(PCSZ pszFileName, OUTLIST HFILE hFile, OUTLIST ULONG ulAction, ULONG ulOpenFlags, ULONG ulOpenMode = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, ULONG ulAttribute = FILE_NORMAL, ULONG ulFileSize = 0, PEAOP2 pEABuf = NULL);
4434 pszFileName, &hFile, &ulAction, ulFileSize, ulAttribute, ulOpenFlags, ulOpenMode, pEABuf
4436 if (CheckOSError(RETVAL))
4437 croak_with_os2error("OS2::open() error");
4439 XS(XS_OS2_open); /* prototype to pass -Wmissing-prototypes */
4443 if (items < 2 || items > 6)
4444 Perl_croak(aTHX_ "Usage: OS2::open(pszFileName, ulOpenMode, ulOpenFlags= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, ulAttribute= FILE_NORMAL, ulFileSize= 0, pEABuf= NULL)");
4450 PCSZ pszFileName = ( SvOK(ST(0)) ? (PCSZ)SvPV_nolen(ST(0)) : NULL );
4453 ULONG ulOpenMode = (ULONG)SvUV(ST(1));
4460 ulOpenFlags = OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
4462 ulOpenFlags = (ULONG)SvUV(ST(2));
4466 ulAttribute = FILE_NORMAL;
4468 ulAttribute = (ULONG)SvUV(ST(3));
4474 ulFileSize = (ULONG)SvUV(ST(4));
4480 pEABuf = (PEAOP2)SvUV(ST(5));
4483 RETVAL = DosOpen(pszFileName, &hFile, &ulAction, ulFileSize, ulAttribute, ulOpenFlags, ulOpenMode, pEABuf);
4484 if (CheckOSError(RETVAL))
4485 croak_with_os2error("OS2::open() error");
4486 XSprePUSH; EXTEND(SP,2);
4487 PUSHs(sv_newmortal());
4488 sv_setuv(ST(0), (UV)hFile);
4489 PUSHs(sv_newmortal());
4490 sv_setuv(ST(1), (UV)ulAction);
4498 char *file = __FILE__;
4502 if (_emx_env & 0x200) { /* OS/2 */
4503 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
4504 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
4505 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
4506 newXS("OS2::extLibpath", XS_Cwd_extLibpath, file);
4507 newXS("OS2::extLibpath_set", XS_Cwd_extLibpath_set, file);
4509 newXS("OS2::Error", XS_OS2_Error, file);
4510 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
4511 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
4512 newXSproto("OS2::DevCap", XS_OS2_DevCap, file, ";$$");
4513 newXSproto("OS2::SysInfoFor", XS_OS2_SysInfoFor, file, "$;$");
4514 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
4515 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
4516 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
4517 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
4518 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
4519 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
4520 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
4521 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
4522 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
4523 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
4524 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
4525 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
4526 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
4527 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
4528 newXS("OS2::replaceModule", XS_OS2_replaceModule, file);
4529 newXS("OS2::perfSysCall", XS_OS2_perfSysCall, file);
4530 newXSproto("OS2::_control87", XS_OS2__control87, file, "$$");
4531 newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
4532 newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
4533 newXSproto("OS2::DLLname", XS_OS2_DLLname, file, ";$$");
4534 newXSproto("OS2::mytype", XS_OS2_mytype, file, ";$");
4535 newXSproto("OS2::mytype_set", XS_OS2_mytype_set, file, "$");
4536 newXSproto("OS2::_headerInfo", XS_OS2__headerInfo, file, "$$;$$");
4537 newXSproto("OS2::libPath", XS_OS2_libPath, file, "");
4538 newXSproto("OS2::Timer", XS_OS2_Timer, file, "");
4539 newXSproto("OS2::msCounter", XS_OS2_msCounter, file, "");
4540 newXSproto("OS2::ms_sleep", XS_OS2_ms_sleep, file, "$;$");
4541 newXSproto("OS2::_InfoTable", XS_OS2__InfoTable, file, ";$");
4542 newXSproto("OS2::incrMaxFHandles", XS_OS2_incrMaxFHandles, file, ";$");
4543 newXSproto("OS2::SysValues", XS_OS2_SysValues, file, ";$$");
4544 newXSproto("OS2::SysValues_set", XS_OS2_SysValues_set, file, "$$;$");
4545 newXSproto("OS2::Beep", XS_OS2_Beep, file, ";$$");
4546 newXSproto("OS2::pipe", XS_OS2_pipe, file, "$$;$$$$$$");
4547 newXSproto("OS2::pipeCntl", XS_OS2_pipeCntl, file, "$$;$");
4548 newXSproto("OS2::open", XS_OS2_open, file, "$$;$$$$");
4549 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
4552 sv_setiv(GvSV(gv), 1);
4554 gv = gv_fetchpv("OS2::is_static", TRUE, SVt_PV);
4557 sv_setiv(GvSV(gv), 1);
4559 gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV);
4561 sv_setiv(GvSV(gv), exe_is_aout());
4562 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
4564 sv_setiv(GvSV(gv), _emx_rev);
4565 sv_setpv(GvSV(gv), _emx_vprt);
4567 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
4569 sv_setiv(GvSV(gv), _emx_env);
4570 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
4572 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
4573 gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
4575 sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
4580 extern void _emx_init(void*);
4582 static void jmp_out_of_atexit(void);
4584 #define FORCE_EMX_INIT_CONTRACT_ARGV 1
4585 #define FORCE_EMX_INIT_INSTALL_ATEXIT 2
4588 my_emx_init(void *layout) {
4589 static volatile void *old_esp = 0; /* Cannot be on stack! */
4591 /* Can't just call emx_init(), since it moves the stack pointer */
4592 /* It also busts a lot of registers, so be extra careful */
4600 "popf\n" : : "r" (layout), "m" (old_esp) );
4603 struct layout_table_t {
4624 static ULONG osv_res; /* Cannot be on stack! */
4626 /* Can't just call __os_version(), since it does not follow C
4627 calling convention: it busts a lot of registers, so be extra careful */
4630 "call ___os_version\n"
4633 "popf\n" : "=m" (osv_res) );
4639 force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags)
4641 /* Calling emx_init() will bust the top of stack: it installs an
4642 exception handler and puts argv data there. */
4643 char *oldarg, *oldenv;
4644 void *oldstackend, *oldstack;
4647 ULONG rc, error = 0, out;
4649 static struct layout_table_t layout_table;
4651 char buf[48*1024]; /* _emx_init() requires 32K, cmd.exe has 64K only */
4653 EXCEPTIONREGISTRATIONRECORD xreg;
4657 layout_table.os2_dll = (ULONG)&os2_dll_fake;
4658 layout_table.flags = 0x02000002; /* flags: application, OMF */
4660 DosGetInfoBlocks(&tib, &pib);
4661 oldarg = pib->pib_pchcmd;
4662 oldenv = pib->pib_pchenv;
4663 oldstack = tib->tib_pstack;
4664 oldstackend = tib->tib_pstacklimit;
4666 if ( (char*)&s < (char*)oldstack + 4*1024
4667 || (char *)oldstackend < (char*)oldstack + 52*1024 )
4668 early_error("It is a lunacy to try to run EMX Perl ",
4669 "with less than 64K of stack;\r\n",
4670 " at least with non-EMX starter...\r\n");
4672 /* Minimize the damage to the stack via reducing the size of argv. */
4673 if (flags & FORCE_EMX_INIT_CONTRACT_ARGV) {
4674 pib->pib_pchcmd = "\0\0"; /* Need 3 concatenated strings */
4675 pib->pib_pchcmd = "\0"; /* Ended by an extra \0. */
4678 newstack = alloca(sizeof(*newstack));
4679 /* Emulate the stack probe */
4680 s = ((char*)newstack) + sizeof(*newstack);
4681 while (s > (char*)newstack) {
4686 /* Reassigning stack is documented to work */
4687 tib->tib_pstack = (void*)newstack;
4688 tib->tib_pstacklimit = (void*)((char*)newstack + sizeof(*newstack));
4690 /* Can't just call emx_init(), since it moves the stack pointer */
4691 my_emx_init((void*)&layout_table);
4693 /* Remove the exception handler, cannot use it - too low on the stack.
4694 Check whether it is inside the new stack. */
4696 if (tib->tib_pexchain >= tib->tib_pstacklimit
4697 || tib->tib_pexchain < tib->tib_pstack) {
4700 "panic: ExceptionHandler misplaced: not %#lx <= %#lx < %#lx\n",
4701 (unsigned long)tib->tib_pstack,
4702 (unsigned long)tib->tib_pexchain,
4703 (unsigned long)tib->tib_pstacklimit);
4706 if (tib->tib_pexchain != &(newstack->xreg)) {
4707 sprintf(buf, "ExceptionHandler misplaced: %#lx != %#lx\n",
4708 (unsigned long)tib->tib_pexchain,
4709 (unsigned long)&(newstack->xreg));
4711 rc = DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)tib->tib_pexchain);
4713 sprintf(buf + strlen(buf),
4714 "warning: DosUnsetExceptionHandler rc=%#lx=%lu\n", rc, rc);
4717 /* ExceptionRecords should be on stack, in a correct order. Sigh... */
4718 preg->prev_structure = 0;
4719 preg->ExceptionHandler = _emx_exception;
4720 rc = DosSetExceptionHandler(preg);
4722 sprintf(buf + strlen(buf),
4723 "warning: DosSetExceptionHandler rc=%#lx=%lu\n", rc, rc);
4724 DosWrite(2, buf, strlen(buf), &out);
4725 emx_exception_init = 1; /* Do it around spawn*() calls */
4728 emx_exception_init = 1; /* Do it around spawn*() calls */
4731 /* Restore the damage */
4732 pib->pib_pchcmd = oldarg;
4733 pib->pib_pchcmd = oldenv;
4734 tib->tib_pstacklimit = oldstackend;
4735 tib->tib_pstack = oldstack;
4736 emx_runtime_init = 1;
4738 DosWrite(2, buf, strlen(buf), &out);
4744 jmp_out_of_atexit(void)
4746 if (longjmp_at_exit)
4747 longjmp(at_exit_buf, 1);
4750 extern void _CRT_term(void);
4753 Perl_OS2_term(void **p, int exitstatus, int flags)
4755 if (!emx_runtime_secondary)
4758 /* The principal executable is not running the same CRTL, so there
4759 is nobody to shutdown *this* CRTL except us... */
4760 if (flags & FORCE_EMX_DEINIT_EXIT) {
4761 if (p && !emx_exception_init)
4762 DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
4763 /* Do not run the executable's CRTL's termination routines */
4764 exit(exitstatus); /* Run at-exit, flush buffers, etc */
4766 /* Run at-exit list, and jump out at the end */
4767 if ((flags & FORCE_EMX_DEINIT_RUN_ATEXIT) && !setjmp(at_exit_buf)) {
4768 longjmp_at_exit = 1;
4769 exit(exitstatus); /* The first pass through "if" */
4772 /* Get here if we managed to jump out of exit(), or did not run atexit. */
4773 longjmp_at_exit = 0; /* Maybe exit() is called again? */
4774 #if 0 /* _atexit_n is not exported */
4775 if (flags & FORCE_EMX_DEINIT_RUN_ATEXIT)
4776 _atexit_n = 0; /* Remove the atexit() handlers */
4778 /* Will segfault on program termination if we leave this dangling... */
4779 if (p && !emx_exception_init)
4780 DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
4781 /* Typically there is no need to do this, done from _DLL_InitTerm() */
4782 if (flags & FORCE_EMX_DEINIT_CRT_TERM)
4783 _CRT_term(); /* Flush buffers, etc. */
4784 /* Now it is a good time to call exit() in the caller's CRTL... */
4787 #include <emx/startup.h>
4789 extern ULONG __os_version(); /* See system.doc */
4792 check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg)
4794 ULONG v_crt, v_emx, count = 0, rc = NO_ERROR, rc1, maybe_inited = 0;
4795 static HMTX hmtx_emx_init = NULLHANDLE;
4796 static int emx_init_done = 0;
4798 /* If _environ is not set, this code sits in a DLL which
4799 uses a CRT DLL which not compatible with the executable's
4800 CRT library. Some parts of the DLL are not initialized.
4802 if (_environ != NULL)
4803 return; /* Properly initialized */
4805 /* It is not DOS, so we may use OS/2 API now */
4806 /* Some data we manipulate is static; protect ourselves from
4807 calling the same API from a different thread. */
4808 DosEnterMustComplete(&count);
4810 rc1 = DosEnterCritSec();
4812 rc = DosCreateMutexSem(NULL, &hmtx_emx_init, 0, TRUE); /*Create owned*/
4817 hmtx_emx_init = NULLHANDLE;
4819 if (rc1 == NO_ERROR)
4821 DosExitMustComplete(&count);
4823 while (maybe_inited) { /* Other thread did or is doing the same now */
4826 rc = DosRequestMutexSem(hmtx_emx_init,
4827 (ULONG) SEM_INDEFINITE_WAIT); /* Timeout (none) */
4828 if (rc == ERROR_INTERRUPT)
4830 if (rc != NO_ERROR) {
4835 "panic: EMX backdoor init: DosRequestMutexSem error: %lu=%#lx\n", rc, rc);
4836 DosWrite(2, buf, strlen(buf), &out);
4839 DosReleaseMutexSem(hmtx_emx_init);
4843 /* If the executable does not use EMX.DLL, EMX.DLL is not completely
4844 initialized either. Uninitialized EMX.DLL returns 0 in the low
4845 nibble of __os_version(). */
4846 v_emx = my_os_version();
4848 /* _osmajor and _osminor are normally set in _DLL_InitTerm of CRT DLL
4849 (=>_CRT_init=>_entry2) via a call to __os_version(), then
4850 reset when the EXE initialization code calls _text=>_init=>_entry2.
4851 The first time they are wrongly set to 0; the second time the
4852 EXE initialization code had already called emx_init=>initialize1
4853 which correctly set version_major, version_minor used by
4855 v_crt = (_osmajor | _osminor);
4857 if ((_emx_env & 0x200) && !(v_emx & 0xFFFF)) { /* OS/2, EMX uninit. */
4858 force_init_emx_runtime( preg,
4859 FORCE_EMX_INIT_CONTRACT_ARGV
4860 | FORCE_EMX_INIT_INSTALL_ATEXIT );
4861 emx_wasnt_initialized = 1;
4862 /* Update CRTL data basing on now-valid EMX runtime data */
4863 if (!v_crt) { /* The only wrong data are the versions. */
4864 v_emx = my_os_version(); /* *Now* it works */
4865 *(unsigned char *)&_osmajor = v_emx & 0xFF; /* Cast out const */
4866 *(unsigned char *)&_osminor = (v_emx>>8) & 0xFF;
4869 emx_runtime_secondary = 1;
4870 /* if (flags & FORCE_EMX_INIT_INSTALL_ATEXIT) */
4871 atexit(jmp_out_of_atexit); /* Allow run of atexit() w/o exit() */
4873 if (env == NULL) { /* Fetch from the process info block */
4879 DosGetInfoBlocks(&tib, &pib);
4880 e = pib->pib_pchenv;
4881 while (*e) { /* Get count */
4883 e = e + strlen(e) + 1;
4885 Newx(env, c + 1, char*);
4887 e = pib->pib_pchenv;
4890 e = e + strlen(e) + 1;
4894 _environ = _org_environ = env;
4897 DosReleaseMutexSem(hmtx_emx_init);
4900 #define ENTRY_POINT 0x10000
4905 struct layout_table_t *layout;
4906 if (emx_wasnt_initialized)
4908 /* Now we know that the principal executable is an EMX application
4909 - unless somebody did already play with delayed initialization... */
4910 /* With EMX applications to determine whether it is AOUT one needs
4911 to examine the start of the executable to find "layout" */
4912 if ( *(unsigned char*)ENTRY_POINT != 0x68 /* PUSH n */
4913 || *(unsigned char*)(ENTRY_POINT+5) != 0xe8 /* CALL */
4914 || *(unsigned char*)(ENTRY_POINT+10) != 0xeb /* JMP */
4915 || *(unsigned char*)(ENTRY_POINT+12) != 0xe8) /* CALL */
4916 return 0; /* ! EMX executable */
4918 Copy((char*)(ENTRY_POINT+1), &layout, 1, struct layout_table_t*);
4919 return !(layout->flags & 2);
4923 Perl_OS2_init(char **env)
4925 Perl_OS2_init3(env, 0, 0);
4929 Perl_OS2_init3(char **env, void **preg, int flags)
4934 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
4937 check_emx_runtime(env, (EXCEPTIONREGISTRATIONRECORD *)preg);
4940 OS2_Perl_data.xs_init = &Xs_OS2_init;
4941 if (perl_sh_installed) {
4942 int l = strlen(perl_sh_installed);
4944 Newx(PL_sh_path, l + 1, char);
4945 memcpy(PL_sh_path, perl_sh_installed, l + 1);
4946 } else if ( (shell = getenv("PERL_SH_DRIVE")) ) {
4947 Newx(PL_sh_path, strlen(SH_PATH) + 1, char);
4948 strcpy(PL_sh_path, SH_PATH);
4949 PL_sh_path[0] = shell[0];
4950 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
4951 int l = strlen(shell), i;
4953 while (l && (shell[l-1] == '/' || shell[l-1] == '\\'))
4955 Newx(PL_sh_path, l + 8, char);
4956 strncpy(PL_sh_path, shell, l);
4957 strcpy(PL_sh_path + l, "/sh.exe");
4958 for (i = 0; i < l; i++) {
4959 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
4962 MUTEX_INIT(&start_thread_mutex);
4963 MUTEX_INIT(&perlos2_state_mutex);
4964 os2_mytype = my_type(); /* Do it before morphing. Needed? */
4965 os2_mytype_ini = os2_mytype;
4966 Perl_os2_initial_mode = -1; /* Uninit */
4968 s = getenv("PERL_BEGINLIBPATH");
4970 rc = fill_extLibpath(0, s, NULL, 1, "PERL_BEGINLIBPATH");
4972 rc = fill_extLibpath(0, getenv("PERL_PRE_BEGINLIBPATH"), getenv("PERL_POST_BEGINLIBPATH"), 0, "PERL_(PRE/POST)_BEGINLIBPATH");
4974 s = getenv("PERL_ENDLIBPATH");
4976 rc = fill_extLibpath(1, s, NULL, 1, "PERL_ENDLIBPATH");
4978 rc = fill_extLibpath(1, getenv("PERL_PRE_ENDLIBPATH"), getenv("PERL_POST_ENDLIBPATH"), 0, "PERL_(PRE/POST)_ENDLIBPATH");
4983 snprintf(buf, sizeof buf, "Error setting BEGIN/ENDLIBPATH: %s\n",
4985 DosWrite(2, buf, strlen(buf), &rc);
4989 _emxload_env("PERL_EMXLOAD_SECS");
4990 /* Some DLLs reset FP flags on load. We may have been linked with them */
4991 _control87(MCW_EM, MCW_EM);
4997 static ULONG max_fh = 0;
4999 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
5000 if (fd >= max_fh) { /* Renew */
5003 if (DosSetRelMaxFH(&delta, &max_fh)) /* Assume it OK??? */
5009 /* Kernels up to Oct 2003 trap on (invalid) dup(max_fh); [off-by-one + double fault]. */
5011 dup2(int from, int to)
5013 if (fd_ok(from < to ? to : from))
5014 return _dup2(from, to);
5032 my_tmpnam (char *str)
5034 char *p = getenv("TMP"), *tpath;
5036 if (!p) p = getenv("TEMP");
5037 tpath = tempnam(p, "pltmp");
5051 if (s.st_mode & S_IWOTH) {
5054 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
5060 /* EMX flavors do not tolerate trailing slashes. t/op/mkdir.t has many
5061 trailing slashes, so we need to support this as well. */
5064 my_rmdir (__const__ char *s)
5068 STRLEN l = strlen(s);
5071 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
5073 Newx(buf, l + 1, char);
5075 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
5089 my_mkdir (__const__ char *s, long perm)
5093 STRLEN l = strlen(s);
5096 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
5098 Newx(buf, l + 1, char);
5100 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
5105 rc = mkdir(s, perm);
5113 /* This code was contributed by Rocco Caputo. */
5115 my_flock(int handle, int o)
5117 FILELOCK rNull, rFull;
5118 ULONG timeout, handle_type, flag_word;
5120 int blocking, shared;
5121 static int use_my_flock = -1;
5123 if (use_my_flock == -1) {
5124 MUTEX_LOCK(&perlos2_state_mutex);
5125 if (use_my_flock == -1) {
5126 char *s = getenv("USE_PERL_FLOCK");
5128 use_my_flock = atoi(s);
5132 MUTEX_UNLOCK(&perlos2_state_mutex);
5134 if (!(_emx_env & 0x200) || !use_my_flock)
5135 return flock(handle, o); /* Delegate to EMX. */
5137 /* is this a file? */
5138 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
5139 (handle_type & 0xFF))
5144 /* set lock/unlock ranges */
5145 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
5146 rFull.lRange = 0x7FFFFFFF;
5147 /* set timeout for blocking */
5148 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
5149 /* shared or exclusive? */
5150 shared = (o & LOCK_SH) ? 1 : 0;
5151 /* do not block the unlock */
5152 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
5153 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
5158 case ERROR_INVALID_HANDLE:
5161 case ERROR_SHARING_BUFFER_EXCEEDED:
5164 case ERROR_LOCK_VIOLATION:
5165 break; /* not an error */
5166 case ERROR_INVALID_PARAMETER:
5167 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
5168 case ERROR_READ_LOCKS_NOT_SUPPORTED:
5171 case ERROR_INTERRUPT:
5179 /* lock may block */
5180 if (o & (LOCK_SH | LOCK_EX)) {
5181 /* for blocking operations */
5195 case ERROR_INVALID_HANDLE:
5198 case ERROR_SHARING_BUFFER_EXCEEDED:
5201 case ERROR_LOCK_VIOLATION:
5203 errno = EWOULDBLOCK;
5207 case ERROR_INVALID_PARAMETER:
5208 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
5209 case ERROR_READ_LOCKS_NOT_SUPPORTED:
5212 case ERROR_INTERRUPT:
5219 /* give away timeslice */
5231 if (_my_pwent == -1) {
5232 char *s = getenv("USE_PERL_PWENT");
5234 _my_pwent = atoi(s);
5248 if (!use_my_pwent()) {
5249 setpwent(); /* Delegate to EMX. */
5258 if (!use_my_pwent()) {
5259 endpwent(); /* Delegate to EMX. */
5267 if (!use_my_pwent())
5268 return getpwent(); /* Delegate to EMX. */
5270 return 0; /* Return one entry only */
5289 return 0; /* Return one entry only */
5296 /* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */
5297 static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK";
5299 static struct passwd *
5300 passw_wrap(struct passwd *p)
5304 if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
5307 s = getenv("PW_PASSWD");
5309 s = (char*)pw_p; /* Make match impossible */
5316 my_getpwuid (uid_t id)
5318 return passw_wrap(getpwuid(id));
5322 my_getpwnam (__const__ char *n)
5324 return passw_wrap(getpwnam(n));
5328 gcvt_os2 (double value, int digits, char *buffer)
5330 double absv = value > 0 ? value : -value;
5331 /* EMX implementation is lousy between 0.1 and 0.0001 (uses exponents below
5332 0.1), 1-digit stuff is ok below 0.001; multi-digit below 0.0001. */
5336 buggy = (absv < 1000 && (absv >= 10 || (absv > 1 && floor(absv) != absv)));
5341 sprintf(pat, "%%.%dg", digits);
5342 sprintf(buffer, pat, value);
5345 return gcvt (value, digits, buffer);
5349 int fork_with_resources()
5351 #if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
5353 void *ctx = PERL_GET_CONTEXT;
5355 unsigned fpflag = _control87(0,0);
5358 if (rc == 0) { /* child */
5359 #if (defined(USE_5005THREADS) || defined(USE_ITHREADS)) && !defined(USE_SLOW_THREAD_SPECIFIC)
5360 ALLOC_THREAD_KEY; /* Acquire the thread-local memory */
5361 PERL_SET_CONTEXT(ctx); /* Reinit the thread-local memory */
5364 { /* Reload loaded-on-demand DLLs */
5365 struct dll_handle_t *dlls = dll_handles;
5367 while (dlls->modname) {
5368 char dllname[260], fail[260];
5371 if (!dlls->handle) { /* Was not loaded */
5375 /* It was loaded in the parent. We need to reload it. */
5377 rc = DosQueryModuleName(dlls->handle, sizeof(dllname), dllname);
5379 Perl_warn_nocontext("Can't find DLL name for the module `%s' by the handle %d, rc=%lu=%#lx",
5380 dlls->modname, (int)dlls->handle, rc, rc);
5384 rc = DosLoadModule(fail, sizeof fail, dllname, &dlls->handle);
5386 Perl_warn_nocontext("Can't load DLL `%s', possible problematic module `%s'",
5392 { /* Support message queue etc. */
5393 os2_mytype = my_type();
5394 /* Apparently, subprocesses (in particular, fork()) do not
5395 inherit the morphed state, so os2_mytype is the same as
5398 if (Perl_os2_initial_mode != -1
5399 && Perl_os2_initial_mode != os2_mytype) {
5404 (void)_obtain_Perl_HAB;
5405 if (Perl_hmq_refcnt) {
5408 Create_HMQ(Perl_hmq_servers != 0,
5409 "Cannot create a message queue on fork");
5412 /* We may have loaded some modules */
5413 _control87(fpflag, MCW_EM); /* Some modules reset FP flags on (un)load */
5418 /* APIRET APIENTRY DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal); */
5420 ULONG _THUNK_FUNCTION(Dos16GetInfoSeg)(USHORT *pGlobal, USHORT *pLocal);
5423 myDosGetInfoSeg(PGINFOSEG *pGlobal, PLINFOSEG *pLocal)
5426 USHORT gSel, lSel; /* Will not cross 64K boundary */
5429 (_THUNK_PROLOG (4+4);
5430 _THUNK_FLAT (&gSel);
5431 _THUNK_FLAT (&lSel);
5432 _THUNK_CALL (Dos16GetInfoSeg)));
5435 *pGlobal = MAKEPGINFOSEG(gSel);
5436 *pLocal = MAKEPLINFOSEG(lSel);
5445 MUTEX_LOCK(&perlos2_state_mutex);
5447 rc = myDosGetInfoSeg(&gTable, &lTable);
5448 MUTEX_UNLOCK(&perlos2_state_mutex);
5449 os2cp_croak(rc, "Dos16GetInfoSeg");
5454 { /* XXXX Is not lTable thread-specific? */
5457 return gTable->SIS_MsCount;
5461 InfoTable(int local)
5465 return local ? (ULONG)lTable : (ULONG)gTable;