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
12 #include <sys/uflags.h>
15 * Various Unix compatibility functions for OS/2
29 typedef void (*emx_startroutine)(void *);
30 typedef void* (*pthreads_startroutine)(void *);
39 const char *pthreads_states[] = {
50 enum pthreads_state state;
53 thread_join_t *thread_join_data;
54 int thread_join_count;
55 perl_mutex start_thread_mutex;
58 pthread_join(perl_os_thread tid, void **status)
60 MUTEX_LOCK(&start_thread_mutex);
61 switch (thread_join_data[tid].state) {
62 case pthreads_st_exited:
63 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
64 MUTEX_UNLOCK(&start_thread_mutex);
65 *status = thread_join_data[tid].status;
67 case pthreads_st_waited:
68 MUTEX_UNLOCK(&start_thread_mutex);
69 croak("join with a thread with a waiter");
72 thread_join_data[tid].state = pthreads_st_waited;
73 COND_INIT(&thread_join_data[tid].cond);
74 MUTEX_UNLOCK(&start_thread_mutex);
75 COND_WAIT(&thread_join_data[tid].cond, NULL);
76 COND_DESTROY(&thread_join_data[tid].cond);
77 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
78 *status = thread_join_data[tid].status;
81 MUTEX_UNLOCK(&start_thread_mutex);
82 croak("join: unknown thread state: '%s'",
83 pthreads_states[thread_join_data[tid].state]);
90 pthread_startit(void *arg)
92 /* Thread is already started, we need to transfer control only */
93 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
94 int tid = pthread_self();
97 arg = ((void**)arg)[1];
98 if (tid >= thread_join_count) {
99 int oc = thread_join_count;
101 thread_join_count = tid + 5 + tid/5;
102 if (thread_join_data) {
103 Renew(thread_join_data, thread_join_count, thread_join_t);
104 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
106 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
109 if (thread_join_data[tid].state != pthreads_st_none)
110 croak("attempt to reuse thread id %i", tid);
111 thread_join_data[tid].state = pthreads_st_run;
112 /* Now that we copied/updated the guys, we may release the caller... */
113 MUTEX_UNLOCK(&start_thread_mutex);
114 thread_join_data[tid].status = (*start_routine)(arg);
115 switch (thread_join_data[tid].state) {
116 case pthreads_st_waited:
117 COND_SIGNAL(&thread_join_data[tid].cond);
120 thread_join_data[tid].state = pthreads_st_exited;
126 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
127 void *(*start_routine)(void*), void *arg)
131 args[0] = (void*)start_routine;
134 MUTEX_LOCK(&start_thread_mutex);
135 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
136 /*stacksize*/ 10*1024*1024, (void*)args);
137 MUTEX_LOCK(&start_thread_mutex);
138 MUTEX_UNLOCK(&start_thread_mutex);
139 return *tid ? 0 : EINVAL;
143 pthread_detach(perl_os_thread tid)
145 MUTEX_LOCK(&start_thread_mutex);
146 switch (thread_join_data[tid].state) {
147 case pthreads_st_waited:
148 MUTEX_UNLOCK(&start_thread_mutex);
149 croak("detach on a thread with a waiter");
151 case pthreads_st_run:
152 thread_join_data[tid].state = pthreads_st_detached;
153 MUTEX_UNLOCK(&start_thread_mutex);
156 MUTEX_UNLOCK(&start_thread_mutex);
157 croak("detach: unknown thread state: '%s'",
158 pthreads_states[thread_join_data[tid].state]);
164 /* This is a very bastardized version: */
166 os2_cond_wait(perl_cond *c, perl_mutex *m)
170 if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
171 croak("panic: COND_WAIT-reset: rc=%i", rc);
172 if (m) MUTEX_UNLOCK(m);
173 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
174 && (rc != ERROR_INTERRUPT))
175 croak("panic: COND_WAIT: rc=%i", rc);
176 if (rc == ERROR_INTERRUPT)
178 if (m) MUTEX_LOCK(m);
182 /*****************************************************************************/
183 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
184 static PFN ExtFCN[2]; /* Labeled by ord below. */
185 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
186 #define ORD_QUERY_ELP 0
187 #define ORD_SET_ELP 1
188 struct PMWIN_entries_t PMWIN_entries;
191 loadByOrd(char *modname, ULONG ord)
193 if (ExtFCN[ord] == NULL) {
194 static HMODULE hdosc = 0;
199 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
201 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
202 croak("This version of OS/2 does not support %s.%i",
203 modname, loadOrd[ord]);
206 if ((long)ExtFCN[ord] == -1)
207 croak("panic queryaddr");
211 init_PMWIN_entries(void)
213 static HMODULE hpmwin = 0;
214 static const int ords[] = {
215 763, /* Initialize */
216 716, /* CreateMsgQueue */
217 726, /* DestroyMsgQueue */
220 912, /* DispatchMsg */
229 if (CheckOSError(DosLoadModule(buf, sizeof buf, "pmwin", &hpmwin)))
230 croak("This version of OS/2 does not support pmwin: error in %s", buf);
232 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
233 ((PFN*)&PMWIN_entries)+i)))
234 croak("This version of OS/2 does not support pmwin.%d", ords[i]);
241 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
243 #define QSS_INI_BUFFER 1024
246 get_sysinfo(ULONG pid, ULONG flags)
249 ULONG rc, buf_len = QSS_INI_BUFFER;
251 New(1322, pbuffer, buf_len, char);
252 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
253 rc = QuerySysState(flags, pid, pbuffer, buf_len);
254 while (rc == ERROR_BUFFER_OVERFLOW) {
255 Renew(pbuffer, buf_len *= 2, char);
256 rc = QuerySysState(flags, pid, pbuffer, buf_len);
263 return (PQTOPLEVEL)pbuffer;
266 #define PRIO_ERR 0x1111
274 psi = get_sysinfo(pid, QSS_PROCESS);
278 if (pid != psi->procdata->pid) {
280 croak("panic: wrong pid in sysinfo");
282 prio = psi->procdata->threads->priority;
288 setpriority(int which, int pid, int val)
293 prio = sys_prio(pid);
295 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
296 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
297 /* Do not change class. */
298 return CheckOSError(DosSetPriority((pid < 0)
299 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
301 (32 - val) % 32 - (prio & 0xFF),
304 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
305 /* Documentation claims one can change both class and basevalue,
306 * but I find it wrong. */
307 /* Change class, but since delta == 0 denotes absolute 0, correct. */
308 if (CheckOSError(DosSetPriority((pid < 0)
309 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
310 priors[(32 - val) >> 5] + 1,
314 if ( ((32 - val) % 32) == 0 ) return 0;
315 return CheckOSError(DosSetPriority((pid < 0)
316 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
322 /* else return CheckOSError(DosSetPriority((pid < 0) */
323 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
324 /* priors[(32 - val) >> 5] + 1, */
325 /* (32 - val) % 32 - (prio & 0xFF), */
331 getpriority(int which /* ignored */, int pid)
337 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
338 /* DosGetInfoBlocks has old priority! */
339 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
340 /* if (pid != pib->pib_ulpid) { */
342 if (ret == PRIO_ERR) {
346 /* ret = tib->tib_ptib2->tib2_ulpri; */
347 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
350 /*****************************************************************************/
353 /* There is no big sense to make it thread-specific, since signals
354 are delivered to thread 1 only. XXXX Maybe make it into an array? */
355 static int spawn_pid;
356 static int spawn_killed;
359 spawn_sighandler(int sig)
361 /* Some programs do not arrange for the keyboard signals to be
362 delivered to them. We need to deliver the signal manually. */
363 /* We may get a signal only if
364 a) kid does not receive keyboard signal: deliver it;
365 b) kid already died, and we get a signal. We may only hope
366 that the pid number was not reused.
370 sig = SIGKILL; /* Try harder. */
371 kill(spawn_pid, sig);
376 result(int flag, int pid)
379 Signal_t (*ihand)(); /* place to save signal during system() */
380 Signal_t (*qhand)(); /* place to save signal during system() */
386 if (pid < 0 || flag != 0)
392 ihand = rsignal(SIGINT, &spawn_sighandler);
393 qhand = rsignal(SIGQUIT, &spawn_sighandler);
395 r = wait4pid(pid, &status, 0);
396 } while (r == -1 && errno == EINTR);
397 rsignal(SIGINT, ihand);
398 rsignal(SIGQUIT, qhand);
400 PL_statusvalue = (U16)status;
403 return status & 0xFFFF;
405 ihand = rsignal(SIGINT, SIG_IGN);
406 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
407 rsignal(SIGINT, ihand);
408 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
411 return PL_statusvalue;
415 #define EXECF_SPAWN 0
417 #define EXECF_TRUEEXEC 2
418 #define EXECF_SPAWN_NOWAIT 3
419 #define EXECF_SPAWN_BYFLAG 4
421 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
430 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
431 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
434 return (pib->pib_ultype);
438 file_type(char *path)
443 if (!(_emx_env & 0x200))
444 croak("file_type not implemented on DOS"); /* not OS/2. */
445 if (CheckOSError(DosQueryAppType(path, &apptype))) {
447 case ERROR_FILE_NOT_FOUND:
448 case ERROR_PATH_NOT_FOUND:
450 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
452 default: /* Found, but not an
453 executable, or some other
461 static ULONG os2_mytype;
463 /* Spawn/exec a program, revert to shell if needed. */
464 /* global PL_Argv[] contains arguments. */
467 do_spawn_ve(really, flag, execf, inicmd, addflag)
478 char buf[256], *s = 0, scrbuf[280];
480 static char * fargs[4]
481 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
482 char **argsp = fargs;
485 int new_stderr = -1, nostderr = 0, fl_stderr;
492 if (strEQ(PL_Argv[0],"/bin/sh"))
493 PL_Argv[0] = PL_sh_path;
495 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
496 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
497 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
498 ) /* will spawnvp use PATH? */
499 TAINT_ENV(); /* testing IFS here is overkill, probably */
500 /* We should check PERL_SH* and PERLLIB_* as well? */
501 if (!really || !*(tmps = SvPV(really, n_a)))
506 if (_emx_env & 0x200) { /* OS/2. */
507 int type = file_type(tmps);
509 if (type == -1) { /* Not found */
514 else if (type == -2) { /* Not an EXE */
519 else if (type == -3) { /* Is a directory? */
520 /* Special-case this */
522 int l = strlen(tmps);
524 if (l + 5 <= sizeof tbuf) {
526 strcpy(tbuf + l, ".exe");
527 type = file_type(tbuf);
537 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
538 case FAPPTYP_WINDOWAPI:
540 if (os2_mytype != 3) { /* not PM */
541 if (flag == P_NOWAIT)
543 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
544 warn("Starting PM process with flag=%d, mytype=%d",
549 case FAPPTYP_NOTWINDOWCOMPAT:
551 if (os2_mytype != 0) { /* not full screen */
552 if (flag == P_NOWAIT)
554 else if ((flag & 7) != P_SESSION)
555 warn("Starting Full Screen process with flag=%d, mytype=%d",
560 case FAPPTYP_NOTSPEC:
561 /* Let the shell handle this... */
570 new_stderr = dup(2); /* Preserve stderr */
571 if (new_stderr == -1) {
579 fl_stderr = fcntl(2, F_GETFD);
583 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
587 rc = result(trueflag, spawnvp(flag,tmps,PL_Argv));
589 if (execf == EXECF_TRUEEXEC)
590 rc = execvp(tmps,PL_Argv);
591 else if (execf == EXECF_EXEC)
592 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
593 else if (execf == EXECF_SPAWN_NOWAIT)
594 rc = spawnvp(flag,tmps,PL_Argv);
595 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
596 rc = result(trueflag,
597 spawnvp(flag,tmps,PL_Argv));
599 if (rc < 0 && pass == 1
600 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
605 if (err == ENOENT || err == ENOEXEC) {
606 /* No such file, or is a script. */
607 /* Try adding script extensions to the file name, and
609 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
618 if (l >= sizeof scrbuf) {
621 warn("Size of scriptname too big: %d", l);
629 file = fopen(scr, "r");
633 if (!fgets(buf, sizeof buf, file)) { /* Empty... */
637 /* Special case: maybe from -Zexe build, so
638 there is an executable around (contrary to
639 documentation, DosQueryAppType sometimes (?)
640 does not append ".exe", so we could have
641 reached this place). */
642 if (l + 5 < sizeof scrbuf) {
643 strcpy(scrbuf + l, ".exe");
644 if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0
645 && !S_ISDIR(PL_statbuf.st_mode)) {
655 if (fclose(file) != 0) { /* Failure */
657 warn("Error reading \"%s\": %s",
658 scr, Strerror(errno));
659 buf[0] = 0; /* Not #! */
665 } else if (buf[0] == 'e') {
666 if (strnEQ(buf, "extproc", 7)
669 } else if (buf[0] == 'E') {
670 if (strnEQ(buf, "EXTPROC", 7)
675 buf[0] = 0; /* Not #! */
683 /* Do better than pdksh: allow a few args,
684 strip trailing whitespace. */
694 while (*s && !isSPACE(*s))
701 warn("Too many args on %.*s line of \"%s\"",
712 || (!buf[0] && file)) { /* File without magic */
713 /* In fact we tried all what pdksh would
714 try. There is no point in calling
715 pdksh, we may just emulate its logic. */
716 char *shell = getenv("EXECSHELL");
717 char *shell_opt = NULL;
723 shell = getenv("OS2_SHELL");
724 if (inicmd) { /* No spaces at start! */
726 while (*s && !isSPACE(*s)) {
728 inicmd = NULL; /* Cannot use */
736 /* Dosish shells will choke on slashes
737 in paths, fortunately, this is
738 important for zeroth arg only. */
745 /* If EXECSHELL is set, we do not set */
748 shell = ((_emx_env & 0x200)
751 nargs = shell_opt ? 2 : 1; /* shell file args */
752 exec_args[0] = shell;
753 exec_args[1] = shell_opt;
755 if (nargs == 2 && inicmd) {
756 /* Use the original cmd line */
757 /* XXXX This is good only until we refuse
758 quoted arguments... */
762 } else if (!buf[0] && inicmd) { /* No file */
763 /* Start with the original cmdline. */
764 /* XXXX This is good only until we refuse
765 quoted arguments... */
769 nargs = 2; /* shell -c */
772 while (a[1]) /* Get to the end */
774 a++; /* Copy finil NULL too */
775 while (a >= PL_Argv) {
776 *(a + nargs) = *a; /* PL_Argv was preallocated to be
781 PL_Argv[nargs] = argsp[nargs];
782 /* Enable pathless exec if #! (as pdksh). */
783 pass = (buf[0] == '#' ? 2 : 3);
787 /* Not found: restore errno */
791 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
792 char *no_dir = strrchr(PL_Argv[0], '/');
794 /* Do as pdksh port does: if not found with /, try without
797 PL_Argv[0] = no_dir + 1;
802 if (rc < 0 && ckWARN(WARN_EXEC))
803 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n",
804 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
806 PL_Argv[0], Strerror(errno));
807 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
808 && ((trueflag & 0xFF) == P_WAIT))
812 if (new_stderr != -1) { /* How can we use error codes? */
815 fcntl(2, F_SETFD, fl_stderr);
821 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
823 do_spawn3(char *cmd, int execf, int flag)
828 char *shell, *copt, *news = NULL;
829 int rc, err, seenspace = 0, mergestderr = 0;
830 char fullcmd[MAXNAMLEN + 1];
833 if ((shell = getenv("EMXSHELL")) != NULL)
835 else if ((shell = getenv("SHELL")) != NULL)
837 else if ((shell = getenv("COMSPEC")) != NULL)
842 /* Consensus on perl5-porters is that it is _very_ important to
843 have a shell which will not change between computers with the
844 same architecture, to avoid "action on a distance".
845 And to have simple build, this shell should be sh. */
850 while (*cmd && isSPACE(*cmd))
853 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
854 STRLEN l = strlen(PL_sh_path);
856 New(1302, news, strlen(cmd) - 7 + l + 1, char);
857 strcpy(news, PL_sh_path);
858 strcpy(news + l, cmd + 7);
862 /* save an extra exec if possible */
863 /* see if there are shell metacharacters in it */
865 if (*cmd == '.' && isSPACE(cmd[1]))
868 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
871 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
875 for (s = cmd; *s; s++) {
876 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
877 if (*s == '\n' && s[1] == '\0') {
880 } else if (*s == '\\' && !seenspace) {
881 continue; /* Allow backslashes in names */
882 } else if (*s == '>' && s >= cmd + 3
883 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
884 && isSPACE(s[-2]) ) {
887 while (*t && isSPACE(*t))
892 break; /* Allow 2>&1 as the last thing */
895 /* We do not convert this to do_spawn_ve since shell
896 should be smart enough to start itself gloriously. */
898 if (execf == EXECF_TRUEEXEC)
899 rc = execl(shell,shell,copt,cmd,(char*)0);
900 else if (execf == EXECF_EXEC)
901 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
902 else if (execf == EXECF_SPAWN_NOWAIT)
903 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
904 else if (execf == EXECF_SPAWN_BYFLAG)
905 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
907 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
909 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
910 if (rc < 0 && ckWARN(WARN_EXEC))
911 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
912 (execf == EXECF_SPAWN ? "spawn" : "exec"),
913 shell, Strerror(errno));
920 } else if (*s == ' ' || *s == '\t') {
925 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
926 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
927 PL_Cmd = savepvn(cmd, s-cmd);
929 for (s = PL_Cmd; *s;) {
930 while (*s && isSPACE(*s)) s++;
933 while (*s && !isSPACE(*s)) s++;
939 rc = do_spawn_ve(NULL, flag, execf, cmd, mergestderr);
950 do_aspawn(really,mark,sp)
958 int flag = P_WAIT, flag_set = 0;
962 New(1301,PL_Argv, sp - mark + 3, char*);
965 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
972 while (++mark <= sp) {
974 *a++ = SvPVx(*mark, n_a);
980 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
981 rc = do_spawn3(a[-1], EXECF_SPAWN_BYFLAG, flag);
983 rc = do_spawn_ve(really, flag, EXECF_SPAWN, NULL, 0);
994 return do_spawn3(cmd, EXECF_SPAWN, 0);
1001 return do_spawn3(cmd, EXECF_SPAWN_NOWAIT,0);
1008 do_spawn3(cmd, EXECF_EXEC, 0);
1016 return do_spawn3(cmd, EXECF_TRUEEXEC, 0);
1020 my_syspopen(cmd,mode)
1027 register I32 this, that, newfd;
1028 register I32 pid, rc;
1033 /* `this' is what we use in the parent, `that' in the child. */
1034 this = (*mode == 'w');
1038 taint_proper("Insecure %s%s", "EXEC");
1042 /* Now we need to spawn the child. */
1043 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1044 int new = dup(p[this]);
1051 newfd = dup(*mode == 'r'); /* Preserve std* */
1053 /* This cannot happen due to fh being bad after pipe(), since
1054 pipe() should have created fh 0 and 1 even if they were
1055 initially closed. But we closed p[this] before. */
1056 if (errno != EBADF) {
1063 fh_fl = fcntl(*mode == 'r', F_GETFD);
1064 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1065 dup2(p[that], *mode == 'r');
1068 /* Where is `this' and newfd now? */
1069 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1071 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1072 pid = do_spawn_nowait(cmd);
1074 close(*mode == 'r'); /* It was closed initially */
1075 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1076 dup2(newfd, *mode == 'r'); /* Return std* back. */
1078 fcntl(*mode == 'r', F_SETFD, fh_fl);
1080 fcntl(*mode == 'r', F_SETFD, fh_fl);
1081 if (p[that] == (*mode == 'r'))
1087 if (p[that] < p[this]) { /* Make fh as small as possible */
1088 dup2(p[this], p[that]);
1092 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1093 (void)SvUPGRADE(sv,SVt_IV);
1095 PL_forkprocess = pid;
1096 return PerlIO_fdopen(p[this], mode);
1098 #else /* USE_POPEN */
1104 res = popen(cmd, mode);
1106 char *shell = getenv("EMXSHELL");
1108 my_setenv("EMXSHELL", PL_sh_path);
1109 res = popen(cmd, mode);
1110 my_setenv("EMXSHELL", shell);
1112 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1113 (void)SvUPGRADE(sv,SVt_IV);
1114 SvIVX(sv) = -1; /* A cooky. */
1117 #endif /* USE_POPEN */
1121 /******************************************************************/
1127 croak(PL_no_func, "Unsupported function fork");
1133 /*******************************************************************/
1134 /* not implemented in EMX 0.9a */
1136 void * ctermid(x) { return 0; }
1138 #ifdef MYTTYNAME /* was not in emx0.9a */
1139 void * ttyname(x) { return 0; }
1142 /******************************************************************/
1143 /* my socket forwarders - EMX lib only provides static forwarders */
1145 static HMODULE htcp = 0;
1150 static BYTE buf[20];
1153 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1155 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1156 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1157 return (void *) ((void * (*)(void)) fcn) ();
1162 tcp1(char *name, int arg)
1164 static BYTE buf[20];
1167 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1169 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1170 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1171 ((void (*)(int)) fcn) (arg);
1174 void * gethostent() { return tcp0("GETHOSTENT"); }
1175 void * getnetent() { return tcp0("GETNETENT"); }
1176 void * getprotoent() { return tcp0("GETPROTOENT"); }
1177 void * getservent() { return tcp0("GETSERVENT"); }
1178 void sethostent(x) { tcp1("SETHOSTENT", x); }
1179 void setnetent(x) { tcp1("SETNETENT", x); }
1180 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1181 void setservent(x) { tcp1("SETSERVENT", x); }
1182 void endhostent() { tcp0("ENDHOSTENT"); }
1183 void endnetent() { tcp0("ENDNETENT"); }
1184 void endprotoent() { tcp0("ENDPROTOENT"); }
1185 void endservent() { tcp0("ENDSERVENT"); }
1187 /*****************************************************************************/
1188 /* not implemented in C Set++ */
1191 int setuid(x) { errno = EINVAL; return -1; }
1192 int setgid(x) { errno = EINVAL; return -1; }
1195 /*****************************************************************************/
1196 /* stat() hack for char/block device */
1200 /* First attempt used DosQueryFSAttach which crashed the system when
1201 used with 5.001. Now just look for /dev/. */
1204 os2_stat(char *name, struct stat *st)
1206 static int ino = SHRT_MAX;
1208 if (stricmp(name, "/dev/con") != 0
1209 && stricmp(name, "/dev/tty") != 0)
1210 return stat(name, st);
1212 memset(st, 0, sizeof *st);
1213 st->st_mode = S_IFCHR|0666;
1214 st->st_ino = (ino-- & 0x7FFF);
1221 #ifdef USE_PERL_SBRK
1223 /* SBRK() emulation, mostly moved to malloc.c. */
1226 sys_alloc(int size) {
1228 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1230 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1233 croak("Got an error from DosAllocMem: %li", (long)rc);
1237 #endif /* USE_PERL_SBRK */
1241 char *tmppath = TMPPATH1;
1246 char *p = getenv("TMP"), *tpath;
1249 if (!p) p = getenv("TEMP");
1252 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1256 strcpy(tpath + len + 1, TMPPATH1);
1263 XS(XS_File__Copy_syscopy)
1266 if (items < 2 || items > 3)
1267 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
1270 char * src = (char *)SvPV(ST(0),n_a);
1271 char * dst = (char *)SvPV(ST(1),n_a);
1278 flag = (unsigned long)SvIV(ST(2));
1281 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1282 ST(0) = sv_newmortal();
1283 sv_setiv(ST(0), (IV)RETVAL);
1288 #include "patchlevel.h"
1294 static char fname[9];
1295 int pos = 6, len, avlen;
1296 unsigned int sum = 0;
1302 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
1304 if (SvTYPE(sv) != SVt_PVAV)
1305 croak("Not array reference given to mod2fname");
1307 avlen = av_len((AV*)sv);
1309 croak("Empty array reference given to mod2fname");
1311 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1312 strncpy(fname, s, 8);
1314 if (len < 6) pos = len;
1316 sum = 33 * sum + *(s++); /* Checksumming first chars to
1317 * get the capitalization into c.s. */
1320 while (avlen >= 0) {
1321 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1323 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1328 sum++; /* Avoid conflict of DLLs in memory. */
1330 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* */
1331 fname[pos] = 'A' + (sum % 26);
1332 fname[pos + 1] = 'A' + (sum / 26 % 26);
1333 fname[pos + 2] = '\0';
1334 return (char *)fname;
1337 XS(XS_DynaLoader_mod2fname)
1341 croak("Usage: DynaLoader::mod2fname(sv)");
1346 RETVAL = mod2fname(sv);
1347 ST(0) = sv_newmortal();
1348 sv_setpv((SV*)ST(0), RETVAL);
1356 static char buf[300];
1359 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1362 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
1363 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
1366 if (len && buf[len - 1] == '\n')
1368 if (len && buf[len - 1] == '\r')
1370 if (len && buf[len - 1] == '.')
1381 if (_execname(buf, sizeof buf) != 0)
1382 return PL_origargv[0];
1395 perllib_mangle(char *s, unsigned int l)
1397 static char *newp, *oldp;
1398 static int newl, oldl, notfound;
1399 static char ret[STATIC_FILE_LENGTH+1];
1401 if (!newp && !notfound) {
1402 newp = getenv("PERLLIB_PREFIX");
1407 while (*newp && !isSPACE(*newp) && *newp != ';') {
1408 newp++; oldl++; /* Skip digits. */
1410 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1411 newp++; /* Skip whitespace. */
1413 newl = strlen(newp);
1414 if (newl == 0 || oldl == 0) {
1415 croak("Malformed PERLLIB_PREFIX");
1420 if (*s == '\\') *s = '/';
1433 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1436 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1437 croak("Malformed PERLLIB_PREFIX");
1439 strcpy(ret + newl, s + oldl);
1444 Perl_hab_GET() /* Needed if perl.h cannot be included */
1446 return perl_hab_GET();
1450 Perl_Register_MQ(int serve)
1455 if (Perl_os2_initial_mode++)
1457 DosGetInfoBlocks(&tib, &pib);
1458 Perl_os2_initial_mode = pib->pib_ultype;
1459 Perl_hmq_refcnt = 1;
1460 /* Try morphing into a PM application. */
1461 if (pib->pib_ultype != 3) /* 2 is VIO */
1462 pib->pib_ultype = 3; /* 3 is PM */
1463 init_PMWIN_entries();
1464 /* 64 messages if before OS/2 3.0, ignored otherwise */
1465 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1469 _exit(188); /* Panic can try to create a window. */
1470 croak("Cannot create a message queue, or morph to a PM application");
1476 Perl_Serve_Messages(int force)
1481 if (Perl_hmq_servers && !force)
1483 if (!Perl_hmq_refcnt)
1484 croak("No message queue");
1485 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1487 if (msg.msg == WM_QUIT)
1488 croak("QUITing...");
1489 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1495 Perl_Process_Messages(int force, I32 *cntp)
1499 if (Perl_hmq_servers && !force)
1501 if (!Perl_hmq_refcnt)
1502 croak("No message queue");
1503 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1506 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1507 if (msg.msg == WM_DESTROY)
1509 if (msg.msg == WM_CREATE)
1512 croak("QUITing...");
1516 Perl_Deregister_MQ(int serve)
1521 if (--Perl_hmq_refcnt == 0) {
1522 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1524 /* Try morphing back from a PM application. */
1525 if (pib->pib_ultype == 3) /* 3 is PM */
1526 pib->pib_ultype = Perl_os2_initial_mode;
1528 warn("Unexpected program mode %d when morphing back from PM",
1533 extern void dlopen();
1534 void *fakedl = &dlopen; /* Pull in dynaloading part. */
1536 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1537 && ((path)[2] == '/' || (path)[2] == '\\'))
1538 #define sys_is_rooted _fnisabs
1539 #define sys_is_relative _fnisrel
1540 #define current_drive _getdrive
1542 #undef chdir /* Was _chdir2. */
1543 #define sys_chdir(p) (chdir(p) == 0)
1544 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1546 static int DOS_harderr_state = -1;
1552 croak("Usage: OS2::Error(harderr, exception)");
1554 int arg1 = SvIV(ST(0));
1555 int arg2 = SvIV(ST(1));
1556 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1557 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1558 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1561 if (CheckOSError(DosError(a)))
1562 croak("DosError(%d) failed", a);
1563 ST(0) = sv_newmortal();
1564 if (DOS_harderr_state >= 0)
1565 sv_setiv(ST(0), DOS_harderr_state);
1566 DOS_harderr_state = RETVAL;
1571 static signed char DOS_suppression_state = -1;
1573 XS(XS_OS2_Errors2Drive)
1577 croak("Usage: OS2::Errors2Drive(drive)");
1581 int suppress = SvOK(sv);
1582 char *s = suppress ? SvPV(sv, n_a) : NULL;
1583 char drive = (s ? *s : 0);
1586 if (suppress && !isALPHA(drive))
1587 croak("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1588 if (CheckOSError(DosSuppressPopUps((suppress
1589 ? SPU_ENABLESUPPRESSION
1590 : SPU_DISABLESUPPRESSION),
1592 croak("DosSuppressPopUps(%c) failed", drive);
1593 ST(0) = sv_newmortal();
1594 if (DOS_suppression_state > 0)
1595 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1596 else if (DOS_suppression_state == 0)
1597 sv_setpvn(ST(0), "", 0);
1598 DOS_suppression_state = drive;
1603 static const char * const si_fields[QSV_MAX] = {
1605 "MAX_TEXT_SESSIONS",
1609 "DYN_PRI_VARIATION",
1627 "FOREGROUND_FS_SESSION",
1628 "FOREGROUND_PROCESS"
1635 croak("Usage: OS2::SysInfo()");
1637 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1638 APIRET rc = NO_ERROR; /* Return code */
1641 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1642 QSV_MAX, /* information */
1645 croak("DosQuerySysInfo() failed");
1646 EXTEND(SP,2*QSV_MAX);
1647 while (i < QSV_MAX) {
1648 ST(j) = sv_newmortal();
1649 sv_setpv(ST(j++), si_fields[i]);
1650 ST(j) = sv_newmortal();
1651 sv_setiv(ST(j++), si[i]);
1655 XSRETURN(2 * QSV_MAX);
1658 XS(XS_OS2_BootDrive)
1662 croak("Usage: OS2::BootDrive()");
1664 ULONG si[1] = {0}; /* System Information Data Buffer */
1665 APIRET rc = NO_ERROR; /* Return code */
1668 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1669 (PVOID)si, sizeof(si))))
1670 croak("DosQuerySysInfo() failed");
1671 ST(0) = sv_newmortal();
1672 c = 'a' - 1 + si[0];
1673 sv_setpvn(ST(0), &c, 1);
1682 croak("Usage: OS2::MorphPM(serve)");
1684 bool serve = SvOK(ST(0));
1685 unsigned long pmq = perl_hmq_GET(serve);
1687 ST(0) = sv_newmortal();
1688 sv_setiv(ST(0), pmq);
1693 XS(XS_OS2_UnMorphPM)
1697 croak("Usage: OS2::UnMorphPM(serve)");
1699 bool serve = SvOK(ST(0));
1701 perl_hmq_UNSET(serve);
1706 XS(XS_OS2_Serve_Messages)
1710 croak("Usage: OS2::Serve_Messages(force)");
1712 bool force = SvOK(ST(0));
1713 unsigned long cnt = Perl_Serve_Messages(force);
1715 ST(0) = sv_newmortal();
1716 sv_setiv(ST(0), cnt);
1721 XS(XS_OS2_Process_Messages)
1724 if (items < 1 || items > 2)
1725 croak("Usage: OS2::Process_Messages(force [, cnt])");
1727 bool force = SvOK(ST(0));
1733 int fake = SvIV(sv); /* Force SvIVX */
1736 croak("Can't upgrade count to IV");
1739 cnt = Perl_Process_Messages(force, cntp);
1740 ST(0) = sv_newmortal();
1741 sv_setiv(ST(0), cnt);
1746 XS(XS_Cwd_current_drive)
1750 croak("Usage: Cwd::current_drive()");
1754 RETVAL = current_drive();
1755 ST(0) = sv_newmortal();
1756 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1761 XS(XS_Cwd_sys_chdir)
1765 croak("Usage: Cwd::sys_chdir(path)");
1768 char * path = (char *)SvPV(ST(0),n_a);
1771 RETVAL = sys_chdir(path);
1772 ST(0) = boolSV(RETVAL);
1773 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1778 XS(XS_Cwd_change_drive)
1782 croak("Usage: Cwd::change_drive(d)");
1785 char d = (char)*SvPV(ST(0),n_a);
1788 RETVAL = change_drive(d);
1789 ST(0) = boolSV(RETVAL);
1790 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1795 XS(XS_Cwd_sys_is_absolute)
1799 croak("Usage: Cwd::sys_is_absolute(path)");
1802 char * path = (char *)SvPV(ST(0),n_a);
1805 RETVAL = sys_is_absolute(path);
1806 ST(0) = boolSV(RETVAL);
1807 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1812 XS(XS_Cwd_sys_is_rooted)
1816 croak("Usage: Cwd::sys_is_rooted(path)");
1819 char * path = (char *)SvPV(ST(0),n_a);
1822 RETVAL = sys_is_rooted(path);
1823 ST(0) = boolSV(RETVAL);
1824 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1829 XS(XS_Cwd_sys_is_relative)
1833 croak("Usage: Cwd::sys_is_relative(path)");
1836 char * path = (char *)SvPV(ST(0),n_a);
1839 RETVAL = sys_is_relative(path);
1840 ST(0) = boolSV(RETVAL);
1841 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1850 croak("Usage: Cwd::sys_cwd()");
1854 RETVAL = _getcwd2(p, MAXPATHLEN);
1855 ST(0) = sv_newmortal();
1856 sv_setpv((SV*)ST(0), RETVAL);
1861 XS(XS_Cwd_sys_abspath)
1864 if (items < 1 || items > 2)
1865 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1868 char * path = (char *)SvPV(ST(0),n_a);
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) ) {
1926 if ( ( ( sys_is_absolute(dir)
1927 || (isALPHA(dir[0]) && dir[1] == ':'
1928 && strnicmp(dir, path,1) == 0))
1929 && strnicmp(dir, path,1) == 0)
1930 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1931 && toupper(path[0]) == current_drive())) {
1933 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1934 RETVAL = p; goto done;
1936 RETVAL = NULL; goto done;
1940 /* Need to prepend the absolute path of dir. */
1941 char p1[MAXPATHLEN];
1943 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1946 if (p1[ l - 1 ] != '/') {
1950 Copy(path, p1 + l, strlen(path) + 1, char);
1951 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1963 ST(0) = sv_newmortal();
1964 sv_setpv((SV*)ST(0), RETVAL);
1968 typedef APIRET (*PELP)(PSZ path, ULONG type);
1971 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1973 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
1974 return (*(PELP)ExtFCN[ord])(path, type);
1977 #define extLibpath(type) \
1978 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1979 : BEGIN_LIBPATH))) \
1982 #define extLibpath_set(p,type) \
1983 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1986 XS(XS_Cwd_extLibpath)
1989 if (items < 0 || items > 1)
1990 croak("Usage: Cwd::extLibpath(type = 0)");
2000 type = (int)SvIV(ST(0));
2003 RETVAL = extLibpath(type);
2004 ST(0) = sv_newmortal();
2005 sv_setpv((SV*)ST(0), RETVAL);
2010 XS(XS_Cwd_extLibpath_set)
2013 if (items < 1 || items > 2)
2014 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
2017 char * s = (char *)SvPV(ST(0),n_a);
2025 type = (int)SvIV(ST(1));
2028 RETVAL = extLibpath_set(s, type);
2029 ST(0) = boolSV(RETVAL);
2030 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2038 char *file = __FILE__;
2042 if (_emx_env & 0x200) { /* OS/2 */
2043 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2044 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2045 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2047 newXS("OS2::Error", XS_OS2_Error, file);
2048 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2049 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2050 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2051 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2052 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2053 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2054 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2055 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2056 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2057 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2058 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2059 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2060 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2061 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2062 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2063 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2064 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2067 sv_setiv(GvSV(gv), 1);
2069 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2071 sv_setiv(GvSV(gv), _emx_rev);
2072 sv_setpv(GvSV(gv), _emx_vprt);
2074 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2076 sv_setiv(GvSV(gv), _emx_env);
2077 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2079 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2083 OS2_Perl_data_t OS2_Perl_data;
2086 Perl_OS2_init(char **env)
2092 OS2_Perl_data.xs_init = &Xs_OS2_init;
2093 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2094 if (environ == NULL && env) {
2097 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2098 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2099 strcpy(PL_sh_path, SH_PATH);
2100 PL_sh_path[0] = shell[0];
2101 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2102 int l = strlen(shell), i;
2103 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2106 New(1304, PL_sh_path, l + 8, char);
2107 strncpy(PL_sh_path, shell, l);
2108 strcpy(PL_sh_path + l, "/sh.exe");
2109 for (i = 0; i < l; i++) {
2110 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2113 MUTEX_INIT(&start_thread_mutex);
2114 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2121 my_tmpnam (char *str)
2123 char *p = getenv("TMP"), *tpath;
2126 if (!p) p = getenv("TEMP");
2127 tpath = tempnam(p, "pltmp");
2141 if (s.st_mode & S_IWOTH) {
2144 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2150 /* This code was contributed by Rocco Caputo. */
2152 my_flock(int handle, int o)
2154 FILELOCK rNull, rFull;
2155 ULONG timeout, handle_type, flag_word;
2157 int blocking, shared;
2158 static int use_my = -1;
2161 char *s = getenv("USE_PERL_FLOCK");
2167 if (!(_emx_env & 0x200) || !use_my)
2168 return flock(handle, o); /* Delegate to EMX. */
2171 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2172 (handle_type & 0xFF))
2177 // set lock/unlock ranges
2178 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2179 rFull.lRange = 0x7FFFFFFF;
2180 // set timeout for blocking
2181 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2182 // shared or exclusive?
2183 shared = (o & LOCK_SH) ? 1 : 0;
2184 // do not block the unlock
2185 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2186 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2191 case ERROR_INVALID_HANDLE:
2194 case ERROR_SHARING_BUFFER_EXCEEDED:
2197 case ERROR_LOCK_VIOLATION:
2198 break; // not an error
2199 case ERROR_INVALID_PARAMETER:
2200 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2201 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2204 case ERROR_INTERRUPT:
2213 if (o & (LOCK_SH | LOCK_EX)) {
2214 // for blocking operations
2228 case ERROR_INVALID_HANDLE:
2231 case ERROR_SHARING_BUFFER_EXCEEDED:
2234 case ERROR_LOCK_VIOLATION:
2236 errno = EWOULDBLOCK;
2240 case ERROR_INVALID_PARAMETER:
2241 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2242 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2245 case ERROR_INTERRUPT:
2252 // give away timeslice