3 #define INCL_DOSFILEMGR
6 /* These 3 are needed for compile if os2.h includes os2tk.h, not os2emx.h */
7 #define INCL_DOSPROCESS
8 #define SPU_DISABLESUPPRESSION 0
9 #define SPU_ENABLESUPPRESSION 1
13 #include <sys/uflags.h>
16 * Various Unix compatibility functions for OS/2
27 #define PERLIO_NOT_STDIO 0
32 static int exe_is_aout(void);
34 /*****************************************************************************/
35 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
36 #define C_ARR_LEN(sym) (sizeof(sym)/sizeof(*sym))
42 static struct dll_handle doscalls_handle = {"doscalls", 0};
43 static struct dll_handle tcp_handle = {"tcp32dll", 0};
44 static struct dll_handle pmwin_handle = {"pmwin", 0};
45 static struct dll_handle rexx_handle = {"rexx", 0};
46 static struct dll_handle rexxapi_handle = {"rexxapi", 0};
47 static struct dll_handle sesmgr_handle = {"sesmgr", 0};
48 static struct dll_handle pmshapi_handle = {"pmshapi", 0};
50 /* This should match enum entries_ordinals defined in os2ish.h. */
52 struct dll_handle *dll;
53 const char *entryname;
55 } loadOrdinals[ORD_NENTRIES] = {
56 {&doscalls_handle, NULL, 874}, /* DosQueryExtLibpath */
57 {&doscalls_handle, NULL, 873}, /* DosSetExtLibpath */
58 {&doscalls_handle, NULL, 460}, /* DosVerifyPidTid */
59 {&tcp_handle, "SETHOSTENT", 0},
60 {&tcp_handle, "SETNETENT" , 0},
61 {&tcp_handle, "SETPROTOENT", 0},
62 {&tcp_handle, "SETSERVENT", 0},
63 {&tcp_handle, "GETHOSTENT", 0},
64 {&tcp_handle, "GETNETENT" , 0},
65 {&tcp_handle, "GETPROTOENT", 0},
66 {&tcp_handle, "GETSERVENT", 0},
67 {&tcp_handle, "ENDHOSTENT", 0},
68 {&tcp_handle, "ENDNETENT", 0},
69 {&tcp_handle, "ENDPROTOENT", 0},
70 {&tcp_handle, "ENDSERVENT", 0},
71 {&pmwin_handle, NULL, 763}, /* WinInitialize */
72 {&pmwin_handle, NULL, 716}, /* WinCreateMsgQueue */
73 {&pmwin_handle, NULL, 726}, /* WinDestroyMsgQueue */
74 {&pmwin_handle, NULL, 918}, /* WinPeekMsg */
75 {&pmwin_handle, NULL, 915}, /* WinGetMsg */
76 {&pmwin_handle, NULL, 912}, /* WinDispatchMsg */
77 {&pmwin_handle, NULL, 753}, /* WinGetLastError */
78 {&pmwin_handle, NULL, 705}, /* WinCancelShutdown */
79 /* These are needed in extensions.
80 How to protect PMSHAPI: it comes through EMX functions? */
81 {&rexx_handle, "RexxStart", 0},
82 {&rexx_handle, "RexxVariablePool", 0},
83 {&rexxapi_handle, "RexxRegisterFunctionExe", 0},
84 {&rexxapi_handle, "RexxDeregisterFunction", 0},
85 {&sesmgr_handle, "DOSSMSETTITLE", 0}, /* Would not work runtime-loaded */
86 {&pmshapi_handle, "PRF32QUERYPROFILESIZE", 0},
87 {&pmshapi_handle, "PRF32OPENPROFILE", 0},
88 {&pmshapi_handle, "PRF32CLOSEPROFILE", 0},
89 {&pmshapi_handle, "PRF32QUERYPROFILE", 0},
90 {&pmshapi_handle, "PRF32RESET", 0},
91 {&pmshapi_handle, "PRF32QUERYPROFILEDATA", 0},
92 {&pmshapi_handle, "PRF32WRITEPROFILEDATA", 0},
94 /* At least some of these do not work by name, since they need
95 WIN32 instead of WIN... */
97 These were generated with
98 nm I:\emx\lib\os2.a | fgrep -f API-list | grep = > API-list-entries
99 perl -wnle "next unless /^0+\s+E\s+_(\w+)=(\w+).(\d+)/; print qq( ORD_$1,)" API-list-entries > API-list-ORD_
100 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
102 {&pmshapi_handle, NULL, 123}, /* WinChangeSwitchEntry */
103 {&pmshapi_handle, NULL, 124}, /* WinQuerySwitchEntry */
104 {&pmshapi_handle, NULL, 125}, /* WinQuerySwitchHandle */
105 {&pmshapi_handle, NULL, 126}, /* WinQuerySwitchList */
106 {&pmshapi_handle, NULL, 131}, /* WinSwitchToProgram */
107 {&pmwin_handle, NULL, 702}, /* WinBeginEnumWindows */
108 {&pmwin_handle, NULL, 737}, /* WinEndEnumWindows */
109 {&pmwin_handle, NULL, 740}, /* WinEnumDlgItem */
110 {&pmwin_handle, NULL, 756}, /* WinGetNextWindow */
111 {&pmwin_handle, NULL, 768}, /* WinIsChild */
112 {&pmwin_handle, NULL, 799}, /* WinQueryActiveWindow */
113 {&pmwin_handle, NULL, 805}, /* WinQueryClassName */
114 {&pmwin_handle, NULL, 817}, /* WinQueryFocus */
115 {&pmwin_handle, NULL, 834}, /* WinQueryWindow */
116 {&pmwin_handle, NULL, 837}, /* WinQueryWindowPos */
117 {&pmwin_handle, NULL, 838}, /* WinQueryWindowProcess */
118 {&pmwin_handle, NULL, 841}, /* WinQueryWindowText */
119 {&pmwin_handle, NULL, 842}, /* WinQueryWindowTextLength */
120 {&pmwin_handle, NULL, 860}, /* WinSetFocus */
121 {&pmwin_handle, NULL, 875}, /* WinSetWindowPos */
122 {&pmwin_handle, NULL, 877}, /* WinSetWindowText */
123 {&pmwin_handle, NULL, 883}, /* WinShowWindow */
124 {&pmwin_handle, NULL, 772}, /* WinIsWindow */
125 {&pmwin_handle, NULL, 899}, /* WinWindowFromId */
126 {&pmwin_handle, NULL, 900}, /* WinWindowFromPoint */
127 {&pmwin_handle, NULL, 919}, /* WinPostMsg */
128 {&pmwin_handle, NULL, 735}, /* WinEnableWindow */
129 {&pmwin_handle, NULL, 736}, /* WinEnableWindowUpdate */
130 {&pmwin_handle, NULL, 773}, /* WinIsWindowEnabled */
131 {&pmwin_handle, NULL, 774}, /* WinIsWindowShowing */
132 {&pmwin_handle, NULL, 775}, /* WinIsWindowVisible */
133 {&pmwin_handle, NULL, 839}, /* WinQueryWindowPtr */
134 {&pmwin_handle, NULL, 843}, /* WinQueryWindowULong */
135 {&pmwin_handle, NULL, 844}, /* WinQueryWindowUShort */
136 {&pmwin_handle, NULL, 874}, /* WinSetWindowBits */
137 {&pmwin_handle, NULL, 876}, /* WinSetWindowPtr */
138 {&pmwin_handle, NULL, 878}, /* WinSetWindowULong */
139 {&pmwin_handle, NULL, 879}, /* WinSetWindowUShort */
140 {&pmwin_handle, NULL, 813}, /* WinQueryDesktopWindow */
141 {&pmwin_handle, NULL, 851}, /* WinSetActiveWindow */
142 {&doscalls_handle, NULL, 360}, /* DosQueryModFromEIP */
145 static PFN ExtFCN[C_ARR_LEN(loadOrdinals)]; /* Labeled by ord ORD_*. */
146 const Perl_PFN * const pExtFCN = ExtFCN;
147 struct PMWIN_entries_t PMWIN_entries;
150 loadModule(const char *modname, int fail)
152 HMODULE h = (HMODULE)dlopen(modname, 0);
155 Perl_croak_nocontext("Error loading module '%s': %s",
161 loadByOrdinal(enum entries_ordinals ord, int fail)
163 if (ExtFCN[ord] == NULL) {
167 if (!loadOrdinals[ord].dll->handle)
168 loadOrdinals[ord].dll->handle
169 = loadModule(loadOrdinals[ord].dll->modname, fail);
170 if (!loadOrdinals[ord].dll->handle)
171 return 0; /* Possible with FAIL==0 only */
172 if (CheckOSError(DosQueryProcAddr(loadOrdinals[ord].dll->handle,
173 loadOrdinals[ord].entrypoint,
174 loadOrdinals[ord].entryname,&fcn))) {
175 char buf[20], *s = (char*)loadOrdinals[ord].entryname;
180 sprintf(s = buf, "%d", loadOrdinals[ord].entrypoint);
181 Perl_croak_nocontext(
182 "This version of OS/2 does not support %s.%s",
183 loadOrdinals[ord].dll->modname, s);
187 if ((long)ExtFCN[ord] == -1)
188 Perl_croak_nocontext("panic queryaddr");
193 init_PMWIN_entries(void)
197 for (i = ORD_WinInitialize; i <= ORD_WinCancelShutdown; i++)
198 ((PFN*)&PMWIN_entries)[i - ORD_WinInitialize] = loadByOrdinal(i, 1);
201 /*****************************************************/
202 /* socket forwarders without linking with tcpip DLLs */
204 DeclFuncByORD(struct hostent *, gethostent, ORD_GETHOSTENT, (void), ())
205 DeclFuncByORD(struct netent *, getnetent, ORD_GETNETENT, (void), ())
206 DeclFuncByORD(struct protoent *, getprotoent, ORD_GETPROTOENT, (void), ())
207 DeclFuncByORD(struct servent *, getservent, ORD_GETSERVENT, (void), ())
209 DeclVoidFuncByORD(sethostent, ORD_SETHOSTENT, (int x), (x))
210 DeclVoidFuncByORD(setnetent, ORD_SETNETENT, (int x), (x))
211 DeclVoidFuncByORD(setprotoent, ORD_SETPROTOENT, (int x), (x))
212 DeclVoidFuncByORD(setservent, ORD_SETSERVENT, (int x), (x))
214 DeclVoidFuncByORD(endhostent, ORD_ENDHOSTENT, (void), ())
215 DeclVoidFuncByORD(endnetent, ORD_ENDNETENT, (void), ())
216 DeclVoidFuncByORD(endprotoent, ORD_ENDPROTOENT, (void), ())
217 DeclVoidFuncByORD(endservent, ORD_ENDSERVENT, (void), ())
220 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
222 #define QSS_INI_BUFFER 1024
224 ULONG (*pDosVerifyPidTid) (PID pid, TID tid);
225 static int pidtid_lookup;
228 get_sysinfo(ULONG pid, ULONG flags)
231 ULONG rc, buf_len = QSS_INI_BUFFER;
234 if (!pidtid_lookup) {
236 *(PFN*)&pDosVerifyPidTid = loadByOrdinal(ORD_DosVerifyPidTid, 0);
238 if (pDosVerifyPidTid) { /* Warp3 or later */
239 /* Up to some fixpak QuerySysState() kills the system if a non-existent
241 if (CheckOSError(pDosVerifyPidTid(pid, 1)))
244 New(1322, pbuffer, buf_len, char);
245 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
246 rc = QuerySysState(flags, pid, pbuffer, buf_len);
247 while (rc == ERROR_BUFFER_OVERFLOW) {
248 Renew(pbuffer, buf_len *= 2, char);
249 rc = QuerySysState(flags, pid, pbuffer, buf_len);
256 psi = (PQTOPLEVEL)pbuffer;
257 if (psi && pid && pid != psi->procdata->pid) {
259 Perl_croak_nocontext("panic: wrong pid in sysinfo");
264 #define PRIO_ERR 0x1111
274 psi = get_sysinfo(pid, QSS_PROCESS);
277 prio = psi->procdata->threads->priority;
283 setpriority(int which, int pid, int val)
285 ULONG rc, prio = sys_prio(pid);
287 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
288 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
289 /* Do not change class. */
290 return CheckOSError(DosSetPriority((pid < 0)
291 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
293 (32 - val) % 32 - (prio & 0xFF),
296 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
297 /* Documentation claims one can change both class and basevalue,
298 * but I find it wrong. */
299 /* Change class, but since delta == 0 denotes absolute 0, correct. */
300 if (CheckOSError(DosSetPriority((pid < 0)
301 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
302 priors[(32 - val) >> 5] + 1,
306 if ( ((32 - val) % 32) == 0 ) return 0;
307 return CheckOSError(DosSetPriority((pid < 0)
308 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
317 getpriority(int which /* ignored */, int pid)
321 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
323 if (ret == PRIO_ERR) {
326 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
329 /*****************************************************************************/
332 int emx_runtime_init; /* If 1, we need to manually init it */
333 int emx_exception_init; /* If 1, we need to manually set it */
335 /* There is no big sense to make it thread-specific, since signals
336 are delivered to thread 1 only. XXXX Maybe make it into an array? */
337 static int spawn_pid;
338 static int spawn_killed;
341 spawn_sighandler(int sig)
343 /* Some programs do not arrange for the keyboard signals to be
344 delivered to them. We need to deliver the signal manually. */
345 /* We may get a signal only if
346 a) kid does not receive keyboard signal: deliver it;
347 b) kid already died, and we get a signal. We may only hope
348 that the pid number was not reused.
352 sig = SIGKILL; /* Try harder. */
353 kill(spawn_pid, sig);
358 result(pTHX_ int flag, int pid)
361 Signal_t (*ihand)(); /* place to save signal during system() */
362 Signal_t (*qhand)(); /* place to save signal during system() */
368 if (pid < 0 || flag != 0)
374 ihand = rsignal(SIGINT, &spawn_sighandler);
375 qhand = rsignal(SIGQUIT, &spawn_sighandler);
377 r = wait4pid(pid, &status, 0);
378 } while (r == -1 && errno == EINTR);
379 rsignal(SIGINT, ihand);
380 rsignal(SIGQUIT, qhand);
382 PL_statusvalue = (U16)status;
385 return status & 0xFFFF;
387 ihand = rsignal(SIGINT, SIG_IGN);
388 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
389 rsignal(SIGINT, ihand);
390 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
393 return PL_statusvalue;
406 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
415 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
416 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
419 return (pib->pib_ultype);
423 file_type(char *path)
428 if (!(_emx_env & 0x200))
429 Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
430 if (CheckOSError(DosQueryAppType(path, &apptype))) {
432 case ERROR_FILE_NOT_FOUND:
433 case ERROR_PATH_NOT_FOUND:
435 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
437 default: /* Found, but not an
438 executable, or some other
446 static ULONG os2_mytype;
448 /* Spawn/exec a program, revert to shell if needed. */
449 /* global PL_Argv[] contains arguments. */
451 extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *,
452 EXCEPTIONREGISTRATIONRECORD *,
457 do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
463 static char * fargs[4]
464 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
465 char **argsp = fargs;
468 int new_stderr = -1, nostderr = 0;
478 if (strEQ(PL_Argv[0],"/bin/sh"))
479 PL_Argv[0] = PL_sh_path;
481 /* We should check PERL_SH* and PERLLIB_* as well? */
482 if (!really || !*(tmps = SvPV(really, n_a)))
484 if (tmps[0] != '/' && tmps[0] != '\\'
485 && !(tmps[0] && tmps[1] == ':'
486 && (tmps[2] == '/' || tmps[2] != '\\'))
487 ) /* will spawnvp use PATH? */
488 TAINT_ENV(); /* testing IFS here is overkill, probably */
492 if (_emx_env & 0x200) { /* OS/2. */
493 int type = file_type(tmps);
495 if (type == -1) { /* Not found */
500 else if (type == -2) { /* Not an EXE */
505 else if (type == -3) { /* Is a directory? */
506 /* Special-case this */
508 int l = strlen(tmps);
510 if (l + 5 <= sizeof tbuf) {
512 strcpy(tbuf + l, ".exe");
513 type = file_type(tbuf);
523 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
524 case FAPPTYP_WINDOWAPI:
526 if (os2_mytype != 3) { /* not PM */
527 if (flag == P_NOWAIT)
529 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
530 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting PM process with flag=%d, mytype=%d",
535 case FAPPTYP_NOTWINDOWCOMPAT:
537 if (os2_mytype != 0) { /* not full screen */
538 if (flag == P_NOWAIT)
540 else if ((flag & 7) != P_SESSION)
541 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Starting Full Screen process with flag=%d, mytype=%d",
546 case FAPPTYP_NOTSPEC:
547 /* Let the shell handle this... */
549 buf = ""; /* Pacify a warning */
550 file = 0; /* Pacify a warning */
558 new_stderr = dup(2); /* Preserve stderr */
559 if (new_stderr == -1) {
567 fl_stderr = fcntl(2, F_GETFD);
571 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
575 rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv));
577 if (execf == EXECF_TRUEEXEC)
578 rc = execvp(tmps,PL_Argv);
579 else if (execf == EXECF_EXEC)
580 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
581 else if (execf == EXECF_SPAWN_NOWAIT)
582 rc = spawnvp(flag,tmps,PL_Argv);
583 else if (execf == EXECF_SYNC)
584 rc = spawnvp(trueflag,tmps,PL_Argv);
585 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
586 rc = result(aTHX_ trueflag,
587 spawnvp(flag,tmps,PL_Argv));
589 if (rc < 0 && pass == 1
590 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
595 if (err == ENOENT || err == ENOEXEC) {
596 /* No such file, or is a script. */
597 /* Try adding script extensions to the file name, and
599 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
603 SV *scrsv = sv_2mortal(newSVpv(scr, 0));
604 SV *bufsv = sv_newmortal();
607 scr = SvPV(scrsv, n_a); /* free()ed later */
609 file = PerlIO_open(scr, "r");
614 buf = sv_gets(bufsv, file, 0 /* No append */);
616 buf = ""; /* XXX Needed? */
617 if (!buf[0]) { /* Empty... */
619 /* Special case: maybe from -Zexe build, so
620 there is an executable around (contrary to
621 documentation, DosQueryAppType sometimes (?)
622 does not append ".exe", so we could have
623 reached this place). */
624 sv_catpv(scrsv, ".exe");
625 scr = SvPV(scrsv, n_a); /* Reload */
626 if (PerlLIO_stat(scr,&PL_statbuf) >= 0
627 && !S_ISDIR(PL_statbuf.st_mode)) { /* Found */
631 } else { /* Restore */
632 SvCUR_set(scrsv, SvCUR(scrsv) - 4);
636 if (PerlIO_close(file) != 0) { /* Failure */
638 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Error reading \"%s\": %s",
639 scr, Strerror(errno));
640 buf = ""; /* Not #! */
646 } else if (buf[0] == 'e') {
647 if (strnEQ(buf, "extproc", 7)
650 } else if (buf[0] == 'E') {
651 if (strnEQ(buf, "EXTPROC", 7)
656 buf = ""; /* Not #! */
664 /* Do better than pdksh: allow a few args,
665 strip trailing whitespace. */
675 while (*s && !isSPACE(*s))
682 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Too many args on %.*s line of \"%s\"",
687 /* Can jump from far, buf/file invalid if force_shell: */
694 || (!buf[0] && file)) { /* File without magic */
695 /* In fact we tried all what pdksh would
696 try. There is no point in calling
697 pdksh, we may just emulate its logic. */
698 char *shell = getenv("EXECSHELL");
699 char *shell_opt = NULL;
705 shell = getenv("OS2_SHELL");
706 if (inicmd) { /* No spaces at start! */
708 while (*s && !isSPACE(*s)) {
710 inicmd = NULL; /* Cannot use */
718 /* Dosish shells will choke on slashes
719 in paths, fortunately, this is
720 important for zeroth arg only. */
727 /* If EXECSHELL is set, we do not set */
730 shell = ((_emx_env & 0x200)
733 nargs = shell_opt ? 2 : 1; /* shell file args */
734 exec_args[0] = shell;
735 exec_args[1] = shell_opt;
737 if (nargs == 2 && inicmd) {
738 /* Use the original cmd line */
739 /* XXXX This is good only until we refuse
740 quoted arguments... */
744 } else if (!buf[0] && inicmd) { /* No file */
745 /* Start with the original cmdline. */
746 /* XXXX This is good only until we refuse
747 quoted arguments... */
751 nargs = 2; /* shell -c */
754 while (a[1]) /* Get to the end */
756 a++; /* Copy finil NULL too */
757 while (a >= PL_Argv) {
758 *(a + nargs) = *a; /* PL_Argv was preallocated to be
763 PL_Argv[nargs] = argsp[nargs];
764 /* Enable pathless exec if #! (as pdksh). */
765 pass = (buf[0] == '#' ? 2 : 3);
769 /* Not found: restore errno */
773 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
774 char *no_dir = strrchr(PL_Argv[0], '/');
776 /* Do as pdksh port does: if not found with /, try without
779 PL_Argv[0] = no_dir + 1;
784 if (rc < 0 && ckWARN(WARN_EXEC))
785 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s\n",
786 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
788 PL_Argv[0], Strerror(errno));
789 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
790 && ((trueflag & 0xFF) == P_WAIT))
794 if (new_stderr != -1) { /* How can we use error codes? */
797 fcntl(2, F_SETFD, fl_stderr);
803 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
805 do_spawn3(pTHX_ char *cmd, int execf, int flag)
809 char *shell, *copt, *news = NULL;
810 int rc, seenspace = 0, mergestderr = 0;
813 if ((shell = getenv("EMXSHELL")) != NULL)
815 else if ((shell = getenv("SHELL")) != NULL)
817 else if ((shell = getenv("COMSPEC")) != NULL)
822 /* Consensus on perl5-porters is that it is _very_ important to
823 have a shell which will not change between computers with the
824 same architecture, to avoid "action on a distance".
825 And to have simple build, this shell should be sh. */
830 while (*cmd && isSPACE(*cmd))
833 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
834 STRLEN l = strlen(PL_sh_path);
836 New(1302, news, strlen(cmd) - 7 + l + 1, char);
837 strcpy(news, PL_sh_path);
838 strcpy(news + l, cmd + 7);
842 /* save an extra exec if possible */
843 /* see if there are shell metacharacters in it */
845 if (*cmd == '.' && isSPACE(cmd[1]))
848 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
851 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
855 for (s = cmd; *s; s++) {
856 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
857 if (*s == '\n' && s[1] == '\0') {
860 } else if (*s == '\\' && !seenspace) {
861 continue; /* Allow backslashes in names */
862 } else if (*s == '>' && s >= cmd + 3
863 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
864 && isSPACE(s[-2]) ) {
867 while (*t && isSPACE(*t))
872 break; /* Allow 2>&1 as the last thing */
875 /* We do not convert this to do_spawn_ve since shell
876 should be smart enough to start itself gloriously. */
878 if (execf == EXECF_TRUEEXEC)
879 rc = execl(shell,shell,copt,cmd,(char*)0);
880 else if (execf == EXECF_EXEC)
881 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
882 else if (execf == EXECF_SPAWN_NOWAIT)
883 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
884 else if (execf == EXECF_SPAWN_BYFLAG)
885 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
887 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
888 if (execf == EXECF_SYNC)
889 rc = spawnl(P_WAIT,shell,shell,copt,cmd,(char*)0);
891 rc = result(aTHX_ P_WAIT,
892 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
893 if (rc < 0 && ckWARN(WARN_EXEC))
894 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
895 (execf == EXECF_SPAWN ? "spawn" : "exec"),
896 shell, Strerror(errno));
903 } else if (*s == ' ' || *s == '\t') {
908 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
909 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
910 PL_Cmd = savepvn(cmd, s-cmd);
912 for (s = PL_Cmd; *s;) {
913 while (*s && isSPACE(*s)) s++;
916 while (*s && !isSPACE(*s)) s++;
922 rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
933 os2_do_aspawn(pTHX_ SV *really, register void **vmark, register void **vsp)
935 register SV **mark = (SV **)vmark;
936 register SV **sp = (SV **)vsp;
939 int flag = P_WAIT, flag_set = 0;
943 New(1301,PL_Argv, sp - mark + 3, char*);
946 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
953 while (++mark <= sp) {
955 *a++ = SvPVx(*mark, n_a);
961 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
962 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
964 rc = do_spawn_ve(aTHX_ really, flag, EXECF_SPAWN, NULL, 0);
972 os2_do_spawn(pTHX_ char *cmd)
974 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
978 do_spawn_nowait(pTHX_ char *cmd)
980 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
984 Perl_do_exec(pTHX_ char *cmd)
986 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
991 os2exec(pTHX_ char *cmd)
993 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
997 my_syspopen(pTHX_ char *cmd, char *mode)
1001 register I32 this, that, newfd;
1004 int fh_fl = 0; /* Pacify the warning */
1006 /* `this' is what we use in the parent, `that' in the child. */
1007 this = (*mode == 'w');
1011 taint_proper("Insecure %s%s", "EXEC");
1015 /* Now we need to spawn the child. */
1016 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1017 int new = dup(p[this]);
1024 newfd = dup(*mode == 'r'); /* Preserve std* */
1026 /* This cannot happen due to fh being bad after pipe(), since
1027 pipe() should have created fh 0 and 1 even if they were
1028 initially closed. But we closed p[this] before. */
1029 if (errno != EBADF) {
1036 fh_fl = fcntl(*mode == 'r', F_GETFD);
1037 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1038 dup2(p[that], *mode == 'r');
1041 /* Where is `this' and newfd now? */
1042 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1044 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1045 pid = do_spawn_nowait(aTHX_ cmd);
1047 close(*mode == 'r'); /* It was closed initially */
1048 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1049 dup2(newfd, *mode == 'r'); /* Return std* back. */
1051 fcntl(*mode == 'r', F_SETFD, fh_fl);
1053 fcntl(*mode == 'r', F_SETFD, fh_fl);
1054 if (p[that] == (*mode == 'r'))
1060 if (p[that] < p[this]) { /* Make fh as small as possible */
1061 dup2(p[this], p[that]);
1065 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1066 (void)SvUPGRADE(sv,SVt_IV);
1068 PL_forkprocess = pid;
1069 return PerlIO_fdopen(p[this], mode);
1071 #else /* USE_POPEN */
1077 res = popen(cmd, mode);
1079 char *shell = getenv("EMXSHELL");
1081 my_setenv("EMXSHELL", PL_sh_path);
1082 res = popen(cmd, mode);
1083 my_setenv("EMXSHELL", shell);
1085 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1086 (void)SvUPGRADE(sv,SVt_IV);
1087 SvIVX(sv) = -1; /* A cooky. */
1090 #endif /* USE_POPEN */
1094 /******************************************************************/
1100 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1106 /*******************************************************************/
1107 /* not implemented in EMX 0.9d */
1109 char * ctermid(char *s) { return 0; }
1111 #ifdef MYTTYNAME /* was not in emx0.9a */
1112 void * ttyname(x) { return 0; }
1115 /*****************************************************************************/
1116 /* not implemented in C Set++ */
1119 int setuid(x) { errno = EINVAL; return -1; }
1120 int setgid(x) { errno = EINVAL; return -1; }
1123 /*****************************************************************************/
1124 /* stat() hack for char/block device */
1128 /* First attempt used DosQueryFSAttach which crashed the system when
1129 used with 5.001. Now just look for /dev/. */
1132 os2_stat(const char *name, struct stat *st)
1134 static int ino = SHRT_MAX;
1136 if (stricmp(name, "/dev/con") != 0
1137 && stricmp(name, "/dev/tty") != 0)
1138 return stat(name, st);
1140 memset(st, 0, sizeof *st);
1141 st->st_mode = S_IFCHR|0666;
1142 st->st_ino = (ino-- & 0x7FFF);
1149 #ifdef USE_PERL_SBRK
1151 /* SBRK() emulation, mostly moved to malloc.c. */
1154 sys_alloc(int size) {
1156 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1158 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1161 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1165 #endif /* USE_PERL_SBRK */
1169 char *tmppath = TMPPATH1;
1174 char *p = getenv("TMP"), *tpath;
1177 if (!p) p = getenv("TEMP");
1180 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1184 strcpy(tpath + len + 1, TMPPATH1);
1191 XS(XS_File__Copy_syscopy)
1194 if (items < 2 || items > 3)
1195 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1198 char * src = (char *)SvPV(ST(0),n_a);
1199 char * dst = (char *)SvPV(ST(1),n_a);
1206 flag = (unsigned long)SvIV(ST(2));
1209 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1210 ST(0) = sv_newmortal();
1211 sv_setiv(ST(0), (IV)RETVAL);
1216 #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */
1217 #include "patchlevel.h"
1218 #undef PERL_PATCHLEVEL_H_IMPLICIT
1221 mod2fname(pTHX_ SV *sv)
1223 static char fname[9];
1224 int pos = 6, len, avlen;
1225 unsigned int sum = 0;
1229 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
1231 if (SvTYPE(sv) != SVt_PVAV)
1232 Perl_croak_nocontext("Not array reference given to mod2fname");
1234 avlen = av_len((AV*)sv);
1236 Perl_croak_nocontext("Empty array reference given to mod2fname");
1238 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1239 strncpy(fname, s, 8);
1241 if (len < 6) pos = len;
1243 sum = 33 * sum + *(s++); /* Checksumming first chars to
1244 * get the capitalization into c.s. */
1247 while (avlen >= 0) {
1248 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1250 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1254 /* We always load modules as *specific* DLLs, and with the full name.
1255 When loading a specific DLL by its full name, one cannot get a
1256 different DLL, even if a DLL with the same basename is loaded already.
1257 Thus there is no need to include the version into the mangling scheme. */
1259 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
1261 # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
1262 # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
1264 sum += COMPATIBLE_VERSION_SUM;
1266 fname[pos] = 'A' + (sum % 26);
1267 fname[pos + 1] = 'A' + (sum / 26 % 26);
1268 fname[pos + 2] = '\0';
1269 return (char *)fname;
1272 XS(XS_DynaLoader_mod2fname)
1276 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
1281 RETVAL = mod2fname(aTHX_ sv);
1282 ST(0) = sv_newmortal();
1283 sv_setpv((SV*)ST(0), RETVAL);
1291 static char buf[300];
1294 int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
1296 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1300 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1301 s = buf + strlen(buf);
1304 if (DosGetMessage(NULL, 0, s, sizeof(buf) - 1 - (s-buf),
1305 rc, "OSO001.MSG", &len)) {
1307 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1308 s = buf + strlen(buf);
1310 sprintf(s, "[No description found in OSO001.MSG]");
1313 if (len && s[len - 1] == '\n')
1315 if (len && s[len - 1] == '\r')
1317 if (len && s[len - 1] == '.')
1319 if (len >= 10 && number && strnEQ(s, buf, 7)
1320 && s[7] == ':' && s[8] == ' ')
1321 /* Some messages start with SYSdddd:, some not */
1322 Move(s + 9, s, (len -= 9) + 1, char);
1334 CroakWinError(int die, char *name)
1338 croak("%s: %s", (name ? name : "Win* API call"), os2error(Perl_rc));
1344 char buf[300], *p, *o = PL_origargv[0], ok = 1;
1346 if (_execname(buf, sizeof buf) != 0)
1353 if (ok && *o != '/' && *o != '\\')
1355 } else if (ok && tolower(*o) != tolower(*p))
1360 if (ok) { /* PL_origargv[0] matches the real name. Use PL_origargv[0]: */
1361 strcpy(buf, PL_origargv[0]); /* _execname() is always uppercased */
1375 perllib_mangle(char *s, unsigned int l)
1377 static char *newp, *oldp;
1378 static int newl, oldl, notfound;
1379 static char ret[STATIC_FILE_LENGTH+1];
1381 if (!newp && !notfound) {
1382 newp = getenv("PERLLIB_PREFIX");
1387 while (*newp && !isSPACE(*newp) && *newp != ';') {
1388 newp++; oldl++; /* Skip digits. */
1390 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1391 newp++; /* Skip whitespace. */
1393 newl = strlen(newp);
1394 if (newl == 0 || oldl == 0) {
1395 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1400 if (*s == '\\') *s = '/';
1413 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1416 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1417 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1419 strcpy(ret + newl, s + oldl);
1424 Perl_hab_GET() /* Needed if perl.h cannot be included */
1426 return perl_hab_GET();
1430 Perl_Register_MQ(int serve)
1432 if (Perl_hmq_refcnt <= 0) {
1436 Perl_hmq_refcnt = 0; /* Be extra safe */
1437 DosGetInfoBlocks(&tib, &pib);
1438 Perl_os2_initial_mode = pib->pib_ultype;
1439 /* Try morphing into a PM application. */
1440 if (pib->pib_ultype != 3) /* 2 is VIO */
1441 pib->pib_ultype = 3; /* 3 is PM */
1442 init_PMWIN_entries();
1443 /* 64 messages if before OS/2 3.0, ignored otherwise */
1444 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1448 SAVEINT(cnt); /* Allow catch()ing. */
1450 _exit(188); /* Panic can try to create a window. */
1451 Perl_croak_nocontext("Cannot create a message queue, or morph to a PM application");
1455 if ( Perl_hmq_servers <= 0 /* Safe to inform us on shutdown, */
1456 && Perl_hmq_refcnt > 0 ) /* this was switched off before... */
1457 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
1459 } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
1460 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1466 Perl_Serve_Messages(int force)
1471 if (Perl_hmq_servers > 0 && !force)
1473 if (Perl_hmq_refcnt <= 0)
1474 Perl_croak_nocontext("No message queue");
1475 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1477 if (msg.msg == WM_QUIT)
1478 Perl_croak_nocontext("QUITing...");
1479 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1485 Perl_Process_Messages(int force, I32 *cntp)
1489 if (Perl_hmq_servers > 0 && !force)
1491 if (Perl_hmq_refcnt <= 0)
1492 Perl_croak_nocontext("No message queue");
1493 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1496 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1497 if (msg.msg == WM_DESTROY)
1499 if (msg.msg == WM_CREATE)
1502 Perl_croak_nocontext("QUITing...");
1506 Perl_Deregister_MQ(int serve)
1513 if (--Perl_hmq_refcnt <= 0) {
1514 init_PMWIN_entries(); /* To be extra safe */
1515 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1517 /* Try morphing back from a PM application. */
1518 DosGetInfoBlocks(&tib, &pib);
1519 if (pib->pib_ultype == 3) /* 3 is PM */
1520 pib->pib_ultype = Perl_os2_initial_mode;
1522 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
1524 } else if (serve && Perl_hmq_servers <= 0) /* Last server exited */
1525 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1528 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1529 && ((path)[2] == '/' || (path)[2] == '\\'))
1530 #define sys_is_rooted _fnisabs
1531 #define sys_is_relative _fnisrel
1532 #define current_drive _getdrive
1534 #undef chdir /* Was _chdir2. */
1535 #define sys_chdir(p) (chdir(p) == 0)
1536 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1538 static int DOS_harderr_state = -1;
1544 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
1546 int arg1 = SvIV(ST(0));
1547 int arg2 = SvIV(ST(1));
1548 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1549 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1550 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1553 if (CheckOSError(DosError(a)))
1554 Perl_croak_nocontext("DosError(%d) failed", a);
1555 ST(0) = sv_newmortal();
1556 if (DOS_harderr_state >= 0)
1557 sv_setiv(ST(0), DOS_harderr_state);
1558 DOS_harderr_state = RETVAL;
1563 static signed char DOS_suppression_state = -1;
1565 XS(XS_OS2_Errors2Drive)
1569 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
1573 int suppress = SvOK(sv);
1574 char *s = suppress ? SvPV(sv, n_a) : NULL;
1575 char drive = (s ? *s : 0);
1578 if (suppress && !isALPHA(drive))
1579 Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1580 if (CheckOSError(DosSuppressPopUps((suppress
1581 ? SPU_ENABLESUPPRESSION
1582 : SPU_DISABLESUPPRESSION),
1584 Perl_croak_nocontext("DosSuppressPopUps(%c) failed", drive);
1585 ST(0) = sv_newmortal();
1586 if (DOS_suppression_state > 0)
1587 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1588 else if (DOS_suppression_state == 0)
1589 sv_setpvn(ST(0), "", 0);
1590 DOS_suppression_state = drive;
1595 static const char * const si_fields[QSV_MAX] = {
1597 "MAX_TEXT_SESSIONS",
1601 "DYN_PRI_VARIATION",
1619 "FOREGROUND_FS_SESSION",
1620 "FOREGROUND_PROCESS"
1627 Perl_croak_nocontext("Usage: OS2::SysInfo()");
1629 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1630 APIRET rc = NO_ERROR; /* Return code */
1633 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1634 QSV_MAX, /* information */
1637 Perl_croak_nocontext("DosQuerySysInfo() failed");
1638 EXTEND(SP,2*QSV_MAX);
1639 while (i < QSV_MAX) {
1640 ST(j) = sv_newmortal();
1641 sv_setpv(ST(j++), si_fields[i]);
1642 ST(j) = sv_newmortal();
1643 sv_setiv(ST(j++), si[i]);
1647 XSRETURN(2 * QSV_MAX);
1650 XS(XS_OS2_BootDrive)
1654 Perl_croak_nocontext("Usage: OS2::BootDrive()");
1656 ULONG si[1] = {0}; /* System Information Data Buffer */
1657 APIRET rc = NO_ERROR; /* Return code */
1660 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1661 (PVOID)si, sizeof(si))))
1662 Perl_croak_nocontext("DosQuerySysInfo() failed");
1663 ST(0) = sv_newmortal();
1664 c = 'a' - 1 + si[0];
1665 sv_setpvn(ST(0), &c, 1);
1674 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
1676 bool serve = SvOK(ST(0));
1677 unsigned long pmq = perl_hmq_GET(serve);
1679 ST(0) = sv_newmortal();
1680 sv_setiv(ST(0), pmq);
1685 XS(XS_OS2_UnMorphPM)
1689 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
1691 bool serve = SvOK(ST(0));
1693 perl_hmq_UNSET(serve);
1698 XS(XS_OS2_Serve_Messages)
1702 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
1704 bool force = SvOK(ST(0));
1705 unsigned long cnt = Perl_Serve_Messages(force);
1707 ST(0) = sv_newmortal();
1708 sv_setiv(ST(0), cnt);
1713 XS(XS_OS2_Process_Messages)
1716 if (items < 1 || items > 2)
1717 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
1719 bool force = SvOK(ST(0));
1726 (void)SvIV(sv); /* Force SvIVX */
1728 Perl_croak_nocontext("Can't upgrade count to IV");
1730 cnt = Perl_Process_Messages(force, &cntr);
1733 cnt = Perl_Process_Messages(force, NULL);
1735 ST(0) = sv_newmortal();
1736 sv_setiv(ST(0), cnt);
1741 XS(XS_Cwd_current_drive)
1745 Perl_croak_nocontext("Usage: Cwd::current_drive()");
1749 RETVAL = current_drive();
1750 ST(0) = sv_newmortal();
1751 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1756 XS(XS_Cwd_sys_chdir)
1760 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
1763 char * path = (char *)SvPV(ST(0),n_a);
1766 RETVAL = sys_chdir(path);
1767 ST(0) = boolSV(RETVAL);
1768 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1773 XS(XS_Cwd_change_drive)
1777 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
1780 char d = (char)*SvPV(ST(0),n_a);
1783 RETVAL = change_drive(d);
1784 ST(0) = boolSV(RETVAL);
1785 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1790 XS(XS_Cwd_sys_is_absolute)
1794 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
1797 char * path = (char *)SvPV(ST(0),n_a);
1800 RETVAL = sys_is_absolute(path);
1801 ST(0) = boolSV(RETVAL);
1802 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1807 XS(XS_Cwd_sys_is_rooted)
1811 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
1814 char * path = (char *)SvPV(ST(0),n_a);
1817 RETVAL = sys_is_rooted(path);
1818 ST(0) = boolSV(RETVAL);
1819 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1824 XS(XS_Cwd_sys_is_relative)
1828 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
1831 char * path = (char *)SvPV(ST(0),n_a);
1834 RETVAL = sys_is_relative(path);
1835 ST(0) = boolSV(RETVAL);
1836 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1845 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
1849 RETVAL = _getcwd2(p, MAXPATHLEN);
1850 ST(0) = sv_newmortal();
1851 sv_setpv((SV*)ST(0), RETVAL);
1852 #ifndef INCOMPLETE_TAINTS
1853 SvTAINTED_on(ST(0));
1859 XS(XS_Cwd_sys_abspath)
1862 if (items < 1 || items > 2)
1863 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path, dir = NULL)");
1866 char * path = (char *)SvPV(ST(0),n_a);
1867 char * dir, *s, *t, *e;
1876 dir = (char *)SvPV(ST(1),n_a);
1878 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1882 if (_abspath(p, path, MAXPATHLEN) == 0) {
1888 /* Absolute with drive: */
1889 if ( sys_is_absolute(path) ) {
1890 if (_abspath(p, path, MAXPATHLEN) == 0) {
1895 } else if (path[0] == '/' || path[0] == '\\') {
1896 /* Rooted, but maybe on different drive. */
1897 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1898 char p1[MAXPATHLEN];
1900 /* Need to prepend the drive. */
1903 Copy(path, p1 + 2, strlen(path) + 1, char);
1905 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1910 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1916 /* Either path is relative, or starts with a drive letter. */
1917 /* If the path starts with a drive letter, then dir is
1919 a/b) it is absolute/x:relative on the same drive.
1920 c) path is on current drive, and dir is rooted
1921 In all the cases it is safe to drop the drive part
1923 if ( !sys_is_relative(path) ) {
1924 if ( ( ( sys_is_absolute(dir)
1925 || (isALPHA(dir[0]) && dir[1] == ':'
1926 && strnicmp(dir, path,1) == 0))
1927 && strnicmp(dir, path,1) == 0)
1928 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1929 && toupper(path[0]) == current_drive())) {
1931 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1932 RETVAL = p; goto done;
1934 RETVAL = NULL; goto done;
1938 /* Need to prepend the absolute path of dir. */
1939 char p1[MAXPATHLEN];
1941 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1944 if (p1[ l - 1 ] != '/') {
1948 Copy(path, p1 + l, strlen(path) + 1, char);
1949 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1963 /* Backslashes are already converted to slashes. */
1964 /* Remove trailing slashes */
1966 while (l > 0 && RETVAL[l-1] == '/')
1968 ST(0) = sv_newmortal();
1969 sv_setpvn( sv = (SV*)ST(0), RETVAL, l);
1970 /* Remove duplicate slashes, skipping the first three, which
1971 may be parts of a server-based path */
1972 s = t = 3 + SvPV_force(sv, n_a);
1974 /* Do not worry about multibyte chars here, this would contradict the
1975 eventual UTFization, and currently most other places break too... */
1977 if (s[0] == t[-1] && s[0] == '/')
1978 s++; /* Skip duplicate / */
1984 SvCUR_set(sv, t - SvPVX(sv));
1989 typedef APIRET (*PELP)(PSZ path, ULONG type);
1991 /* Kernels after 2000/09/15 understand this too: */
1992 #ifndef LIBPATHSTRICT
1993 # define LIBPATHSTRICT 3
1997 ExtLIBPATH(ULONG ord, PSZ path, IV type)
2000 PFN f = loadByOrdinal(ord, 1); /* Guarantied to load or die! */
2005 what = BEGIN_LIBPATH;
2007 what = LIBPATHSTRICT;
2008 return (*(PELP)f)(path, what);
2011 #define extLibpath(to,type) \
2012 (CheckOSError(ExtLIBPATH(ORD_DosQueryExtLibpath, (to), (type))) ? NULL : (to) )
2014 #define extLibpath_set(p,type) \
2015 (!CheckOSError(ExtLIBPATH(ORD_DosSetExtLibpath, (p), (type))))
2017 XS(XS_Cwd_extLibpath)
2020 if (items < 0 || items > 1)
2021 Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)");
2034 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
2035 RETVAL = extLibpath(to, type);
2036 if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0)
2037 Perl_croak_nocontext("panic Cwd::extLibpath parameter");
2038 ST(0) = sv_newmortal();
2039 sv_setpv((SV*)ST(0), RETVAL);
2044 XS(XS_Cwd_extLibpath_set)
2047 if (items < 1 || items > 2)
2048 Perl_croak_nocontext("Usage: Cwd::extLibpath_set(s, type = 0)");
2051 char * s = (char *)SvPV(ST(0),n_a);
2062 RETVAL = extLibpath_set(s, type);
2063 ST(0) = boolSV(RETVAL);
2064 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2069 /* Input: Address, BufLen
2071 DosQueryModFromEIP (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
2072 ULONG * Offset, ULONG Address);
2075 DeclOSFuncByORD(APIRET, _DosQueryModFromEIP,ORD_DosQueryModFromEIP,
2076 (HMODULE * hmod, ULONG * obj, ULONG BufLen, PCHAR Buf,
2077 ULONG * Offset, ULONG Address),
2078 (hmod, obj, BufLen, Buf, Offset, Address))
2080 enum module_name_how { mod_name_handle, mod_name_shortname, mod_name_full};
2083 module_name_at(void *pp, enum module_name_how how)
2085 char buf[MAXPATHLEN];
2088 ULONG obj, offset, rc;
2090 if (!_DosQueryModFromEIP(&mod, &obj, sizeof(buf), buf, &offset, (ULONG)pp))
2091 return &PL_sv_undef;
2092 if (how == mod_name_handle)
2093 return newSVuv(mod);
2095 if ( how == mod_name_full
2096 && CheckOSError(DosQueryModuleName(mod, sizeof(buf), buf)) )
2097 return &PL_sv_undef;
2103 return newSVpv(buf, 0);
2107 module_name_of_cv(SV *cv, enum module_name_how how)
2109 if (!cv || !SvROK(cv) || SvTYPE(SvRV(cv)) != SVt_PVCV || !CvXSUB(SvRV(cv)))
2110 croak("Not an XSUB reference");
2111 return module_name_at(CvXSUB(SvRV(cv)), how);
2114 /* Find module name to which *this* subroutine is compiled */
2115 #define module_name(how) module_name_at(&module_name_at, how)
2121 Perl_croak(aTHX_ "Usage: OS2::DLLname( [ how, [\\&xsub] ] )");
2127 how = mod_name_full;
2129 how = (int)SvIV(ST(0));
2132 RETVAL = module_name(how);
2134 RETVAL = module_name_of_cv(ST(1), how);
2141 #define get_control87() _control87(0,0)
2142 #define set_control87 _control87
2144 XS(XS_OS2__control87)
2148 croak("Usage: OS2::_control87(new,mask)");
2150 unsigned new = (unsigned)SvIV(ST(0));
2151 unsigned mask = (unsigned)SvIV(ST(1));
2154 RETVAL = _control87(new, mask);
2155 ST(0) = sv_newmortal();
2156 sv_setiv(ST(0), (IV)RETVAL);
2161 XS(XS_OS2_get_control87)
2165 croak("Usage: OS2::get_control87()");
2169 RETVAL = get_control87();
2170 ST(0) = sv_newmortal();
2171 sv_setiv(ST(0), (IV)RETVAL);
2177 XS(XS_OS2_set_control87)
2180 if (items < 0 || items > 2)
2181 croak("Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
2190 new = (unsigned)SvIV(ST(0));
2196 mask = (unsigned)SvIV(ST(1));
2199 RETVAL = set_control87(new, mask);
2200 ST(0) = sv_newmortal();
2201 sv_setiv(ST(0), (IV)RETVAL);
2209 char *file = __FILE__;
2213 if (_emx_env & 0x200) { /* OS/2 */
2214 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2215 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2216 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2218 newXS("OS2::Error", XS_OS2_Error, file);
2219 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2220 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2221 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2222 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2223 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2224 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2225 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2226 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2227 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2228 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2229 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2230 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2231 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2232 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2233 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2234 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2235 newXSproto("OS2::_control87", XS_OS2__control87, file, "$$");
2236 newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
2237 newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
2238 newXSproto("OS2::DLLname", XS_OS2_DLLname, file, ";$$");
2239 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2242 sv_setiv(GvSV(gv), 1);
2244 gv = gv_fetchpv("OS2::can_fork", TRUE, SVt_PV);
2246 sv_setiv(GvSV(gv), exe_is_aout());
2247 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2249 sv_setiv(GvSV(gv), _emx_rev);
2250 sv_setpv(GvSV(gv), _emx_vprt);
2252 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2254 sv_setiv(GvSV(gv), _emx_env);
2255 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2257 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2258 gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
2260 sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
2265 OS2_Perl_data_t OS2_Perl_data;
2267 extern void _emx_init(void*);
2269 static void jmp_out_of_atexit(void);
2271 #define FORCE_EMX_INIT_CONTRACT_ARGV 1
2272 #define FORCE_EMX_INIT_INSTALL_ATEXIT 2
2275 my_emx_init(void *layout) {
2276 static volatile void *p = 0; /* Cannot be on stack! */
2278 /* Can't just call emx_init(), since it moves the stack pointer */
2279 /* It also busts a lot of registers, so be extra careful */
2287 "popf\n" : : "r" (layout), "m" (p) );
2290 struct layout_table_t {
2311 static ULONG res; /* Cannot be on stack! */
2313 /* Can't just call __os_version(), since it does not follow C
2314 calling convention: it busts a lot of registers, so be extra careful */
2317 "call ___os_version\n"
2320 "popf\n" : "=m" (res) );
2326 force_init_emx_runtime(EXCEPTIONREGISTRATIONRECORD *preg, ULONG flags)
2328 /* Calling emx_init() will bust the top of stack: it installs an
2329 exception handler and puts argv data there. */
2330 char *oldarg, *oldenv;
2331 void *oldstackend, *oldstack;
2334 static ULONG os2_dll;
2335 ULONG rc, error = 0, out;
2337 static struct layout_table_t layout_table;
2339 char buf[48*1024]; /* _emx_init() requires 32K, cmd.exe has 64K only */
2341 EXCEPTIONREGISTRATIONRECORD xreg;
2345 layout_table.os2_dll = (ULONG)&os2_dll;
2346 layout_table.flags = 0x02000002; /* flags: application, OMF */
2348 DosGetInfoBlocks(&tib, &pib);
2349 oldarg = pib->pib_pchcmd;
2350 oldenv = pib->pib_pchenv;
2351 oldstack = tib->tib_pstack;
2352 oldstackend = tib->tib_pstacklimit;
2354 /* Minimize the damage to the stack via reducing the size of argv. */
2355 if (flags & FORCE_EMX_INIT_CONTRACT_ARGV) {
2356 pib->pib_pchcmd = "\0\0"; /* Need 3 concatenated strings */
2357 pib->pib_pchcmd = "\0"; /* Ended by an extra \0. */
2360 newstack = alloca(sizeof(*newstack));
2361 /* Emulate the stack probe */
2362 s = ((char*)newstack) + sizeof(*newstack);
2363 while (s > (char*)newstack) {
2368 /* Reassigning stack is documented to work */
2369 tib->tib_pstack = (void*)newstack;
2370 tib->tib_pstacklimit = (void*)((char*)newstack + sizeof(*newstack));
2372 /* Can't just call emx_init(), since it moves the stack pointer */
2373 my_emx_init((void*)&layout_table);
2375 /* Remove the exception handler, cannot use it - too low on the stack.
2376 Check whether it is inside the new stack. */
2378 if (tib->tib_pexchain >= tib->tib_pstacklimit
2379 || tib->tib_pexchain < tib->tib_pstack) {
2382 "panic: ExceptionHandler misplaced: not %#lx <= %#lx < %#lx\n",
2383 (unsigned long)tib->tib_pstack,
2384 (unsigned long)tib->tib_pexchain,
2385 (unsigned long)tib->tib_pstacklimit);
2388 if (tib->tib_pexchain != &(newstack->xreg)) {
2389 sprintf(buf, "ExceptionHandler misplaced: %#lx != %#lx\n",
2390 (unsigned long)tib->tib_pexchain,
2391 (unsigned long)&(newstack->xreg));
2393 rc = DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)tib->tib_pexchain);
2395 sprintf(buf + strlen(buf),
2396 "warning: DosUnsetExceptionHandler rc=%#lx=%lu\n", rc, rc);
2399 /* ExceptionRecords should be on stack, in a correct order. Sigh... */
2400 preg->prev_structure = 0;
2401 preg->ExceptionHandler = _emx_exception;
2402 rc = DosSetExceptionHandler(preg);
2404 sprintf(buf + strlen(buf),
2405 "warning: DosSetExceptionHandler rc=%#lx=%lu\n", rc, rc);
2406 DosWrite(2, buf, strlen(buf), &out);
2407 emx_exception_init = 1; /* Do it around spawn*() calls */
2410 emx_exception_init = 1; /* Do it around spawn*() calls */
2413 /* Restore the damage */
2414 pib->pib_pchcmd = oldarg;
2415 pib->pib_pchcmd = oldenv;
2416 tib->tib_pstacklimit = oldstackend;
2417 tib->tib_pstack = oldstack;
2418 emx_runtime_init = 1;
2420 DosWrite(2, buf, strlen(buf), &out);
2425 jmp_buf at_exit_buf;
2426 int longjmp_at_exit;
2429 jmp_out_of_atexit(void)
2431 if (longjmp_at_exit)
2432 longjmp(at_exit_buf, 1);
2435 extern void _CRT_term(void);
2437 int emx_runtime_secondary;
2440 Perl_OS2_term(void **p, int exitstatus, int flags)
2442 if (!emx_runtime_secondary)
2445 /* The principal executable is not running the same CRTL, so there
2446 is nobody to shutdown *this* CRTL except us... */
2447 if (flags & FORCE_EMX_DEINIT_EXIT) {
2448 if (p && !emx_exception_init)
2449 DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
2450 /* Do not run the executable's CRTL's termination routines */
2451 exit(exitstatus); /* Run at-exit, flush buffers, etc */
2453 /* Run at-exit list, and jump out at the end */
2454 if ((flags & FORCE_EMX_DEINIT_RUN_ATEXIT) && !setjmp(at_exit_buf)) {
2455 longjmp_at_exit = 1;
2456 exit(exitstatus); /* The first pass through "if" */
2459 /* Get here if we managed to jump out of exit(), or did not run atexit. */
2460 longjmp_at_exit = 0; /* Maybe exit() is called again? */
2461 #if 0 /* _atexit_n is not exported */
2462 if (flags & FORCE_EMX_DEINIT_RUN_ATEXIT)
2463 _atexit_n = 0; /* Remove the atexit() handlers */
2465 /* Will segfault on program termination if we leave this dangling... */
2466 if (p && !emx_exception_init)
2467 DosUnsetExceptionHandler((EXCEPTIONREGISTRATIONRECORD *)p);
2468 /* Typically there is no need to do this, done from _DLL_InitTerm() */
2469 if (flags & FORCE_EMX_DEINIT_CRT_TERM)
2470 _CRT_term(); /* Flush buffers, etc. */
2471 /* Now it is a good time to call exit() in the caller's CRTL... */
2474 #include <emx/startup.h>
2476 extern ULONG __os_version(); /* See system.doc */
2478 static int emx_wasnt_initialized;
2481 check_emx_runtime(char **env, EXCEPTIONREGISTRATIONRECORD *preg)
2485 /* If _environ is not set, this code sits in a DLL which
2486 uses a CRT DLL which not compatible with the executable's
2487 CRT library. Some parts of the DLL are not initialized.
2489 if (_environ != NULL)
2490 return; /* Properly initialized */
2492 /* If the executable does not use EMX.DLL, EMX.DLL is not completely
2493 initialized either. Uninitialized EMX.DLL returns 0 in the low
2494 nibble of __os_version(). */
2495 v_emx = my_os_version();
2497 /* _osmajor and _osminor are normally set in _DLL_InitTerm of CRT DLL
2498 (=>_CRT_init=>_entry2) via a call to __os_version(), then
2499 reset when the EXE initialization code calls _text=>_init=>_entry2.
2500 The first time they are wrongly set to 0; the second time the
2501 EXE initialization code had already called emx_init=>initialize1
2502 which correctly set version_major, version_minor used by
2504 v_crt = (_osmajor | _osminor);
2506 if ((_emx_env & 0x200) && !(v_emx & 0xFFFF)) { /* OS/2, EMX uninit. */
2507 force_init_emx_runtime( preg,
2508 FORCE_EMX_INIT_CONTRACT_ARGV
2509 | FORCE_EMX_INIT_INSTALL_ATEXIT );
2510 emx_wasnt_initialized = 1;
2511 /* Update CRTL data basing on now-valid EMX runtime data */
2512 if (!v_crt) { /* The only wrong data are the versions. */
2513 v_emx = my_os_version(); /* *Now* it works */
2514 *(unsigned char *)&_osmajor = v_emx & 0xFF; /* Cast out const */
2515 *(unsigned char *)&_osminor = (v_emx>>8) & 0xFF;
2518 emx_runtime_secondary = 1;
2519 /* if (flags & FORCE_EMX_INIT_INSTALL_ATEXIT) */
2520 atexit(jmp_out_of_atexit); /* Allow run of atexit() w/o exit() */
2522 if (env == NULL) { /* Fetch from the process info block */
2528 DosGetInfoBlocks(&tib, &pib);
2529 e = pib->pib_pchenv;
2530 while (*e) { /* Get count */
2532 e = e + strlen(e) + 1;
2534 New(1307, env, c + 1, char*);
2536 e = pib->pib_pchenv;
2539 e = e + strlen(e) + 1;
2543 _environ = _org_environ = env;
2546 #define ENTRY_POINT 0x10000
2551 struct layout_table_t *layout;
2552 if (emx_wasnt_initialized)
2554 /* Now we know that the principal executable is an EMX application
2555 - unless somebody did already play with delayed initialization... */
2556 /* With EMX applications to determine whether it is AOUT one needs
2557 to examine the start of the executable to find "layout" */
2558 if ( *(unsigned char*)ENTRY_POINT != 0x68 /* PUSH n */
2559 || *(unsigned char*)(ENTRY_POINT+5) != 0xe8 /* CALL */
2560 || *(unsigned char*)(ENTRY_POINT+10) != 0xeb /* JMP */
2561 || *(unsigned char*)(ENTRY_POINT+12) != 0xe8) /* CALL */
2562 return 0; /* ! EMX executable */
2564 Copy((char*)(ENTRY_POINT+1), &layout, 1, struct layout_table_t*);
2565 return !(layout->flags & 2);
2569 Perl_OS2_init(char **env)
2571 Perl_OS2_init3(env, 0, 0);
2575 Perl_OS2_init3(char **env, void **preg, int flags)
2579 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2582 check_emx_runtime(env, (EXCEPTIONREGISTRATIONRECORD *)preg);
2585 OS2_Perl_data.xs_init = &Xs_OS2_init;
2586 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2587 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2588 strcpy(PL_sh_path, SH_PATH);
2589 PL_sh_path[0] = shell[0];
2590 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2591 int l = strlen(shell), i;
2592 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2595 New(1304, PL_sh_path, l + 8, char);
2596 strncpy(PL_sh_path, shell, l);
2597 strcpy(PL_sh_path + l, "/sh.exe");
2598 for (i = 0; i < l; i++) {
2599 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2602 MUTEX_INIT(&start_thread_mutex);
2603 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2604 /* Some DLLs reset FP flags on load. We may have been linked with them */
2605 _control87(MCW_EM, MCW_EM);
2612 my_tmpnam (char *str)
2614 char *p = getenv("TMP"), *tpath;
2616 if (!p) p = getenv("TEMP");
2617 tpath = tempnam(p, "pltmp");
2631 if (s.st_mode & S_IWOTH) {
2634 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2640 /* EMX flavors do not tolerate trailing slashes. t/op/mkdir.t has many
2641 trailing slashes, so we need to support this as well. */
2644 my_rmdir (__const__ char *s)
2648 STRLEN l = strlen(s);
2651 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
2653 New(1305, buf, l + 1, char);
2655 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
2669 my_mkdir (__const__ char *s, long perm)
2673 STRLEN l = strlen(s);
2676 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
2678 New(1305, buf, l + 1, char);
2680 while (l > 1 && (s[l-1] == '/' || s[l-1] == '\\'))
2685 rc = mkdir(s, perm);
2693 /* This code was contributed by Rocco Caputo. */
2695 my_flock(int handle, int o)
2697 FILELOCK rNull, rFull;
2698 ULONG timeout, handle_type, flag_word;
2700 int blocking, shared;
2701 static int use_my = -1;
2704 char *s = getenv("USE_PERL_FLOCK");
2710 if (!(_emx_env & 0x200) || !use_my)
2711 return flock(handle, o); /* Delegate to EMX. */
2713 /* is this a file? */
2714 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2715 (handle_type & 0xFF))
2720 /* set lock/unlock ranges */
2721 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2722 rFull.lRange = 0x7FFFFFFF;
2723 /* set timeout for blocking */
2724 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2725 /* shared or exclusive? */
2726 shared = (o & LOCK_SH) ? 1 : 0;
2727 /* do not block the unlock */
2728 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2729 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2734 case ERROR_INVALID_HANDLE:
2737 case ERROR_SHARING_BUFFER_EXCEEDED:
2740 case ERROR_LOCK_VIOLATION:
2741 break; /* not an error */
2742 case ERROR_INVALID_PARAMETER:
2743 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2744 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2747 case ERROR_INTERRUPT:
2755 /* lock may block */
2756 if (o & (LOCK_SH | LOCK_EX)) {
2757 /* for blocking operations */
2771 case ERROR_INVALID_HANDLE:
2774 case ERROR_SHARING_BUFFER_EXCEEDED:
2777 case ERROR_LOCK_VIOLATION:
2779 errno = EWOULDBLOCK;
2783 case ERROR_INVALID_PARAMETER:
2784 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2785 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2788 case ERROR_INTERRUPT:
2795 /* give away timeslice */
2804 static int pwent_cnt;
2805 static int _my_pwent = -1;
2810 if (_my_pwent == -1) {
2811 char *s = getenv("USE_PERL_PWENT");
2813 _my_pwent = atoi(s);
2827 if (!use_my_pwent()) {
2828 setpwent(); /* Delegate to EMX. */
2837 if (!use_my_pwent()) {
2838 endpwent(); /* Delegate to EMX. */
2846 if (!use_my_pwent())
2847 return getpwent(); /* Delegate to EMX. */
2849 return 0; /* Return one entry only */
2853 static int grent_cnt;
2870 return 0; /* Return one entry only */
2877 /* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */
2878 static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK";
2880 static struct passwd *
2881 passw_wrap(struct passwd *p)
2883 static struct passwd pw;
2886 if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
2889 s = getenv("PW_PASSWD");
2891 s = (char*)pw_p; /* Make match impossible */
2898 my_getpwuid (uid_t id)
2900 return passw_wrap(getpwuid(id));
2904 my_getpwnam (__const__ char *n)
2906 return passw_wrap(getpwnam(n));
2910 gcvt_os2 (double value, int digits, char *buffer)
2912 return gcvt (value, digits, buffer);