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
34 typedef void (*emx_startroutine)(void *);
35 typedef void* (*pthreads_startroutine)(void *);
44 const char *pthreads_states[] = {
55 enum pthreads_state state;
58 thread_join_t *thread_join_data;
59 int thread_join_count;
60 perl_mutex start_thread_mutex;
63 pthread_join(perl_os_thread tid, void **status)
65 MUTEX_LOCK(&start_thread_mutex);
66 switch (thread_join_data[tid].state) {
67 case pthreads_st_exited:
68 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
69 MUTEX_UNLOCK(&start_thread_mutex);
70 *status = thread_join_data[tid].status;
72 case pthreads_st_waited:
73 MUTEX_UNLOCK(&start_thread_mutex);
74 Perl_croak_nocontext("join with a thread with a waiter");
77 thread_join_data[tid].state = pthreads_st_waited;
78 COND_INIT(&thread_join_data[tid].cond);
79 MUTEX_UNLOCK(&start_thread_mutex);
80 COND_WAIT(&thread_join_data[tid].cond, NULL);
81 COND_DESTROY(&thread_join_data[tid].cond);
82 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
83 *status = thread_join_data[tid].status;
86 MUTEX_UNLOCK(&start_thread_mutex);
87 Perl_croak_nocontext("join: unknown thread state: '%s'",
88 pthreads_states[thread_join_data[tid].state]);
95 pthread_startit(void *arg)
97 /* Thread is already started, we need to transfer control only */
98 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
99 int tid = pthread_self();
102 arg = ((void**)arg)[1];
103 if (tid >= thread_join_count) {
104 int oc = thread_join_count;
106 thread_join_count = tid + 5 + tid/5;
107 if (thread_join_data) {
108 Renew(thread_join_data, thread_join_count, thread_join_t);
109 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
111 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
114 if (thread_join_data[tid].state != pthreads_st_none)
115 Perl_croak_nocontext("attempt to reuse thread id %i", tid);
116 thread_join_data[tid].state = pthreads_st_run;
117 /* Now that we copied/updated the guys, we may release the caller... */
118 MUTEX_UNLOCK(&start_thread_mutex);
119 thread_join_data[tid].status = (*start_routine)(arg);
120 switch (thread_join_data[tid].state) {
121 case pthreads_st_waited:
122 COND_SIGNAL(&thread_join_data[tid].cond);
125 thread_join_data[tid].state = pthreads_st_exited;
131 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
132 void *(*start_routine)(void*), void *arg)
136 args[0] = (void*)start_routine;
139 MUTEX_LOCK(&start_thread_mutex);
140 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
141 /*stacksize*/ 10*1024*1024, (void*)args);
142 MUTEX_LOCK(&start_thread_mutex);
143 MUTEX_UNLOCK(&start_thread_mutex);
144 return *tid ? 0 : EINVAL;
148 pthread_detach(perl_os_thread tid)
150 MUTEX_LOCK(&start_thread_mutex);
151 switch (thread_join_data[tid].state) {
152 case pthreads_st_waited:
153 MUTEX_UNLOCK(&start_thread_mutex);
154 Perl_croak_nocontext("detach on a thread with a waiter");
156 case pthreads_st_run:
157 thread_join_data[tid].state = pthreads_st_detached;
158 MUTEX_UNLOCK(&start_thread_mutex);
161 MUTEX_UNLOCK(&start_thread_mutex);
162 Perl_croak_nocontext("detach: unknown thread state: '%s'",
163 pthreads_states[thread_join_data[tid].state]);
169 /* This is a very bastardized version: */
171 os2_cond_wait(perl_cond *c, perl_mutex *m)
175 if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
176 Perl_croak_nocontext("panic: COND_WAIT-reset: rc=%i", rc);
177 if (m) MUTEX_UNLOCK(m);
178 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
179 && (rc != ERROR_INTERRUPT))
180 Perl_croak_nocontext("panic: COND_WAIT: rc=%i", rc);
181 if (rc == ERROR_INTERRUPT)
183 if (m) MUTEX_LOCK(m);
187 /*****************************************************************************/
188 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
189 static PFN ExtFCN[2]; /* Labeled by ord below. */
190 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
191 #define ORD_QUERY_ELP 0
192 #define ORD_SET_ELP 1
193 struct PMWIN_entries_t PMWIN_entries;
196 loadModule(char *modname)
198 HMODULE h = (HMODULE)dlopen(modname, 0);
200 Perl_croak_nocontext("Error loading module '%s': %s",
206 loadByOrd(char *modname, ULONG ord)
208 if (ExtFCN[ord] == NULL) {
209 static HMODULE hdosc = 0;
214 hdosc = loadModule(modname);
215 if (CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
216 Perl_croak_nocontext(
217 "This version of OS/2 does not support %s.%i",
218 modname, loadOrd[ord]);
221 if ((long)ExtFCN[ord] == -1)
222 Perl_croak_nocontext("panic queryaddr");
226 init_PMWIN_entries(void)
228 static HMODULE hpmwin = 0;
229 static const int ords[] = {
230 763, /* Initialize */
231 716, /* CreateMsgQueue */
232 726, /* DestroyMsgQueue */
235 912, /* DispatchMsg */
236 753, /* GetLastError */
237 705, /* CancelShutdown */
245 hpmwin = loadModule("pmwin");
246 while (i < sizeof(ords)/sizeof(int)) {
247 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
248 ((PFN*)&PMWIN_entries)+i)))
249 Perl_croak_nocontext("This version of OS/2 does not support pmwin.%d", ords[i]);
256 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
258 #define QSS_INI_BUFFER 1024
261 get_sysinfo(ULONG pid, ULONG flags)
264 ULONG rc, buf_len = QSS_INI_BUFFER;
266 New(1322, pbuffer, buf_len, char);
267 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
268 rc = QuerySysState(flags, pid, pbuffer, buf_len);
269 while (rc == ERROR_BUFFER_OVERFLOW) {
270 Renew(pbuffer, buf_len *= 2, char);
271 rc = QuerySysState(flags, pid, pbuffer, buf_len);
278 return (PQTOPLEVEL)pbuffer;
281 #define PRIO_ERR 0x1111
289 psi = get_sysinfo(pid, QSS_PROCESS);
293 if (pid != psi->procdata->pid) {
295 Perl_croak_nocontext("panic: wrong pid in sysinfo");
297 prio = psi->procdata->threads->priority;
303 setpriority(int which, int pid, int val)
305 ULONG rc, prio = sys_prio(pid);
307 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
308 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
309 /* Do not change class. */
310 return CheckOSError(DosSetPriority((pid < 0)
311 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
313 (32 - val) % 32 - (prio & 0xFF),
316 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
317 /* Documentation claims one can change both class and basevalue,
318 * but I find it wrong. */
319 /* Change class, but since delta == 0 denotes absolute 0, correct. */
320 if (CheckOSError(DosSetPriority((pid < 0)
321 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
322 priors[(32 - val) >> 5] + 1,
326 if ( ((32 - val) % 32) == 0 ) return 0;
327 return CheckOSError(DosSetPriority((pid < 0)
328 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
334 /* else return CheckOSError(DosSetPriority((pid < 0) */
335 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
336 /* priors[(32 - val) >> 5] + 1, */
337 /* (32 - val) % 32 - (prio & 0xFF), */
343 getpriority(int which /* ignored */, int pid)
347 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
349 if (ret == PRIO_ERR) {
352 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
355 /*****************************************************************************/
358 /* There is no big sense to make it thread-specific, since signals
359 are delivered to thread 1 only. XXXX Maybe make it into an array? */
360 static int spawn_pid;
361 static int spawn_killed;
364 spawn_sighandler(int sig)
366 /* Some programs do not arrange for the keyboard signals to be
367 delivered to them. We need to deliver the signal manually. */
368 /* We may get a signal only if
369 a) kid does not receive keyboard signal: deliver it;
370 b) kid already died, and we get a signal. We may only hope
371 that the pid number was not reused.
375 sig = SIGKILL; /* Try harder. */
376 kill(spawn_pid, sig);
381 result(pTHX_ int flag, int pid)
384 Signal_t (*ihand)(); /* place to save signal during system() */
385 Signal_t (*qhand)(); /* place to save signal during system() */
391 if (pid < 0 || flag != 0)
397 ihand = rsignal(SIGINT, &spawn_sighandler);
398 qhand = rsignal(SIGQUIT, &spawn_sighandler);
400 r = wait4pid(pid, &status, 0);
401 } while (r == -1 && errno == EINTR);
402 rsignal(SIGINT, ihand);
403 rsignal(SIGQUIT, qhand);
405 PL_statusvalue = (U16)status;
408 return status & 0xFFFF;
410 ihand = rsignal(SIGINT, SIG_IGN);
411 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
412 rsignal(SIGINT, ihand);
413 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
416 return PL_statusvalue;
420 #define EXECF_SPAWN 0
422 #define EXECF_TRUEEXEC 2
423 #define EXECF_SPAWN_NOWAIT 3
424 #define EXECF_SPAWN_BYFLAG 4
426 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
435 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
436 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
439 return (pib->pib_ultype);
443 file_type(char *path)
448 if (!(_emx_env & 0x200))
449 Perl_croak_nocontext("file_type not implemented on DOS"); /* not OS/2. */
450 if (CheckOSError(DosQueryAppType(path, &apptype))) {
452 case ERROR_FILE_NOT_FOUND:
453 case ERROR_PATH_NOT_FOUND:
455 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
457 default: /* Found, but not an
458 executable, or some other
466 static ULONG os2_mytype;
468 /* Spawn/exec a program, revert to shell if needed. */
469 /* global PL_Argv[] contains arguments. */
472 do_spawn_ve(pTHX_ SV *really, U32 flag, U32 execf, char *inicmd, U32 addflag)
478 static char * fargs[4]
479 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
480 char **argsp = fargs;
483 int new_stderr = -1, nostderr = 0;
493 if (strEQ(PL_Argv[0],"/bin/sh"))
494 PL_Argv[0] = PL_sh_path;
496 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
497 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
498 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
499 ) /* will spawnvp use PATH? */
500 TAINT_ENV(); /* testing IFS here is overkill, probably */
501 /* We should check PERL_SH* and PERLLIB_* as well? */
502 if (!really || !*(tmps = SvPV(really, n_a)))
507 if (_emx_env & 0x200) { /* OS/2. */
508 int type = file_type(tmps);
510 if (type == -1) { /* Not found */
515 else if (type == -2) { /* Not an EXE */
520 else if (type == -3) { /* Is a directory? */
521 /* Special-case this */
523 int l = strlen(tmps);
525 if (l + 5 <= sizeof tbuf) {
527 strcpy(tbuf + l, ".exe");
528 type = file_type(tbuf);
538 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
539 case FAPPTYP_WINDOWAPI:
541 if (os2_mytype != 3) { /* not PM */
542 if (flag == P_NOWAIT)
544 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
545 Perl_warner(aTHX_ WARN_EXEC, "Starting PM process with flag=%d, mytype=%d",
550 case FAPPTYP_NOTWINDOWCOMPAT:
552 if (os2_mytype != 0) { /* not full screen */
553 if (flag == P_NOWAIT)
555 else if ((flag & 7) != P_SESSION)
556 Perl_warner(aTHX_ WARN_EXEC, "Starting Full Screen process with flag=%d, mytype=%d",
561 case FAPPTYP_NOTSPEC:
562 /* Let the shell handle this... */
564 buf = ""; /* Pacify a warning */
565 file = 0; /* Pacify a warning */
573 new_stderr = dup(2); /* Preserve stderr */
574 if (new_stderr == -1) {
582 fl_stderr = fcntl(2, F_GETFD);
586 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
590 rc = result(aTHX_ trueflag, spawnvp(flag,tmps,PL_Argv));
592 if (execf == EXECF_TRUEEXEC)
593 rc = execvp(tmps,PL_Argv);
594 else if (execf == EXECF_EXEC)
595 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
596 else if (execf == EXECF_SPAWN_NOWAIT)
597 rc = spawnvp(flag,tmps,PL_Argv);
598 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
599 rc = result(aTHX_ trueflag,
600 spawnvp(flag,tmps,PL_Argv));
602 if (rc < 0 && pass == 1
603 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
608 if (err == ENOENT || err == ENOEXEC) {
609 /* No such file, or is a script. */
610 /* Try adding script extensions to the file name, and
612 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
616 SV *scrsv = sv_2mortal(newSVpv(scr, 0));
617 SV *bufsv = sv_newmortal();
620 scr = SvPV(scrsv, n_a); /* free()ed later */
622 file = PerlIO_open(scr, "r");
627 buf = sv_gets(bufsv, file, 0 /* No append */);
629 buf = ""; /* XXX Needed? */
630 if (!buf[0]) { /* Empty... */
632 /* Special case: maybe from -Zexe build, so
633 there is an executable around (contrary to
634 documentation, DosQueryAppType sometimes (?)
635 does not append ".exe", so we could have
636 reached this place). */
637 sv_catpv(scrsv, ".exe");
638 scr = SvPV(scrsv, n_a); /* Reload */
639 if (PerlLIO_stat(scr,&PL_statbuf) >= 0
640 && !S_ISDIR(PL_statbuf.st_mode)) { /* Found */
644 } else { /* Restore */
645 SvCUR_set(scrsv, SvCUR(scrsv) - 4);
649 if (PerlIO_close(file) != 0) { /* Failure */
651 Perl_warner(aTHX_ WARN_EXEC, "Error reading \"%s\": %s",
652 scr, Strerror(errno));
653 buf = ""; /* Not #! */
659 } else if (buf[0] == 'e') {
660 if (strnEQ(buf, "extproc", 7)
663 } else if (buf[0] == 'E') {
664 if (strnEQ(buf, "EXTPROC", 7)
669 buf = ""; /* Not #! */
677 /* Do better than pdksh: allow a few args,
678 strip trailing whitespace. */
688 while (*s && !isSPACE(*s))
695 Perl_warner(aTHX_ WARN_EXEC, "Too many args on %.*s line of \"%s\"",
700 /* Can jump from far, buf/file invalid if force_shell: */
707 || (!buf[0] && file)) { /* File without magic */
708 /* In fact we tried all what pdksh would
709 try. There is no point in calling
710 pdksh, we may just emulate its logic. */
711 char *shell = getenv("EXECSHELL");
712 char *shell_opt = NULL;
718 shell = getenv("OS2_SHELL");
719 if (inicmd) { /* No spaces at start! */
721 while (*s && !isSPACE(*s)) {
723 inicmd = NULL; /* Cannot use */
731 /* Dosish shells will choke on slashes
732 in paths, fortunately, this is
733 important for zeroth arg only. */
740 /* If EXECSHELL is set, we do not set */
743 shell = ((_emx_env & 0x200)
746 nargs = shell_opt ? 2 : 1; /* shell file args */
747 exec_args[0] = shell;
748 exec_args[1] = shell_opt;
750 if (nargs == 2 && inicmd) {
751 /* Use the original cmd line */
752 /* XXXX This is good only until we refuse
753 quoted arguments... */
757 } else if (!buf[0] && inicmd) { /* No file */
758 /* Start with the original cmdline. */
759 /* XXXX This is good only until we refuse
760 quoted arguments... */
764 nargs = 2; /* shell -c */
767 while (a[1]) /* Get to the end */
769 a++; /* Copy finil NULL too */
770 while (a >= PL_Argv) {
771 *(a + nargs) = *a; /* PL_Argv was preallocated to be
776 PL_Argv[nargs] = argsp[nargs];
777 /* Enable pathless exec if #! (as pdksh). */
778 pass = (buf[0] == '#' ? 2 : 3);
782 /* Not found: restore errno */
786 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
787 char *no_dir = strrchr(PL_Argv[0], '/');
789 /* Do as pdksh port does: if not found with /, try without
792 PL_Argv[0] = no_dir + 1;
797 if (rc < 0 && ckWARN(WARN_EXEC))
798 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n",
799 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
801 PL_Argv[0], Strerror(errno));
802 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
803 && ((trueflag & 0xFF) == P_WAIT))
807 if (new_stderr != -1) { /* How can we use error codes? */
810 fcntl(2, F_SETFD, fl_stderr);
816 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
818 do_spawn3(pTHX_ char *cmd, int execf, int flag)
822 char *shell, *copt, *news = NULL;
823 int rc, seenspace = 0, mergestderr = 0;
826 if ((shell = getenv("EMXSHELL")) != NULL)
828 else if ((shell = getenv("SHELL")) != NULL)
830 else if ((shell = getenv("COMSPEC")) != NULL)
835 /* Consensus on perl5-porters is that it is _very_ important to
836 have a shell which will not change between computers with the
837 same architecture, to avoid "action on a distance".
838 And to have simple build, this shell should be sh. */
843 while (*cmd && isSPACE(*cmd))
846 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
847 STRLEN l = strlen(PL_sh_path);
849 New(1302, news, strlen(cmd) - 7 + l + 1, char);
850 strcpy(news, PL_sh_path);
851 strcpy(news + l, cmd + 7);
855 /* save an extra exec if possible */
856 /* see if there are shell metacharacters in it */
858 if (*cmd == '.' && isSPACE(cmd[1]))
861 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
864 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
868 for (s = cmd; *s; s++) {
869 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
870 if (*s == '\n' && s[1] == '\0') {
873 } else if (*s == '\\' && !seenspace) {
874 continue; /* Allow backslashes in names */
875 } else if (*s == '>' && s >= cmd + 3
876 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
877 && isSPACE(s[-2]) ) {
880 while (*t && isSPACE(*t))
885 break; /* Allow 2>&1 as the last thing */
888 /* We do not convert this to do_spawn_ve since shell
889 should be smart enough to start itself gloriously. */
891 if (execf == EXECF_TRUEEXEC)
892 rc = execl(shell,shell,copt,cmd,(char*)0);
893 else if (execf == EXECF_EXEC)
894 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
895 else if (execf == EXECF_SPAWN_NOWAIT)
896 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
897 else if (execf == EXECF_SPAWN_BYFLAG)
898 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
900 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
901 rc = result(aTHX_ P_WAIT,
902 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
903 if (rc < 0 && ckWARN(WARN_EXEC))
904 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
905 (execf == EXECF_SPAWN ? "spawn" : "exec"),
906 shell, Strerror(errno));
913 } else if (*s == ' ' || *s == '\t') {
918 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
919 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
920 PL_Cmd = savepvn(cmd, s-cmd);
922 for (s = PL_Cmd; *s;) {
923 while (*s && isSPACE(*s)) s++;
926 while (*s && !isSPACE(*s)) s++;
932 rc = do_spawn_ve(aTHX_ NULL, flag, execf, cmd, mergestderr);
943 os2_do_aspawn(pTHX_ SV *really, register void **vmark, register void **vsp)
945 register SV **mark = (SV **)vmark;
946 register SV **sp = (SV **)vsp;
949 int flag = P_WAIT, flag_set = 0;
953 New(1301,PL_Argv, sp - mark + 3, char*);
956 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
963 while (++mark <= sp) {
965 *a++ = SvPVx(*mark, n_a);
971 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
972 rc = do_spawn3(aTHX_ a[-1], EXECF_SPAWN_BYFLAG, flag);
974 rc = do_spawn_ve(aTHX_ really, flag, EXECF_SPAWN, NULL, 0);
982 os2_do_spawn(pTHX_ char *cmd)
984 return do_spawn3(aTHX_ cmd, EXECF_SPAWN, 0);
988 do_spawn_nowait(pTHX_ char *cmd)
990 return do_spawn3(aTHX_ cmd, EXECF_SPAWN_NOWAIT,0);
994 Perl_do_exec(pTHX_ char *cmd)
996 do_spawn3(aTHX_ cmd, EXECF_EXEC, 0);
1001 os2exec(pTHX_ char *cmd)
1003 return do_spawn3(aTHX_ cmd, EXECF_TRUEEXEC, 0);
1007 my_syspopen(pTHX_ char *cmd, char *mode)
1011 register I32 this, that, newfd;
1014 int fh_fl = 0; /* Pacify the warning */
1016 /* `this' is what we use in the parent, `that' in the child. */
1017 this = (*mode == 'w');
1021 taint_proper("Insecure %s%s", "EXEC");
1025 /* Now we need to spawn the child. */
1026 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1027 int new = dup(p[this]);
1034 newfd = dup(*mode == 'r'); /* Preserve std* */
1036 /* This cannot happen due to fh being bad after pipe(), since
1037 pipe() should have created fh 0 and 1 even if they were
1038 initially closed. But we closed p[this] before. */
1039 if (errno != EBADF) {
1046 fh_fl = fcntl(*mode == 'r', F_GETFD);
1047 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1048 dup2(p[that], *mode == 'r');
1051 /* Where is `this' and newfd now? */
1052 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1054 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1055 pid = do_spawn_nowait(aTHX_ cmd);
1057 close(*mode == 'r'); /* It was closed initially */
1058 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1059 dup2(newfd, *mode == 'r'); /* Return std* back. */
1061 fcntl(*mode == 'r', F_SETFD, fh_fl);
1063 fcntl(*mode == 'r', F_SETFD, fh_fl);
1064 if (p[that] == (*mode == 'r'))
1070 if (p[that] < p[this]) { /* Make fh as small as possible */
1071 dup2(p[this], p[that]);
1075 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1076 (void)SvUPGRADE(sv,SVt_IV);
1078 PL_forkprocess = pid;
1079 return PerlIO_fdopen(p[this], mode);
1081 #else /* USE_POPEN */
1087 res = popen(cmd, mode);
1089 char *shell = getenv("EMXSHELL");
1091 my_setenv("EMXSHELL", PL_sh_path);
1092 res = popen(cmd, mode);
1093 my_setenv("EMXSHELL", shell);
1095 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1096 (void)SvUPGRADE(sv,SVt_IV);
1097 SvIVX(sv) = -1; /* A cooky. */
1100 #endif /* USE_POPEN */
1104 /******************************************************************/
1110 Perl_croak_nocontext(PL_no_func, "Unsupported function fork");
1116 /*******************************************************************/
1117 /* not implemented in EMX 0.9d */
1119 char * ctermid(char *s) { return 0; }
1121 #ifdef MYTTYNAME /* was not in emx0.9a */
1122 void * ttyname(x) { return 0; }
1125 /******************************************************************/
1126 /* my socket forwarders - EMX lib only provides static forwarders */
1128 static HMODULE htcp = 0;
1135 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1137 htcp = loadModule("tcp32dll");
1138 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1139 return (void *) ((void * (*)(void)) fcn) ();
1144 tcp1(char *name, int arg)
1146 static BYTE buf[20];
1149 if (!(_emx_env & 0x200)) Perl_croak_nocontext("%s requires OS/2", name); /* Die if not OS/2. */
1151 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1152 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1153 ((void (*)(int)) fcn) (arg);
1156 struct hostent * gethostent() { return tcp0("GETHOSTENT"); }
1157 struct netent * getnetent() { return tcp0("GETNETENT"); }
1158 struct protoent * getprotoent() { return tcp0("GETPROTOENT"); }
1159 struct servent * getservent() { return tcp0("GETSERVENT"); }
1161 void sethostent(x) { tcp1("SETHOSTENT", x); }
1162 void setnetent(x) { tcp1("SETNETENT", x); }
1163 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1164 void setservent(x) { tcp1("SETSERVENT", x); }
1165 void endhostent() { tcp0("ENDHOSTENT"); }
1166 void endnetent() { tcp0("ENDNETENT"); }
1167 void endprotoent() { tcp0("ENDPROTOENT"); }
1168 void endservent() { tcp0("ENDSERVENT"); }
1170 /*****************************************************************************/
1171 /* not implemented in C Set++ */
1174 int setuid(x) { errno = EINVAL; return -1; }
1175 int setgid(x) { errno = EINVAL; return -1; }
1178 /*****************************************************************************/
1179 /* stat() hack for char/block device */
1183 /* First attempt used DosQueryFSAttach which crashed the system when
1184 used with 5.001. Now just look for /dev/. */
1187 os2_stat(const char *name, struct stat *st)
1189 static int ino = SHRT_MAX;
1191 if (stricmp(name, "/dev/con") != 0
1192 && stricmp(name, "/dev/tty") != 0)
1193 return stat(name, st);
1195 memset(st, 0, sizeof *st);
1196 st->st_mode = S_IFCHR|0666;
1197 st->st_ino = (ino-- & 0x7FFF);
1204 #ifdef USE_PERL_SBRK
1206 /* SBRK() emulation, mostly moved to malloc.c. */
1209 sys_alloc(int size) {
1211 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1213 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1216 Perl_croak_nocontext("Got an error from DosAllocMem: %li", (long)rc);
1220 #endif /* USE_PERL_SBRK */
1224 char *tmppath = TMPPATH1;
1229 char *p = getenv("TMP"), *tpath;
1232 if (!p) p = getenv("TEMP");
1235 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1239 strcpy(tpath + len + 1, TMPPATH1);
1246 XS(XS_File__Copy_syscopy)
1249 if (items < 2 || items > 3)
1250 Perl_croak_nocontext("Usage: File::Copy::syscopy(src,dst,flag=0)");
1253 char * src = (char *)SvPV(ST(0),n_a);
1254 char * dst = (char *)SvPV(ST(1),n_a);
1261 flag = (unsigned long)SvIV(ST(2));
1264 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1265 ST(0) = sv_newmortal();
1266 sv_setiv(ST(0), (IV)RETVAL);
1271 #define PERL_PATCHLEVEL_H_IMPLICIT /* Do not init local_patches. */
1272 #include "patchlevel.h"
1273 #undef PERL_PATCHLEVEL_H_IMPLICIT
1276 mod2fname(pTHX_ SV *sv)
1278 static char fname[9];
1279 int pos = 6, len, avlen;
1280 unsigned int sum = 0;
1284 if (!SvROK(sv)) Perl_croak_nocontext("Not a reference given to mod2fname");
1286 if (SvTYPE(sv) != SVt_PVAV)
1287 Perl_croak_nocontext("Not array reference given to mod2fname");
1289 avlen = av_len((AV*)sv);
1291 Perl_croak_nocontext("Empty array reference given to mod2fname");
1293 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1294 strncpy(fname, s, 8);
1296 if (len < 6) pos = len;
1298 sum = 33 * sum + *(s++); /* Checksumming first chars to
1299 * get the capitalization into c.s. */
1302 while (avlen >= 0) {
1303 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1305 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1310 sum++; /* Avoid conflict of DLLs in memory. */
1312 /* We always load modules as *specific* DLLs, and with the full name.
1313 When loading a specific DLL by its full name, one cannot get a
1314 different DLL, even if a DLL with the same basename is loaded already.
1315 Thus there is no need to include the version into the mangling scheme. */
1317 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* Up to 5.6.1 */
1319 # ifndef COMPATIBLE_VERSION_SUM /* Binary compatibility with the 5.00553 binary */
1320 # define COMPATIBLE_VERSION_SUM (5 * 200 + 53 * 2)
1322 sum += COMPATIBLE_VERSION_SUM;
1324 fname[pos] = 'A' + (sum % 26);
1325 fname[pos + 1] = 'A' + (sum / 26 % 26);
1326 fname[pos + 2] = '\0';
1327 return (char *)fname;
1330 XS(XS_DynaLoader_mod2fname)
1334 Perl_croak_nocontext("Usage: DynaLoader::mod2fname(sv)");
1339 RETVAL = mod2fname(aTHX_ sv);
1340 ST(0) = sv_newmortal();
1341 sv_setpv((SV*)ST(0), RETVAL);
1349 static char buf[300];
1352 int number = SvTRUE(get_sv("OS2::nsyserror", TRUE));
1354 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1358 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1359 s = buf + strlen(buf);
1362 if (DosGetMessage(NULL, 0, s, sizeof(buf) - 1 - (s-buf),
1363 rc, "OSO001.MSG", &len)) {
1365 sprintf(buf, "SYS%04d=%#x: ", rc, rc);
1366 s = buf + strlen(buf);
1368 sprintf(s, "[No description found in OSO001.MSG]");
1371 if (len && s[len - 1] == '\n')
1373 if (len && s[len - 1] == '\r')
1375 if (len && s[len - 1] == '.')
1377 if (len >= 10 && number && strnEQ(s, buf, 7)
1378 && s[7] == ':' && s[8] == ' ')
1379 /* Some messages start with SYSdddd:, some not */
1380 Move(s + 9, s, (len -= 9) + 1, char);
1388 char buf[300], *p, *o = PL_origargv[0], ok = 1;
1390 if (_execname(buf, sizeof buf) != 0)
1397 if (ok && *o != '/' && *o != '\\')
1399 } else if (ok && tolower(*o) != tolower(*p))
1404 if (ok) { /* PL_origargv[0] matches the real name. Use PL_origargv[0]: */
1405 strcpy(buf, PL_origargv[0]); /* _execname() is always uppercased */
1419 perllib_mangle(char *s, unsigned int l)
1421 static char *newp, *oldp;
1422 static int newl, oldl, notfound;
1423 static char ret[STATIC_FILE_LENGTH+1];
1425 if (!newp && !notfound) {
1426 newp = getenv("PERLLIB_PREFIX");
1431 while (*newp && !isSPACE(*newp) && *newp != ';') {
1432 newp++; oldl++; /* Skip digits. */
1434 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1435 newp++; /* Skip whitespace. */
1437 newl = strlen(newp);
1438 if (newl == 0 || oldl == 0) {
1439 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1444 if (*s == '\\') *s = '/';
1457 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1460 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1461 Perl_croak_nocontext("Malformed PERLLIB_PREFIX");
1463 strcpy(ret + newl, s + oldl);
1468 Perl_hab_GET() /* Needed if perl.h cannot be included */
1470 return perl_hab_GET();
1474 Perl_Register_MQ(int serve)
1479 if (Perl_os2_initial_mode++)
1481 DosGetInfoBlocks(&tib, &pib);
1482 Perl_os2_initial_mode = pib->pib_ultype;
1483 /* Try morphing into a PM application. */
1484 if (pib->pib_ultype != 3) /* 2 is VIO */
1485 pib->pib_ultype = 3; /* 3 is PM */
1486 init_PMWIN_entries();
1487 /* 64 messages if before OS/2 3.0, ignored otherwise */
1488 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1492 SAVEINT(cnt); /* Allow catch()ing. */
1494 _exit(188); /* Panic can try to create a window. */
1495 Perl_croak_nocontext("Cannot create a message queue, or morph to a PM application");
1498 if ( Perl_hmq_servers <= 0 /* Safe to inform us on shutdown, */
1499 && Perl_hmq_refcnt > 0 ) /* this was switched off before... */
1500 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 0);
1502 } else if (!Perl_hmq_servers) /* Do not inform us on shutdown */
1503 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1509 Perl_Serve_Messages(int force)
1514 if (Perl_hmq_servers > 0 && !force)
1516 if (Perl_hmq_refcnt <= 0)
1517 Perl_croak_nocontext("No message queue");
1518 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1520 if (msg.msg == WM_QUIT)
1521 Perl_croak_nocontext("QUITing...");
1522 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1528 Perl_Process_Messages(int force, I32 *cntp)
1532 if (Perl_hmq_servers > 0 && !force)
1534 if (Perl_hmq_refcnt <= 0)
1535 Perl_croak_nocontext("No message queue");
1536 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1539 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1540 if (msg.msg == WM_DESTROY)
1542 if (msg.msg == WM_CREATE)
1545 Perl_croak_nocontext("QUITing...");
1549 Perl_Deregister_MQ(int serve)
1556 if (--Perl_hmq_refcnt <= 0) {
1557 init_PMWIN_entries(); /* To be extra safe */
1558 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1560 /* Try morphing back from a PM application. */
1561 DosGetInfoBlocks(&tib, &pib);
1562 if (pib->pib_ultype == 3) /* 3 is PM */
1563 pib->pib_ultype = Perl_os2_initial_mode;
1565 Perl_warn_nocontext("Unexpected program mode %d when morphing back from PM",
1567 } else if (serve && Perl_hmq_servers <= 0) /* Last server exited */
1568 (*PMWIN_entries.CancelShutdown)(Perl_hmq, 1);
1571 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1572 && ((path)[2] == '/' || (path)[2] == '\\'))
1573 #define sys_is_rooted _fnisabs
1574 #define sys_is_relative _fnisrel
1575 #define current_drive _getdrive
1577 #undef chdir /* Was _chdir2. */
1578 #define sys_chdir(p) (chdir(p) == 0)
1579 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1581 static int DOS_harderr_state = -1;
1587 Perl_croak_nocontext("Usage: OS2::Error(harderr, exception)");
1589 int arg1 = SvIV(ST(0));
1590 int arg2 = SvIV(ST(1));
1591 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1592 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1593 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1596 if (CheckOSError(DosError(a)))
1597 Perl_croak_nocontext("DosError(%d) failed", a);
1598 ST(0) = sv_newmortal();
1599 if (DOS_harderr_state >= 0)
1600 sv_setiv(ST(0), DOS_harderr_state);
1601 DOS_harderr_state = RETVAL;
1606 static signed char DOS_suppression_state = -1;
1608 XS(XS_OS2_Errors2Drive)
1612 Perl_croak_nocontext("Usage: OS2::Errors2Drive(drive)");
1616 int suppress = SvOK(sv);
1617 char *s = suppress ? SvPV(sv, n_a) : NULL;
1618 char drive = (s ? *s : 0);
1621 if (suppress && !isALPHA(drive))
1622 Perl_croak_nocontext("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1623 if (CheckOSError(DosSuppressPopUps((suppress
1624 ? SPU_ENABLESUPPRESSION
1625 : SPU_DISABLESUPPRESSION),
1627 Perl_croak_nocontext("DosSuppressPopUps(%c) failed", drive);
1628 ST(0) = sv_newmortal();
1629 if (DOS_suppression_state > 0)
1630 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1631 else if (DOS_suppression_state == 0)
1632 sv_setpvn(ST(0), "", 0);
1633 DOS_suppression_state = drive;
1638 static const char * const si_fields[QSV_MAX] = {
1640 "MAX_TEXT_SESSIONS",
1644 "DYN_PRI_VARIATION",
1662 "FOREGROUND_FS_SESSION",
1663 "FOREGROUND_PROCESS"
1670 Perl_croak_nocontext("Usage: OS2::SysInfo()");
1672 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1673 APIRET rc = NO_ERROR; /* Return code */
1676 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1677 QSV_MAX, /* information */
1680 Perl_croak_nocontext("DosQuerySysInfo() failed");
1681 EXTEND(SP,2*QSV_MAX);
1682 while (i < QSV_MAX) {
1683 ST(j) = sv_newmortal();
1684 sv_setpv(ST(j++), si_fields[i]);
1685 ST(j) = sv_newmortal();
1686 sv_setiv(ST(j++), si[i]);
1690 XSRETURN(2 * QSV_MAX);
1693 XS(XS_OS2_BootDrive)
1697 Perl_croak_nocontext("Usage: OS2::BootDrive()");
1699 ULONG si[1] = {0}; /* System Information Data Buffer */
1700 APIRET rc = NO_ERROR; /* Return code */
1703 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1704 (PVOID)si, sizeof(si))))
1705 Perl_croak_nocontext("DosQuerySysInfo() failed");
1706 ST(0) = sv_newmortal();
1707 c = 'a' - 1 + si[0];
1708 sv_setpvn(ST(0), &c, 1);
1717 Perl_croak_nocontext("Usage: OS2::MorphPM(serve)");
1719 bool serve = SvOK(ST(0));
1720 unsigned long pmq = perl_hmq_GET(serve);
1722 ST(0) = sv_newmortal();
1723 sv_setiv(ST(0), pmq);
1728 XS(XS_OS2_UnMorphPM)
1732 Perl_croak_nocontext("Usage: OS2::UnMorphPM(serve)");
1734 bool serve = SvOK(ST(0));
1736 perl_hmq_UNSET(serve);
1741 XS(XS_OS2_Serve_Messages)
1745 Perl_croak_nocontext("Usage: OS2::Serve_Messages(force)");
1747 bool force = SvOK(ST(0));
1748 unsigned long cnt = Perl_Serve_Messages(force);
1750 ST(0) = sv_newmortal();
1751 sv_setiv(ST(0), cnt);
1756 XS(XS_OS2_Process_Messages)
1759 if (items < 1 || items > 2)
1760 Perl_croak_nocontext("Usage: OS2::Process_Messages(force [, cnt])");
1762 bool force = SvOK(ST(0));
1769 (void)SvIV(sv); /* Force SvIVX */
1771 Perl_croak_nocontext("Can't upgrade count to IV");
1773 cnt = Perl_Process_Messages(force, &cntr);
1776 cnt = Perl_Process_Messages(force, NULL);
1778 ST(0) = sv_newmortal();
1779 sv_setiv(ST(0), cnt);
1784 XS(XS_Cwd_current_drive)
1788 Perl_croak_nocontext("Usage: Cwd::current_drive()");
1792 RETVAL = current_drive();
1793 ST(0) = sv_newmortal();
1794 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1799 XS(XS_Cwd_sys_chdir)
1803 Perl_croak_nocontext("Usage: Cwd::sys_chdir(path)");
1806 char * path = (char *)SvPV(ST(0),n_a);
1809 RETVAL = sys_chdir(path);
1810 ST(0) = boolSV(RETVAL);
1811 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1816 XS(XS_Cwd_change_drive)
1820 Perl_croak_nocontext("Usage: Cwd::change_drive(d)");
1823 char d = (char)*SvPV(ST(0),n_a);
1826 RETVAL = change_drive(d);
1827 ST(0) = boolSV(RETVAL);
1828 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1833 XS(XS_Cwd_sys_is_absolute)
1837 Perl_croak_nocontext("Usage: Cwd::sys_is_absolute(path)");
1840 char * path = (char *)SvPV(ST(0),n_a);
1843 RETVAL = sys_is_absolute(path);
1844 ST(0) = boolSV(RETVAL);
1845 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1850 XS(XS_Cwd_sys_is_rooted)
1854 Perl_croak_nocontext("Usage: Cwd::sys_is_rooted(path)");
1857 char * path = (char *)SvPV(ST(0),n_a);
1860 RETVAL = sys_is_rooted(path);
1861 ST(0) = boolSV(RETVAL);
1862 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1867 XS(XS_Cwd_sys_is_relative)
1871 Perl_croak_nocontext("Usage: Cwd::sys_is_relative(path)");
1874 char * path = (char *)SvPV(ST(0),n_a);
1877 RETVAL = sys_is_relative(path);
1878 ST(0) = boolSV(RETVAL);
1879 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1888 Perl_croak_nocontext("Usage: Cwd::sys_cwd()");
1892 RETVAL = _getcwd2(p, MAXPATHLEN);
1893 ST(0) = sv_newmortal();
1894 sv_setpv((SV*)ST(0), RETVAL);
1899 XS(XS_Cwd_sys_abspath)
1902 if (items < 1 || items > 2)
1903 Perl_croak_nocontext("Usage: Cwd::sys_abspath(path, dir = NULL)");
1906 char * path = (char *)SvPV(ST(0),n_a);
1914 dir = (char *)SvPV(ST(1),n_a);
1916 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1920 if (_abspath(p, path, MAXPATHLEN) == 0) {
1926 /* Absolute with drive: */
1927 if ( sys_is_absolute(path) ) {
1928 if (_abspath(p, path, MAXPATHLEN) == 0) {
1933 } else if (path[0] == '/' || path[0] == '\\') {
1934 /* Rooted, but maybe on different drive. */
1935 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1936 char p1[MAXPATHLEN];
1938 /* Need to prepend the drive. */
1941 Copy(path, p1 + 2, strlen(path) + 1, char);
1943 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1948 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1954 /* Either path is relative, or starts with a drive letter. */
1955 /* If the path starts with a drive letter, then dir is
1957 a/b) it is absolute/x:relative on the same drive.
1958 c) path is on current drive, and dir is rooted
1959 In all the cases it is safe to drop the drive part
1961 if ( !sys_is_relative(path) ) {
1962 if ( ( ( sys_is_absolute(dir)
1963 || (isALPHA(dir[0]) && dir[1] == ':'
1964 && strnicmp(dir, path,1) == 0))
1965 && strnicmp(dir, path,1) == 0)
1966 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1967 && toupper(path[0]) == current_drive())) {
1969 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1970 RETVAL = p; goto done;
1972 RETVAL = NULL; goto done;
1976 /* Need to prepend the absolute path of dir. */
1977 char p1[MAXPATHLEN];
1979 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1982 if (p1[ l - 1 ] != '/') {
1986 Copy(path, p1 + l, strlen(path) + 1, char);
1987 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1999 ST(0) = sv_newmortal();
2000 sv_setpv((SV*)ST(0), RETVAL);
2004 typedef APIRET (*PELP)(PSZ path, ULONG type);
2006 /* Kernels after 2000/09/15 understand this too: */
2007 #ifndef LIBPATHSTRICT
2008 # define LIBPATHSTRICT 3
2012 ExtLIBPATH(ULONG ord, PSZ path, IV type)
2016 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
2020 what = BEGIN_LIBPATH;
2022 what = LIBPATHSTRICT;
2023 return (*(PELP)ExtFCN[ord])(path, what);
2026 #define extLibpath(to,type) \
2027 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, (to), (type))) ? NULL : (to) )
2029 #define extLibpath_set(p,type) \
2030 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), (type))))
2032 XS(XS_Cwd_extLibpath)
2035 if (items < 0 || items > 1)
2036 Perl_croak_nocontext("Usage: Cwd::extLibpath(type = 0)");
2049 to[0] = 1; to[1] = 0; /* Sometimes no error reported */
2050 RETVAL = extLibpath(to, type);
2051 if (RETVAL && RETVAL[0] == 1 && RETVAL[1] == 0)
2052 Perl_croak_nocontext("panic Cwd::extLibpath parameter");
2053 ST(0) = sv_newmortal();
2054 sv_setpv((SV*)ST(0), RETVAL);
2059 XS(XS_Cwd_extLibpath_set)
2062 if (items < 1 || items > 2)
2063 Perl_croak_nocontext("Usage: Cwd::extLibpath_set(s, type = 0)");
2066 char * s = (char *)SvPV(ST(0),n_a);
2077 RETVAL = extLibpath_set(s, type);
2078 ST(0) = boolSV(RETVAL);
2079 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2084 #define get_control87() _control87(0,0)
2085 #define set_control87 _control87
2087 XS(XS_OS2__control87)
2091 croak("Usage: OS2::_control87(new,mask)");
2093 unsigned new = (unsigned)SvIV(ST(0));
2094 unsigned mask = (unsigned)SvIV(ST(1));
2097 RETVAL = _control87(new, mask);
2098 ST(0) = sv_newmortal();
2099 sv_setiv(ST(0), (IV)RETVAL);
2104 XS(XS_OS2_get_control87)
2108 croak("Usage: OS2::get_control87()");
2112 RETVAL = get_control87();
2113 ST(0) = sv_newmortal();
2114 sv_setiv(ST(0), (IV)RETVAL);
2120 XS(XS_OS2_set_control87)
2123 if (items < 0 || items > 2)
2124 croak("Usage: OS2::set_control87(new=MCW_EM, mask=MCW_EM)");
2133 new = (unsigned)SvIV(ST(0));
2139 mask = (unsigned)SvIV(ST(1));
2142 RETVAL = set_control87(new, mask);
2143 ST(0) = sv_newmortal();
2144 sv_setiv(ST(0), (IV)RETVAL);
2152 char *file = __FILE__;
2156 if (_emx_env & 0x200) { /* OS/2 */
2157 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2158 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2159 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2161 newXS("OS2::Error", XS_OS2_Error, file);
2162 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2163 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2164 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2165 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2166 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2167 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2168 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2169 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2170 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2171 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2172 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2173 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2174 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2175 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2176 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2177 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2178 newXSproto("OS2::_control87", XS_OS2__control87, file, "$$");
2179 newXSproto("OS2::get_control87", XS_OS2_get_control87, file, "");
2180 newXSproto("OS2::set_control87", XS_OS2_set_control87, file, ";$$");
2181 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2184 sv_setiv(GvSV(gv), 1);
2186 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2188 sv_setiv(GvSV(gv), _emx_rev);
2189 sv_setpv(GvSV(gv), _emx_vprt);
2191 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2193 sv_setiv(GvSV(gv), _emx_env);
2194 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2196 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2197 gv = gv_fetchpv("OS2::nsyserror", TRUE, SVt_PV);
2199 sv_setiv(GvSV(gv), 1); /* DEFAULT: Show number on syserror */
2204 OS2_Perl_data_t OS2_Perl_data;
2207 Perl_OS2_init(char **env)
2213 OS2_Perl_data.xs_init = &Xs_OS2_init;
2214 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2215 if (environ == NULL && env) {
2218 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2219 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2220 strcpy(PL_sh_path, SH_PATH);
2221 PL_sh_path[0] = shell[0];
2222 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2223 int l = strlen(shell), i;
2224 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2227 New(1304, PL_sh_path, l + 8, char);
2228 strncpy(PL_sh_path, shell, l);
2229 strcpy(PL_sh_path + l, "/sh.exe");
2230 for (i = 0; i < l; i++) {
2231 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2234 MUTEX_INIT(&start_thread_mutex);
2235 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2236 /* Some DLLs reset FP flags on load. We may have been linked with them */
2237 _control87(MCW_EM, MCW_EM);
2244 my_tmpnam (char *str)
2246 char *p = getenv("TMP"), *tpath;
2248 if (!p) p = getenv("TEMP");
2249 tpath = tempnam(p, "pltmp");
2263 if (s.st_mode & S_IWOTH) {
2266 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2273 my_rmdir (__const__ char *s)
2275 char buf[MAXPATHLEN];
2276 STRLEN l = strlen(s);
2278 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX rmdir fails... */
2289 my_mkdir (__const__ char *s, long perm)
2291 char buf[MAXPATHLEN];
2292 STRLEN l = strlen(s);
2294 if (s[l-1] == '/' || s[l-1] == '\\') { /* EMX mkdir fails... */
2299 return mkdir(s, perm);
2304 /* This code was contributed by Rocco Caputo. */
2306 my_flock(int handle, int o)
2308 FILELOCK rNull, rFull;
2309 ULONG timeout, handle_type, flag_word;
2311 int blocking, shared;
2312 static int use_my = -1;
2315 char *s = getenv("USE_PERL_FLOCK");
2321 if (!(_emx_env & 0x200) || !use_my)
2322 return flock(handle, o); /* Delegate to EMX. */
2325 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2326 (handle_type & 0xFF))
2331 // set lock/unlock ranges
2332 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2333 rFull.lRange = 0x7FFFFFFF;
2334 // set timeout for blocking
2335 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2336 // shared or exclusive?
2337 shared = (o & LOCK_SH) ? 1 : 0;
2338 // do not block the unlock
2339 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2340 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2345 case ERROR_INVALID_HANDLE:
2348 case ERROR_SHARING_BUFFER_EXCEEDED:
2351 case ERROR_LOCK_VIOLATION:
2352 break; // not an error
2353 case ERROR_INVALID_PARAMETER:
2354 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2355 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2358 case ERROR_INTERRUPT:
2367 if (o & (LOCK_SH | LOCK_EX)) {
2368 // for blocking operations
2382 case ERROR_INVALID_HANDLE:
2385 case ERROR_SHARING_BUFFER_EXCEEDED:
2388 case ERROR_LOCK_VIOLATION:
2390 errno = EWOULDBLOCK;
2394 case ERROR_INVALID_PARAMETER:
2395 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2396 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2399 case ERROR_INTERRUPT:
2406 // give away timeslice
2415 static int pwent_cnt;
2416 static int _my_pwent = -1;
2421 if (_my_pwent == -1) {
2422 char *s = getenv("USE_PERL_PWENT");
2424 _my_pwent = atoi(s);
2438 if (!use_my_pwent()) {
2439 setpwent(); /* Delegate to EMX. */
2448 if (!use_my_pwent()) {
2449 endpwent(); /* Delegate to EMX. */
2457 if (!use_my_pwent())
2458 return getpwent(); /* Delegate to EMX. */
2460 return 0; // Return one entry only
2464 static int grent_cnt;
2481 return 0; // Return one entry only
2488 /* Too long to be a crypt() of anything, so it is not-a-valid pw_passwd. */
2489 static const char pw_p[] = "Jf0Wb/BzMFvk7K7lrzK";
2491 static struct passwd *
2492 passw_wrap(struct passwd *p)
2494 static struct passwd pw;
2497 if (!p || (p->pw_passwd && *p->pw_passwd)) /* Not a dangerous password */
2500 s = getenv("PW_PASSWD");
2502 s = (char*)pw_p; /* Make match impossible */
2509 my_getpwuid (uid_t id)
2511 return passw_wrap(getpwuid(id));
2515 my_getpwnam (__const__ char *n)
2517 return passw_wrap(getpwnam(n));