3 #define INCL_DOSFILEMGR
8 #include <sys/uflags.h>
11 * Various Unix compatibility functions for OS/2
25 typedef void (*emx_startroutine)(void *);
26 typedef void* (*pthreads_startroutine)(void *);
35 const char *pthreads_states[] = {
46 enum pthreads_state state;
49 thread_join_t *thread_join_data;
50 int thread_join_count;
51 perl_mutex start_thread_mutex;
54 pthread_join(perl_os_thread tid, void **status)
56 MUTEX_LOCK(&start_thread_mutex);
57 switch (thread_join_data[tid].state) {
58 case pthreads_st_exited:
59 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
60 MUTEX_UNLOCK(&start_thread_mutex);
61 *status = thread_join_data[tid].status;
63 case pthreads_st_waited:
64 MUTEX_UNLOCK(&start_thread_mutex);
65 croak("join with a thread with a waiter");
68 thread_join_data[tid].state = pthreads_st_waited;
69 COND_INIT(&thread_join_data[tid].cond);
70 MUTEX_UNLOCK(&start_thread_mutex);
71 COND_WAIT(&thread_join_data[tid].cond, NULL);
72 COND_DESTROY(&thread_join_data[tid].cond);
73 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
74 *status = thread_join_data[tid].status;
77 MUTEX_UNLOCK(&start_thread_mutex);
78 croak("join: unknown thread state: '%s'",
79 pthreads_states[thread_join_data[tid].state]);
86 pthread_startit(void *arg)
88 /* Thread is already started, we need to transfer control only */
89 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
90 int tid = pthread_self();
93 arg = ((void**)arg)[1];
94 if (tid >= thread_join_count) {
95 int oc = thread_join_count;
97 thread_join_count = tid + 5 + tid/5;
98 if (thread_join_data) {
99 Renew(thread_join_data, thread_join_count, thread_join_t);
100 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
102 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
105 if (thread_join_data[tid].state != pthreads_st_none)
106 croak("attempt to reuse thread id %i", tid);
107 thread_join_data[tid].state = pthreads_st_run;
108 /* Now that we copied/updated the guys, we may release the caller... */
109 MUTEX_UNLOCK(&start_thread_mutex);
110 thread_join_data[tid].status = (*start_routine)(arg);
111 switch (thread_join_data[tid].state) {
112 case pthreads_st_waited:
113 COND_SIGNAL(&thread_join_data[tid].cond);
116 thread_join_data[tid].state = pthreads_st_exited;
122 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
123 void *(*start_routine)(void*), void *arg)
127 args[0] = (void*)start_routine;
130 MUTEX_LOCK(&start_thread_mutex);
131 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
132 /*stacksize*/ 10*1024*1024, (void*)args);
133 MUTEX_LOCK(&start_thread_mutex);
134 MUTEX_UNLOCK(&start_thread_mutex);
135 return *tid ? 0 : EINVAL;
139 pthread_detach(perl_os_thread tid)
141 MUTEX_LOCK(&start_thread_mutex);
142 switch (thread_join_data[tid].state) {
143 case pthreads_st_waited:
144 MUTEX_UNLOCK(&start_thread_mutex);
145 croak("detach on a thread with a waiter");
147 case pthreads_st_run:
148 thread_join_data[tid].state = pthreads_st_detached;
149 MUTEX_UNLOCK(&start_thread_mutex);
152 MUTEX_UNLOCK(&start_thread_mutex);
153 croak("detach: unknown thread state: '%s'",
154 pthreads_states[thread_join_data[tid].state]);
160 /* This is a very bastardized version: */
162 os2_cond_wait(perl_cond *c, perl_mutex *m)
166 if ((rc = DosResetEventSem(*c,&n_a)) && (rc != ERROR_ALREADY_RESET))
167 croak("panic: COND_WAIT-reset: rc=%i", rc);
168 if (m) MUTEX_UNLOCK(m);
169 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
170 && (rc != ERROR_INTERRUPT))
171 croak("panic: COND_WAIT: rc=%i", rc);
172 if (rc == ERROR_INTERRUPT)
174 if (m) MUTEX_LOCK(m);
178 /*****************************************************************************/
179 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
180 static PFN ExtFCN[2]; /* Labeled by ord below. */
181 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
182 #define ORD_QUERY_ELP 0
183 #define ORD_SET_ELP 1
184 struct PMWIN_entries_t PMWIN_entries;
187 loadByOrd(char *modname, ULONG ord)
189 if (ExtFCN[ord] == NULL) {
190 static HMODULE hdosc = 0;
195 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
197 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
198 croak("This version of OS/2 does not support %s.%i",
199 modname, loadOrd[ord]);
202 if ((long)ExtFCN[ord] == -1)
203 croak("panic queryaddr");
207 init_PMWIN_entries(void)
209 static HMODULE hpmwin = 0;
210 static const int ords[] = {
211 763, /* Initialize */
212 716, /* CreateMsgQueue */
213 726, /* DestroyMsgQueue */
216 912, /* DispatchMsg */
225 if (CheckOSError(DosLoadModule(buf, sizeof buf, "pmwin", &hpmwin)))
226 croak("This version of OS/2 does not support pmwin: error in %s", buf);
228 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
229 ((PFN*)&PMWIN_entries)+i)))
230 croak("This version of OS/2 does not support pmwin.%d", ords[i]);
237 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
239 #define QSS_INI_BUFFER 1024
242 get_sysinfo(ULONG pid, ULONG flags)
245 ULONG rc, buf_len = QSS_INI_BUFFER;
247 New(1322, pbuffer, buf_len, char);
248 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
249 rc = QuerySysState(flags, pid, pbuffer, buf_len);
250 while (rc == ERROR_BUFFER_OVERFLOW) {
251 Renew(pbuffer, buf_len *= 2, char);
252 rc = QuerySysState(flags, pid, pbuffer, buf_len);
259 return (PQTOPLEVEL)pbuffer;
262 #define PRIO_ERR 0x1111
270 psi = get_sysinfo(pid, QSS_PROCESS);
274 if (pid != psi->procdata->pid) {
276 croak("panic: wrong pid in sysinfo");
278 prio = psi->procdata->threads->priority;
284 setpriority(int which, int pid, int val)
289 prio = sys_prio(pid);
291 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
292 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
293 /* Do not change class. */
294 return CheckOSError(DosSetPriority((pid < 0)
295 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
297 (32 - val) % 32 - (prio & 0xFF),
300 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
301 /* Documentation claims one can change both class and basevalue,
302 * but I find it wrong. */
303 /* Change class, but since delta == 0 denotes absolute 0, correct. */
304 if (CheckOSError(DosSetPriority((pid < 0)
305 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
306 priors[(32 - val) >> 5] + 1,
310 if ( ((32 - val) % 32) == 0 ) return 0;
311 return CheckOSError(DosSetPriority((pid < 0)
312 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
318 /* else return CheckOSError(DosSetPriority((pid < 0) */
319 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
320 /* priors[(32 - val) >> 5] + 1, */
321 /* (32 - val) % 32 - (prio & 0xFF), */
327 getpriority(int which /* ignored */, int pid)
333 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
334 /* DosGetInfoBlocks has old priority! */
335 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
336 /* if (pid != pib->pib_ulpid) { */
338 if (ret == PRIO_ERR) {
342 /* ret = tib->tib_ptib2->tib2_ulpri; */
343 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
346 /*****************************************************************************/
349 /* There is no big sense to make it thread-specific, since signals
350 are delivered to thread 1 only. XXXX Maybe make it into an array? */
351 static int spawn_pid;
352 static int spawn_killed;
355 spawn_sighandler(int sig)
357 /* Some programs do not arrange for the keyboard signals to be
358 delivered to them. We need to deliver the signal manually. */
359 /* We may get a signal only if
360 a) kid does not receive keyboard signal: deliver it;
361 b) kid already died, and we get a signal. We may only hope
362 that the pid number was not reused.
366 sig = SIGKILL; /* Try harder. */
367 kill(spawn_pid, sig);
372 result(int flag, int pid)
375 Signal_t (*ihand)(); /* place to save signal during system() */
376 Signal_t (*qhand)(); /* place to save signal during system() */
382 if (pid < 0 || flag != 0)
388 ihand = rsignal(SIGINT, &spawn_sighandler);
389 qhand = rsignal(SIGQUIT, &spawn_sighandler);
391 r = wait4pid(pid, &status, 0);
392 } while (r == -1 && errno == EINTR);
393 rsignal(SIGINT, ihand);
394 rsignal(SIGQUIT, qhand);
396 PL_statusvalue = (U16)status;
399 return status & 0xFFFF;
401 ihand = rsignal(SIGINT, SIG_IGN);
402 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
403 rsignal(SIGINT, ihand);
404 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
407 return PL_statusvalue;
411 #define EXECF_SPAWN 0
413 #define EXECF_TRUEEXEC 2
414 #define EXECF_SPAWN_NOWAIT 3
415 #define EXECF_SPAWN_BYFLAG 4
417 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
426 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
427 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
430 return (pib->pib_ultype);
434 file_type(char *path)
439 if (!(_emx_env & 0x200))
440 croak("file_type not implemented on DOS"); /* not OS/2. */
441 if (CheckOSError(DosQueryAppType(path, &apptype))) {
443 case ERROR_FILE_NOT_FOUND:
444 case ERROR_PATH_NOT_FOUND:
446 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
448 default: /* Found, but not an
449 executable, or some other
457 static ULONG os2_mytype;
459 /* Spawn/exec a program, revert to shell if needed. */
460 /* global PL_Argv[] contains arguments. */
463 do_spawn_ve(really, flag, execf, inicmd, addflag)
474 char buf[256], *s = 0, scrbuf[280];
476 static char * fargs[4]
477 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
478 char **argsp = fargs;
481 int new_stderr = -1, nostderr = 0, fl_stderr;
488 if (strEQ(PL_Argv[0],"/bin/sh"))
489 PL_Argv[0] = PL_sh_path;
491 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
492 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
493 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
494 ) /* will spawnvp use PATH? */
495 TAINT_ENV(); /* testing IFS here is overkill, probably */
496 /* We should check PERL_SH* and PERLLIB_* as well? */
497 if (!really || !*(tmps = SvPV(really, n_a)))
502 if (_emx_env & 0x200) { /* OS/2. */
503 int type = file_type(tmps);
505 if (type == -1) { /* Not found */
510 else if (type == -2) { /* Not an EXE */
515 else if (type == -3) { /* Is a directory? */
516 /* Special-case this */
518 int l = strlen(tmps);
520 if (l + 5 <= sizeof tbuf) {
522 strcpy(tbuf + l, ".exe");
523 type = file_type(tbuf);
533 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
534 case FAPPTYP_WINDOWAPI:
536 if (os2_mytype != 3) { /* not PM */
537 if (flag == P_NOWAIT)
539 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
540 warn("Starting PM process with flag=%d, mytype=%d",
545 case FAPPTYP_NOTWINDOWCOMPAT:
547 if (os2_mytype != 0) { /* not full screen */
548 if (flag == P_NOWAIT)
550 else if ((flag & 7) != P_SESSION)
551 warn("Starting Full Screen process with flag=%d, mytype=%d",
556 case FAPPTYP_NOTSPEC:
557 /* Let the shell handle this... */
566 new_stderr = dup(2); /* Preserve stderr */
567 if (new_stderr == -1) {
575 fl_stderr = fcntl(2, F_GETFD);
579 fcntl(new_stderr, F_SETFD, FD_CLOEXEC);
583 rc = result(trueflag, spawnvp(flag,tmps,PL_Argv));
585 if (execf == EXECF_TRUEEXEC)
586 rc = execvp(tmps,PL_Argv);
587 else if (execf == EXECF_EXEC)
588 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
589 else if (execf == EXECF_SPAWN_NOWAIT)
590 rc = spawnvp(flag,tmps,PL_Argv);
591 else /* EXECF_SPAWN, EXECF_SPAWN_BYFLAG */
592 rc = result(trueflag,
593 spawnvp(flag,tmps,PL_Argv));
595 if (rc < 0 && pass == 1
596 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
601 if (err == ENOENT || err == ENOEXEC) {
602 /* No such file, or is a script. */
603 /* Try adding script extensions to the file name, and
605 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
614 if (l >= sizeof scrbuf) {
617 warn("Size of scriptname too big: %d", l);
625 file = fopen(scr, "r");
629 if (!fgets(buf, sizeof buf, file)) { /* Empty... */
633 /* Special case: maybe from -Zexe build, so
634 there is an executable around (contrary to
635 documentation, DosQueryAppType sometimes (?)
636 does not append ".exe", so we could have
637 reached this place). */
638 if (l + 5 < sizeof scrbuf) {
639 strcpy(scrbuf + l, ".exe");
640 if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0
641 && !S_ISDIR(PL_statbuf.st_mode)) {
651 if (fclose(file) != 0) { /* Failure */
653 warn("Error reading \"%s\": %s",
654 scr, Strerror(errno));
655 buf[0] = 0; /* Not #! */
661 } else if (buf[0] == 'e') {
662 if (strnEQ(buf, "extproc", 7)
665 } else if (buf[0] == 'E') {
666 if (strnEQ(buf, "EXTPROC", 7)
671 buf[0] = 0; /* Not #! */
679 /* Do better than pdksh: allow a few args,
680 strip trailing whitespace. */
690 while (*s && !isSPACE(*s))
697 warn("Too many args on %.*s line of \"%s\"",
708 || (!buf[0] && file)) { /* File without magic */
709 /* In fact we tried all what pdksh would
710 try. There is no point in calling
711 pdksh, we may just emulate its logic. */
712 char *shell = getenv("EXECSHELL");
713 char *shell_opt = NULL;
719 shell = getenv("OS2_SHELL");
720 if (inicmd) { /* No spaces at start! */
722 while (*s && !isSPACE(*s)) {
724 inicmd = NULL; /* Cannot use */
732 /* Dosish shells will choke on slashes
733 in paths, fortunately, this is
734 important for zeroth arg only. */
741 /* If EXECSHELL is set, we do not set */
744 shell = ((_emx_env & 0x200)
747 nargs = shell_opt ? 2 : 1; /* shell file args */
748 exec_args[0] = shell;
749 exec_args[1] = shell_opt;
751 if (nargs == 2 && inicmd) {
752 /* Use the original cmd line */
753 /* XXXX This is good only until we refuse
754 quoted arguments... */
758 } else if (!buf[0] && inicmd) { /* No file */
759 /* Start with the original cmdline. */
760 /* XXXX This is good only until we refuse
761 quoted arguments... */
765 nargs = 2; /* shell -c */
768 while (a[1]) /* Get to the end */
770 a++; /* Copy finil NULL too */
771 while (a >= PL_Argv) {
772 *(a + nargs) = *a; /* PL_Argv was preallocated to be
777 PL_Argv[nargs] = argsp[nargs];
778 /* Enable pathless exec if #! (as pdksh). */
779 pass = (buf[0] == '#' ? 2 : 3);
783 /* Not found: restore errno */
787 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
788 char *no_dir = strrchr(PL_Argv[0], '/');
790 /* Do as pdksh port does: if not found with /, try without
793 PL_Argv[0] = no_dir + 1;
798 if (rc < 0 && ckWARN(WARN_EXEC))
799 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s\n",
800 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
802 PL_Argv[0], Strerror(errno));
803 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
804 && ((trueflag & 0xFF) == P_WAIT))
805 rc = 255 << 8; /* Emulate the fork(). */
808 if (new_stderr != -1) { /* How can we use error codes? */
811 fcntl(2, F_SETFD, fl_stderr);
817 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
819 do_spawn3(char *cmd, int execf, int flag)
824 char *shell, *copt, *news = NULL;
825 int rc, err, seenspace = 0, mergestderr = 0;
826 char fullcmd[MAXNAMLEN + 1];
829 if ((shell = getenv("EMXSHELL")) != NULL)
831 else if ((shell = getenv("SHELL")) != NULL)
833 else if ((shell = getenv("COMSPEC")) != NULL)
838 /* Consensus on perl5-porters is that it is _very_ important to
839 have a shell which will not change between computers with the
840 same architecture, to avoid "action on a distance".
841 And to have simple build, this shell should be sh. */
846 while (*cmd && isSPACE(*cmd))
849 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
850 STRLEN l = strlen(PL_sh_path);
852 New(1302, news, strlen(cmd) - 7 + l + 1, char);
853 strcpy(news, PL_sh_path);
854 strcpy(news + l, cmd + 7);
858 /* save an extra exec if possible */
859 /* see if there are shell metacharacters in it */
861 if (*cmd == '.' && isSPACE(cmd[1]))
864 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
867 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
871 for (s = cmd; *s; s++) {
872 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
873 if (*s == '\n' && s[1] == '\0') {
876 } else if (*s == '\\' && !seenspace) {
877 continue; /* Allow backslashes in names */
878 } else if (*s == '>' && s >= cmd + 3
879 && s[-1] == '2' && s[1] == '&' && s[2] == '1'
880 && isSPACE(s[-2]) ) {
883 while (*t && isSPACE(*t))
888 break; /* Allow 2>&1 as the last thing */
891 /* We do not convert this to do_spawn_ve since shell
892 should be smart enough to start itself gloriously. */
894 if (execf == EXECF_TRUEEXEC)
895 rc = execl(shell,shell,copt,cmd,(char*)0);
896 else if (execf == EXECF_EXEC)
897 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
898 else if (execf == EXECF_SPAWN_NOWAIT)
899 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
900 else if (execf == EXECF_SPAWN_BYFLAG)
901 rc = spawnl(flag,shell,shell,copt,cmd,(char*)0);
903 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
905 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
906 if (rc < 0 && ckWARN(WARN_EXEC))
907 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
908 (execf == EXECF_SPAWN ? "spawn" : "exec"),
909 shell, Strerror(errno));
910 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
915 } else if (*s == ' ' || *s == '\t') {
920 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
921 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
922 PL_Cmd = savepvn(cmd, s-cmd);
924 for (s = PL_Cmd; *s;) {
925 while (*s && isSPACE(*s)) s++;
928 while (*s && !isSPACE(*s)) s++;
934 rc = do_spawn_ve(NULL, flag, execf, cmd, mergestderr);
945 do_aspawn(really,mark,sp)
953 int flag = P_WAIT, flag_set = 0;
957 New(1301,PL_Argv, sp - mark + 3, char*);
960 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
967 while (++mark <= sp) {
969 *a++ = SvPVx(*mark, n_a);
975 if (flag_set && (a == PL_Argv + 1)) { /* One arg? */
976 rc = do_spawn3(a[-1], EXECF_SPAWN_BYFLAG, flag);
978 rc = do_spawn_ve(really, flag, EXECF_SPAWN, NULL, 0);
989 return do_spawn3(cmd, EXECF_SPAWN, 0);
996 return do_spawn3(cmd, EXECF_SPAWN_NOWAIT,0);
1003 do_spawn3(cmd, EXECF_EXEC, 0);
1011 return do_spawn3(cmd, EXECF_TRUEEXEC, 0);
1015 my_syspopen(cmd,mode)
1022 register I32 this, that, newfd;
1023 register I32 pid, rc;
1028 /* `this' is what we use in the parent, `that' in the child. */
1029 this = (*mode == 'w');
1033 taint_proper("Insecure %s%s", "EXEC");
1037 /* Now we need to spawn the child. */
1038 if (p[this] == (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1039 int new = dup(p[this]);
1046 newfd = dup(*mode == 'r'); /* Preserve std* */
1048 /* This cannot happen due to fh being bad after pipe(), since
1049 pipe() should have created fh 0 and 1 even if they were
1050 initially closed. But we closed p[this] before. */
1051 if (errno != EBADF) {
1058 fh_fl = fcntl(*mode == 'r', F_GETFD);
1059 if (p[that] != (*mode == 'r')) { /* if fh 0/1 was initially closed. */
1060 dup2(p[that], *mode == 'r');
1063 /* Where is `this' and newfd now? */
1064 fcntl(p[this], F_SETFD, FD_CLOEXEC);
1066 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1067 pid = do_spawn_nowait(cmd);
1069 close(*mode == 'r'); /* It was closed initially */
1070 else if (newfd != (*mode == 'r')) { /* Probably this check is not needed */
1071 dup2(newfd, *mode == 'r'); /* Return std* back. */
1073 fcntl(*mode == 'r', F_SETFD, fh_fl);
1075 fcntl(*mode == 'r', F_SETFD, fh_fl);
1076 if (p[that] == (*mode == 'r'))
1082 if (p[that] < p[this]) { /* Make fh as small as possible */
1083 dup2(p[this], p[that]);
1087 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1088 (void)SvUPGRADE(sv,SVt_IV);
1090 PL_forkprocess = pid;
1091 return PerlIO_fdopen(p[this], mode);
1093 #else /* USE_POPEN */
1099 res = popen(cmd, mode);
1101 char *shell = getenv("EMXSHELL");
1103 my_setenv("EMXSHELL", PL_sh_path);
1104 res = popen(cmd, mode);
1105 my_setenv("EMXSHELL", shell);
1107 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1108 (void)SvUPGRADE(sv,SVt_IV);
1109 SvIVX(sv) = -1; /* A cooky. */
1112 #endif /* USE_POPEN */
1116 /******************************************************************/
1122 croak(PL_no_func, "Unsupported function fork");
1128 /*******************************************************************/
1129 /* not implemented in EMX 0.9a */
1131 void * ctermid(x) { return 0; }
1133 #ifdef MYTTYNAME /* was not in emx0.9a */
1134 void * ttyname(x) { return 0; }
1137 /******************************************************************/
1138 /* my socket forwarders - EMX lib only provides static forwarders */
1140 static HMODULE htcp = 0;
1145 static BYTE buf[20];
1148 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1150 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1151 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1152 return (void *) ((void * (*)(void)) fcn) ();
1157 tcp1(char *name, int arg)
1159 static BYTE buf[20];
1162 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1164 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1165 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1166 ((void (*)(int)) fcn) (arg);
1169 void * gethostent() { return tcp0("GETHOSTENT"); }
1170 void * getnetent() { return tcp0("GETNETENT"); }
1171 void * getprotoent() { return tcp0("GETPROTOENT"); }
1172 void * getservent() { return tcp0("GETSERVENT"); }
1173 void sethostent(x) { tcp1("SETHOSTENT", x); }
1174 void setnetent(x) { tcp1("SETNETENT", x); }
1175 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1176 void setservent(x) { tcp1("SETSERVENT", x); }
1177 void endhostent() { tcp0("ENDHOSTENT"); }
1178 void endnetent() { tcp0("ENDNETENT"); }
1179 void endprotoent() { tcp0("ENDPROTOENT"); }
1180 void endservent() { tcp0("ENDSERVENT"); }
1182 /*****************************************************************************/
1183 /* not implemented in C Set++ */
1186 int setuid(x) { errno = EINVAL; return -1; }
1187 int setgid(x) { errno = EINVAL; return -1; }
1190 /*****************************************************************************/
1191 /* stat() hack for char/block device */
1195 /* First attempt used DosQueryFSAttach which crashed the system when
1196 used with 5.001. Now just look for /dev/. */
1199 os2_stat(char *name, struct stat *st)
1201 static int ino = SHRT_MAX;
1203 if (stricmp(name, "/dev/con") != 0
1204 && stricmp(name, "/dev/tty") != 0)
1205 return stat(name, st);
1207 memset(st, 0, sizeof *st);
1208 st->st_mode = S_IFCHR|0666;
1209 st->st_ino = (ino-- & 0x7FFF);
1216 #ifdef USE_PERL_SBRK
1218 /* SBRK() emulation, mostly moved to malloc.c. */
1221 sys_alloc(int size) {
1223 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1225 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1228 croak("Got an error from DosAllocMem: %li", (long)rc);
1232 #endif /* USE_PERL_SBRK */
1236 char *tmppath = TMPPATH1;
1241 char *p = getenv("TMP"), *tpath;
1244 if (!p) p = getenv("TEMP");
1247 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1251 strcpy(tpath + len + 1, TMPPATH1);
1258 XS(XS_File__Copy_syscopy)
1261 if (items < 2 || items > 3)
1262 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
1265 char * src = (char *)SvPV(ST(0),n_a);
1266 char * dst = (char *)SvPV(ST(1),n_a);
1273 flag = (unsigned long)SvIV(ST(2));
1276 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1277 ST(0) = sv_newmortal();
1278 sv_setiv(ST(0), (IV)RETVAL);
1283 #include "patchlevel.h"
1289 static char fname[9];
1290 int pos = 6, len, avlen;
1291 unsigned int sum = 0;
1297 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
1299 if (SvTYPE(sv) != SVt_PVAV)
1300 croak("Not array reference given to mod2fname");
1302 avlen = av_len((AV*)sv);
1304 croak("Empty array reference given to mod2fname");
1306 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1307 strncpy(fname, s, 8);
1309 if (len < 6) pos = len;
1311 sum = 33 * sum + *(s++); /* Checksumming first chars to
1312 * get the capitalization into c.s. */
1315 while (avlen >= 0) {
1316 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), n_a);
1318 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1323 sum++; /* Avoid conflict of DLLs in memory. */
1325 sum += PERL_VERSION * 200 + PERL_SUBVERSION * 2; /* */
1326 fname[pos] = 'A' + (sum % 26);
1327 fname[pos + 1] = 'A' + (sum / 26 % 26);
1328 fname[pos + 2] = '\0';
1329 return (char *)fname;
1332 XS(XS_DynaLoader_mod2fname)
1336 croak("Usage: DynaLoader::mod2fname(sv)");
1341 RETVAL = mod2fname(sv);
1342 ST(0) = sv_newmortal();
1343 sv_setpv((SV*)ST(0), RETVAL);
1351 static char buf[300];
1354 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1357 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
1358 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
1361 if (len > 0 && buf[len - 1] == '\n')
1362 buf[len - 1] = '\0';
1363 if (len > 1 && buf[len - 2] == '\r')
1364 buf[len - 2] = '\0';
1365 if (len > 2 && buf[len - 3] == '.')
1366 buf[len - 3] = '\0';
1371 perllib_mangle(char *s, unsigned int l)
1373 static char *newp, *oldp;
1374 static int newl, oldl, notfound;
1375 static char ret[STATIC_FILE_LENGTH+1];
1377 if (!newp && !notfound) {
1378 newp = getenv("PERLLIB_PREFIX");
1383 while (*newp && !isSPACE(*newp) && *newp != ';') {
1384 newp++; oldl++; /* Skip digits. */
1386 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1387 newp++; /* Skip whitespace. */
1389 newl = strlen(newp);
1390 if (newl == 0 || oldl == 0) {
1391 croak("Malformed PERLLIB_PREFIX");
1396 if (*s == '\\') *s = '/';
1409 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1412 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1413 croak("Malformed PERLLIB_PREFIX");
1415 strcpy(ret + newl, s + oldl);
1420 Perl_hab_GET() /* Needed if perl.h cannot be included */
1422 return perl_hab_GET();
1426 Perl_Register_MQ(int serve)
1431 if (Perl_os2_initial_mode++)
1433 DosGetInfoBlocks(&tib, &pib);
1434 Perl_os2_initial_mode = pib->pib_ultype;
1435 Perl_hmq_refcnt = 1;
1436 /* Try morphing into a PM application. */
1437 if (pib->pib_ultype != 3) /* 2 is VIO */
1438 pib->pib_ultype = 3; /* 3 is PM */
1439 init_PMWIN_entries();
1440 /* 64 messages if before OS/2 3.0, ignored otherwise */
1441 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1445 _exit(188); /* Panic can try to create a window. */
1446 croak("Cannot create a message queue, or morph to a PM application");
1452 Perl_Serve_Messages(int force)
1457 if (Perl_hmq_servers && !force)
1459 if (!Perl_hmq_refcnt)
1460 croak("No message queue");
1461 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1463 if (msg.msg == WM_QUIT)
1464 croak("QUITing...");
1465 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1471 Perl_Process_Messages(int force, I32 *cntp)
1475 if (Perl_hmq_servers && !force)
1477 if (!Perl_hmq_refcnt)
1478 croak("No message queue");
1479 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1482 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1483 if (msg.msg == WM_DESTROY)
1485 if (msg.msg == WM_CREATE)
1488 croak("QUITing...");
1492 Perl_Deregister_MQ(int serve)
1497 if (--Perl_hmq_refcnt == 0) {
1498 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1500 /* Try morphing back from a PM application. */
1501 if (pib->pib_ultype == 3) /* 3 is PM */
1502 pib->pib_ultype = Perl_os2_initial_mode;
1504 warn("Unexpected program mode %d when morphing back from PM",
1509 extern void dlopen();
1510 void *fakedl = &dlopen; /* Pull in dynaloading part. */
1512 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1513 && ((path)[2] == '/' || (path)[2] == '\\'))
1514 #define sys_is_rooted _fnisabs
1515 #define sys_is_relative _fnisrel
1516 #define current_drive _getdrive
1518 #undef chdir /* Was _chdir2. */
1519 #define sys_chdir(p) (chdir(p) == 0)
1520 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1522 static int DOS_harderr_state = -1;
1528 croak("Usage: OS2::Error(harderr, exception)");
1530 int arg1 = SvIV(ST(0));
1531 int arg2 = SvIV(ST(1));
1532 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1533 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1534 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1537 if (CheckOSError(DosError(a)))
1538 croak("DosError(%d) failed", a);
1539 ST(0) = sv_newmortal();
1540 if (DOS_harderr_state >= 0)
1541 sv_setiv(ST(0), DOS_harderr_state);
1542 DOS_harderr_state = RETVAL;
1547 static signed char DOS_suppression_state = -1;
1549 XS(XS_OS2_Errors2Drive)
1553 croak("Usage: OS2::Errors2Drive(drive)");
1557 int suppress = SvOK(sv);
1558 char *s = suppress ? SvPV(sv, n_a) : NULL;
1559 char drive = (s ? *s : 0);
1562 if (suppress && !isALPHA(drive))
1563 croak("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1564 if (CheckOSError(DosSuppressPopUps((suppress
1565 ? SPU_ENABLESUPPRESSION
1566 : SPU_DISABLESUPPRESSION),
1568 croak("DosSuppressPopUps(%c) failed", drive);
1569 ST(0) = sv_newmortal();
1570 if (DOS_suppression_state > 0)
1571 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1572 else if (DOS_suppression_state == 0)
1573 sv_setpvn(ST(0), "", 0);
1574 DOS_suppression_state = drive;
1579 static const char * const si_fields[QSV_MAX] = {
1581 "MAX_TEXT_SESSIONS",
1585 "DYN_PRI_VARIATION",
1603 "FOREGROUND_FS_SESSION",
1604 "FOREGROUND_PROCESS"
1611 croak("Usage: OS2::SysInfo()");
1613 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1614 APIRET rc = NO_ERROR; /* Return code */
1617 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1618 QSV_MAX, /* information */
1621 croak("DosQuerySysInfo() failed");
1622 EXTEND(SP,2*QSV_MAX);
1623 while (i < QSV_MAX) {
1624 ST(j) = sv_newmortal();
1625 sv_setpv(ST(j++), si_fields[i]);
1626 ST(j) = sv_newmortal();
1627 sv_setiv(ST(j++), si[i]);
1631 XSRETURN(2 * QSV_MAX);
1634 XS(XS_OS2_BootDrive)
1638 croak("Usage: OS2::BootDrive()");
1640 ULONG si[1] = {0}; /* System Information Data Buffer */
1641 APIRET rc = NO_ERROR; /* Return code */
1644 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1645 (PVOID)si, sizeof(si))))
1646 croak("DosQuerySysInfo() failed");
1647 ST(0) = sv_newmortal();
1648 c = 'a' - 1 + si[0];
1649 sv_setpvn(ST(0), &c, 1);
1658 croak("Usage: OS2::MorphPM(serve)");
1660 bool serve = SvOK(ST(0));
1661 unsigned long pmq = perl_hmq_GET(serve);
1663 ST(0) = sv_newmortal();
1664 sv_setiv(ST(0), pmq);
1669 XS(XS_OS2_UnMorphPM)
1673 croak("Usage: OS2::UnMorphPM(serve)");
1675 bool serve = SvOK(ST(0));
1677 perl_hmq_UNSET(serve);
1682 XS(XS_OS2_Serve_Messages)
1686 croak("Usage: OS2::Serve_Messages(force)");
1688 bool force = SvOK(ST(0));
1689 unsigned long cnt = Perl_Serve_Messages(force);
1691 ST(0) = sv_newmortal();
1692 sv_setiv(ST(0), cnt);
1697 XS(XS_OS2_Process_Messages)
1700 if (items < 1 || items > 2)
1701 croak("Usage: OS2::Process_Messages(force [, cnt])");
1703 bool force = SvOK(ST(0));
1709 int fake = SvIV(sv); /* Force SvIVX */
1712 croak("Can't upgrade count to IV");
1715 cnt = Perl_Process_Messages(force, cntp);
1716 ST(0) = sv_newmortal();
1717 sv_setiv(ST(0), cnt);
1722 XS(XS_Cwd_current_drive)
1726 croak("Usage: Cwd::current_drive()");
1730 RETVAL = current_drive();
1731 ST(0) = sv_newmortal();
1732 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1737 XS(XS_Cwd_sys_chdir)
1741 croak("Usage: Cwd::sys_chdir(path)");
1744 char * path = (char *)SvPV(ST(0),n_a);
1747 RETVAL = sys_chdir(path);
1748 ST(0) = boolSV(RETVAL);
1749 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1754 XS(XS_Cwd_change_drive)
1758 croak("Usage: Cwd::change_drive(d)");
1761 char d = (char)*SvPV(ST(0),n_a);
1764 RETVAL = change_drive(d);
1765 ST(0) = boolSV(RETVAL);
1766 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1771 XS(XS_Cwd_sys_is_absolute)
1775 croak("Usage: Cwd::sys_is_absolute(path)");
1778 char * path = (char *)SvPV(ST(0),n_a);
1781 RETVAL = sys_is_absolute(path);
1782 ST(0) = boolSV(RETVAL);
1783 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1788 XS(XS_Cwd_sys_is_rooted)
1792 croak("Usage: Cwd::sys_is_rooted(path)");
1795 char * path = (char *)SvPV(ST(0),n_a);
1798 RETVAL = sys_is_rooted(path);
1799 ST(0) = boolSV(RETVAL);
1800 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1805 XS(XS_Cwd_sys_is_relative)
1809 croak("Usage: Cwd::sys_is_relative(path)");
1812 char * path = (char *)SvPV(ST(0),n_a);
1815 RETVAL = sys_is_relative(path);
1816 ST(0) = boolSV(RETVAL);
1817 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1826 croak("Usage: Cwd::sys_cwd()");
1830 RETVAL = _getcwd2(p, MAXPATHLEN);
1831 ST(0) = sv_newmortal();
1832 sv_setpv((SV*)ST(0), RETVAL);
1837 XS(XS_Cwd_sys_abspath)
1840 if (items < 1 || items > 2)
1841 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1844 char * path = (char *)SvPV(ST(0),n_a);
1852 dir = (char *)SvPV(ST(1),n_a);
1854 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1858 if (_abspath(p, path, MAXPATHLEN) == 0) {
1864 /* Absolute with drive: */
1865 if ( sys_is_absolute(path) ) {
1866 if (_abspath(p, path, MAXPATHLEN) == 0) {
1871 } else if (path[0] == '/' || path[0] == '\\') {
1872 /* Rooted, but maybe on different drive. */
1873 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1874 char p1[MAXPATHLEN];
1876 /* Need to prepend the drive. */
1879 Copy(path, p1 + 2, strlen(path) + 1, char);
1881 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1886 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1892 /* Either path is relative, or starts with a drive letter. */
1893 /* If the path starts with a drive letter, then dir is
1895 a/b) it is absolute/x:relative on the same drive.
1896 c) path is on current drive, and dir is rooted
1897 In all the cases it is safe to drop the drive part
1899 if ( !sys_is_relative(path) ) {
1902 if ( ( ( sys_is_absolute(dir)
1903 || (isALPHA(dir[0]) && dir[1] == ':'
1904 && strnicmp(dir, path,1) == 0))
1905 && strnicmp(dir, path,1) == 0)
1906 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1907 && toupper(path[0]) == current_drive())) {
1909 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1910 RETVAL = p; goto done;
1912 RETVAL = NULL; goto done;
1916 /* Need to prepend the absolute path of dir. */
1917 char p1[MAXPATHLEN];
1919 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1922 if (p1[ l - 1 ] != '/') {
1926 Copy(path, p1 + l, strlen(path) + 1, char);
1927 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1939 ST(0) = sv_newmortal();
1940 sv_setpv((SV*)ST(0), RETVAL);
1944 typedef APIRET (*PELP)(PSZ path, ULONG type);
1947 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1949 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
1950 return (*(PELP)ExtFCN[ord])(path, type);
1953 #define extLibpath(type) \
1954 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1955 : BEGIN_LIBPATH))) \
1958 #define extLibpath_set(p,type) \
1959 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1962 XS(XS_Cwd_extLibpath)
1965 if (items < 0 || items > 1)
1966 croak("Usage: Cwd::extLibpath(type = 0)");
1976 type = (int)SvIV(ST(0));
1979 RETVAL = extLibpath(type);
1980 ST(0) = sv_newmortal();
1981 sv_setpv((SV*)ST(0), RETVAL);
1986 XS(XS_Cwd_extLibpath_set)
1989 if (items < 1 || items > 2)
1990 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1993 char * s = (char *)SvPV(ST(0),n_a);
2001 type = (int)SvIV(ST(1));
2004 RETVAL = extLibpath_set(s, type);
2005 ST(0) = boolSV(RETVAL);
2006 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
2014 char *file = __FILE__;
2018 if (_emx_env & 0x200) { /* OS/2 */
2019 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
2020 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
2021 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
2023 newXS("OS2::Error", XS_OS2_Error, file);
2024 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
2025 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
2026 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
2027 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
2028 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
2029 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
2030 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
2031 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
2032 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
2033 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
2034 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
2035 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
2036 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
2037 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
2038 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
2039 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
2040 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
2043 sv_setiv(GvSV(gv), 1);
2045 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
2047 sv_setiv(GvSV(gv), _emx_rev);
2048 sv_setpv(GvSV(gv), _emx_vprt);
2050 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
2052 sv_setiv(GvSV(gv), _emx_env);
2053 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
2055 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
2059 OS2_Perl_data_t OS2_Perl_data;
2062 Perl_OS2_init(char **env)
2068 OS2_Perl_data.xs_init = &Xs_OS2_init;
2069 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
2070 if (environ == NULL) {
2073 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
2074 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
2075 strcpy(PL_sh_path, SH_PATH);
2076 PL_sh_path[0] = shell[0];
2077 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
2078 int l = strlen(shell), i;
2079 if (shell[l-1] == '/' || shell[l-1] == '\\') {
2082 New(1304, PL_sh_path, l + 8, char);
2083 strncpy(PL_sh_path, shell, l);
2084 strcpy(PL_sh_path + l, "/sh.exe");
2085 for (i = 0; i < l; i++) {
2086 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
2089 MUTEX_INIT(&start_thread_mutex);
2090 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2097 my_tmpnam (char *str)
2099 char *p = getenv("TMP"), *tpath;
2102 if (!p) p = getenv("TEMP");
2103 tpath = tempnam(p, "pltmp");
2117 if (s.st_mode & S_IWOTH) {
2120 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2126 /* This code was contributed by Rocco Caputo. */
2128 my_flock(int handle, int o)
2130 FILELOCK rNull, rFull;
2131 ULONG timeout, handle_type, flag_word;
2133 int blocking, shared;
2134 static int use_my = -1;
2137 char *s = getenv("USE_PERL_FLOCK");
2143 if (!(_emx_env & 0x200) || !use_my)
2144 return flock(handle, o); /* Delegate to EMX. */
2147 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2148 (handle_type & 0xFF))
2153 // set lock/unlock ranges
2154 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2155 rFull.lRange = 0x7FFFFFFF;
2156 // set timeout for blocking
2157 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2158 // shared or exclusive?
2159 shared = (o & LOCK_SH) ? 1 : 0;
2160 // do not block the unlock
2161 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2162 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2167 case ERROR_INVALID_HANDLE:
2170 case ERROR_SHARING_BUFFER_EXCEEDED:
2173 case ERROR_LOCK_VIOLATION:
2174 break; // not an error
2175 case ERROR_INVALID_PARAMETER:
2176 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2177 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2180 case ERROR_INTERRUPT:
2189 if (o & (LOCK_SH | LOCK_EX)) {
2190 // for blocking operations
2204 case ERROR_INVALID_HANDLE:
2207 case ERROR_SHARING_BUFFER_EXCEEDED:
2210 case ERROR_LOCK_VIOLATION:
2212 errno = EWOULDBLOCK;
2216 case ERROR_INVALID_PARAMETER:
2217 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2218 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2221 case ERROR_INTERRUPT:
2228 // give away timeslice