3 #define INCL_DOSFILEMGR
9 * Various Unix compatibility functions for OS/2
23 typedef void (*emx_startroutine)(void *);
24 typedef void* (*pthreads_startroutine)(void *);
33 const char *pthreads_states[] = {
44 enum pthreads_state state;
47 thread_join_t *thread_join_data;
48 int thread_join_count;
49 perl_mutex start_thread_mutex;
52 pthread_join(perl_os_thread tid, void **status)
54 MUTEX_LOCK(&start_thread_mutex);
55 switch (thread_join_data[tid].state) {
56 case pthreads_st_exited:
57 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
58 MUTEX_UNLOCK(&start_thread_mutex);
59 *status = thread_join_data[tid].status;
61 case pthreads_st_waited:
62 MUTEX_UNLOCK(&start_thread_mutex);
63 croak("join with a thread with a waiter");
66 thread_join_data[tid].state = pthreads_st_waited;
67 COND_INIT(&thread_join_data[tid].cond);
68 MUTEX_UNLOCK(&start_thread_mutex);
69 COND_WAIT(&thread_join_data[tid].cond, NULL);
70 COND_DESTROY(&thread_join_data[tid].cond);
71 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
72 *status = thread_join_data[tid].status;
75 MUTEX_UNLOCK(&start_thread_mutex);
76 croak("join: unknown thread state: '%s'",
77 pthreads_states[thread_join_data[tid].state]);
84 pthread_startit(void *arg)
86 /* Thread is already started, we need to transfer control only */
87 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
88 int tid = pthread_self();
91 arg = ((void**)arg)[1];
92 if (tid >= thread_join_count) {
93 int oc = thread_join_count;
95 thread_join_count = tid + 5 + tid/5;
96 if (thread_join_data) {
97 Renew(thread_join_data, thread_join_count, thread_join_t);
98 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
100 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
103 if (thread_join_data[tid].state != pthreads_st_none)
104 croak("attempt to reuse thread id %i", tid);
105 thread_join_data[tid].state = pthreads_st_run;
106 /* Now that we copied/updated the guys, we may release the caller... */
107 MUTEX_UNLOCK(&start_thread_mutex);
108 thread_join_data[tid].status = (*start_routine)(arg);
109 switch (thread_join_data[tid].state) {
110 case pthreads_st_waited:
111 COND_SIGNAL(&thread_join_data[tid].cond);
114 thread_join_data[tid].state = pthreads_st_exited;
120 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
121 void *(*start_routine)(void*), void *arg)
125 args[0] = (void*)start_routine;
128 MUTEX_LOCK(&start_thread_mutex);
129 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
130 /*stacksize*/ 10*1024*1024, (void*)args);
131 MUTEX_LOCK(&start_thread_mutex);
132 MUTEX_UNLOCK(&start_thread_mutex);
133 return *tid ? 0 : EINVAL;
137 pthread_detach(perl_os_thread tid)
139 MUTEX_LOCK(&start_thread_mutex);
140 switch (thread_join_data[tid].state) {
141 case pthreads_st_waited:
142 MUTEX_UNLOCK(&start_thread_mutex);
143 croak("detach on a thread with a waiter");
145 case pthreads_st_run:
146 thread_join_data[tid].state = pthreads_st_detached;
147 MUTEX_UNLOCK(&start_thread_mutex);
150 MUTEX_UNLOCK(&start_thread_mutex);
151 croak("detach: unknown thread state: '%s'",
152 pthreads_states[thread_join_data[tid].state]);
158 /* This is a very bastardized version: */
160 os2_cond_wait(perl_cond *c, perl_mutex *m)
163 if ((rc = DosResetEventSem(*c,&na)) && (rc != ERROR_ALREADY_RESET))
164 croak("panic: COND_WAIT-reset: rc=%i", rc);
165 if (m) MUTEX_UNLOCK(m);
166 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT)))
167 croak("panic: COND_WAIT: rc=%i", rc);
168 if (m) MUTEX_LOCK(m);
172 /*****************************************************************************/
173 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
174 static PFN ExtFCN[2]; /* Labeled by ord below. */
175 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
176 #define ORD_QUERY_ELP 0
177 #define ORD_SET_ELP 1
182 if (ExtFCN[ord] == NULL) {
183 static HMODULE hdosc = 0;
188 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
189 "doscalls", &hdosc)))
190 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
191 die("This version of OS/2 does not support doscalls.%i",
195 if ((long)ExtFCN[ord] == -1) die("panic queryaddr");
199 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
201 #define QSS_INI_BUFFER 1024
204 get_sysinfo(ULONG pid, ULONG flags)
207 ULONG rc, buf_len = QSS_INI_BUFFER;
209 New(1322, pbuffer, buf_len, char);
210 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
211 rc = QuerySysState(flags, pid, pbuffer, buf_len);
212 while (rc == ERROR_BUFFER_OVERFLOW) {
213 Renew(pbuffer, buf_len *= 2, char);
214 rc = QuerySysState(flags, pid, pbuffer, buf_len);
221 return (PQTOPLEVEL)pbuffer;
224 #define PRIO_ERR 0x1111
232 psi = get_sysinfo(pid, QSS_PROCESS);
236 if (pid != psi->procdata->pid) {
238 croak("panic: wrong pid in sysinfo");
240 prio = psi->procdata->threads->priority;
246 setpriority(int which, int pid, int val)
251 prio = sys_prio(pid);
253 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
254 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
255 /* Do not change class. */
256 return CheckOSError(DosSetPriority((pid < 0)
257 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
259 (32 - val) % 32 - (prio & 0xFF),
262 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
263 /* Documentation claims one can change both class and basevalue,
264 * but I find it wrong. */
265 /* Change class, but since delta == 0 denotes absolute 0, correct. */
266 if (CheckOSError(DosSetPriority((pid < 0)
267 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
268 priors[(32 - val) >> 5] + 1,
272 if ( ((32 - val) % 32) == 0 ) return 0;
273 return CheckOSError(DosSetPriority((pid < 0)
274 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
280 /* else return CheckOSError(DosSetPriority((pid < 0) */
281 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
282 /* priors[(32 - val) >> 5] + 1, */
283 /* (32 - val) % 32 - (prio & 0xFF), */
289 getpriority(int which /* ignored */, int pid)
295 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
296 /* DosGetInfoBlocks has old priority! */
297 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
298 /* if (pid != pib->pib_ulpid) { */
300 if (ret == PRIO_ERR) {
304 /* ret = tib->tib_ptib2->tib2_ulpri; */
305 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
308 /*****************************************************************************/
310 typedef void (*Sigfunc) _((int));
313 result(int flag, int pid)
316 Signal_t (*ihand)(); /* place to save signal during system() */
317 Signal_t (*qhand)(); /* place to save signal during system() */
323 if (pid < 0 || flag != 0)
327 ihand = rsignal(SIGINT, SIG_IGN);
328 qhand = rsignal(SIGQUIT, SIG_IGN);
330 r = wait4pid(pid, &status, 0);
331 } while (r == -1 && errno == EINTR);
332 rsignal(SIGINT, ihand);
333 rsignal(SIGQUIT, qhand);
335 statusvalue = (U16)status;
338 return status & 0xFFFF;
340 ihand = rsignal(SIGINT, SIG_IGN);
341 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
342 rsignal(SIGINT, ihand);
343 statusvalue = res.codeResult << 8 | res.codeTerminate;
351 do_aspawn(really,mark,sp)
360 int flag = P_WAIT, trueflag, err, secondtry = 0;
363 New(1301,Argv, sp - mark + 3, char*);
366 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
371 while (++mark <= sp) {
373 *a++ = SvPVx(*mark, na);
383 if (strEQ(Argv[0],"/bin/sh")) Argv[0] = sh_path;
385 if (Argv[0][0] != '/' && Argv[0][0] != '\\'
386 && !(Argv[0][0] && Argv[0][1] == ':'
387 && (Argv[0][2] == '/' || Argv[0][2] != '\\'))
388 ) /* will swawnvp use PATH? */
389 TAINT_ENV(); /* testing IFS here is overkill, probably */
390 /* We should check PERL_SH* and PERLLIB_* as well? */
392 if (really && *(tmps = SvPV(really, na)))
393 rc = result(trueflag, spawnvp(flag,tmps,Argv));
395 rc = result(trueflag, spawnvp(flag,Argv[0],Argv));
397 if (rc < 0 && secondtry == 0
398 && (!tmps || !*tmps)) { /* Cannot transfer `really' via shell. */
400 if (err == ENOENT) { /* No such file. */
401 /* One reason may be that EMX added .exe. We suppose
402 that .exe-less files are automatically shellable. */
404 (no_dir = strrchr(Argv[0], '/'))
405 || (no_dir = strrchr(Argv[0], '\\'))
406 || (no_dir = Argv[0]);
407 if (!strchr(no_dir, '.')) {
409 if (stat(Argv[0], &buffer) != -1) { /* File exists. */
410 /* Maybe we need to specify the full name here? */
414 } else if (err == ENOEXEC) { /* Need to send to shell. */
426 if (rc < 0 && dowarn)
427 warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
428 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
435 #define EXECF_SPAWN 0
437 #define EXECF_TRUEEXEC 2
438 #define EXECF_SPAWN_NOWAIT 3
441 do_spawn2(cmd, execf)
448 char *shell, *copt, *news = NULL;
449 int rc, added_shell = 0, err, seenspace = 0;
450 char fullcmd[MAXNAMLEN + 1];
453 if ((shell = getenv("EMXSHELL")) != NULL)
455 else if ((shell = getenv("SHELL")) != NULL)
457 else if ((shell = getenv("COMSPEC")) != NULL)
462 /* Consensus on perl5-porters is that it is _very_ important to
463 have a shell which will not change between computers with the
464 same architecture, to avoid "action on a distance".
465 And to have simple build, this shell should be sh. */
470 while (*cmd && isSPACE(*cmd))
473 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
474 STRLEN l = strlen(sh_path);
476 New(1302, news, strlen(cmd) - 7 + l + 1, char);
477 strcpy(news, sh_path);
478 strcpy(news + l, cmd + 7);
483 /* save an extra exec if possible */
484 /* see if there are shell metacharacters in it */
486 if (*cmd == '.' && isSPACE(cmd[1]))
489 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
492 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
496 for (s = cmd; *s; s++) {
497 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
498 if (*s == '\n' && s[1] == '\0') {
501 } else if (*s == '\\' && !seenspace) {
502 continue; /* Allow backslashes in names */
505 if (execf == EXECF_TRUEEXEC)
506 return execl(shell,shell,copt,cmd,(char*)0);
507 else if (execf == EXECF_EXEC)
508 return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
509 else if (execf == EXECF_SPAWN_NOWAIT)
510 return spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
511 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
513 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
514 if (rc < 0 && dowarn)
515 warn("Can't %s \"%s\": %s",
516 (execf == EXECF_SPAWN ? "spawn" : "exec"),
517 shell, Strerror(errno));
518 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
519 if (news) Safefree(news);
521 } else if (*s == ' ' || *s == '\t') {
526 New(1303,Argv, (s - cmd) / 2 + 2, char*);
527 Cmd = savepvn(cmd, s-cmd);
530 while (*s && isSPACE(*s)) s++;
533 while (*s && !isSPACE(*s)) s++;
541 if (execf == EXECF_TRUEEXEC)
542 rc = execvp(Argv[0],Argv);
543 else if (execf == EXECF_EXEC)
544 rc = spawnvp(P_OVERLAY,Argv[0],Argv);
545 else if (execf == EXECF_SPAWN_NOWAIT)
546 rc = spawnvp(P_NOWAIT,Argv[0],Argv);
548 rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
551 if (err == ENOENT) { /* No such file. */
552 /* One reason may be that EMX added .exe. We suppose
553 that .exe-less files are automatically shellable. */
555 (no_dir = strrchr(Argv[0], '/'))
556 || (no_dir = strrchr(Argv[0], '\\'))
557 || (no_dir = Argv[0]);
558 if (!strchr(no_dir, '.')) {
560 if (stat(Argv[0], &buffer) != -1) { /* File exists. */
561 /* Maybe we need to specify the full name here? */
565 } else if (err == ENOEXEC) { /* Need to send to shell. */
569 if (rc < 0 && dowarn)
570 warn("Can't %s \"%s\": %s",
571 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
573 Argv[0], Strerror(err));
574 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
577 if (news) Safefree(news);
586 return do_spawn2(cmd, EXECF_SPAWN);
593 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
600 return do_spawn2(cmd, EXECF_EXEC);
607 return do_spawn2(cmd, EXECF_TRUEEXEC);
611 my_syspopen(cmd,mode)
618 register I32 this, that, newfd;
619 register I32 pid, rc;
623 /* `this' is what we use in the parent, `that' in the child. */
624 this = (*mode == 'w');
628 taint_proper("Insecure %s%s", "EXEC");
632 /* Now we need to spawn the child. */
633 newfd = dup(*mode == 'r'); /* Preserve std* */
634 if (p[that] != (*mode == 'r')) {
635 dup2(p[that], *mode == 'r');
638 /* Where is `this' and newfd now? */
639 fcntl(p[this], F_SETFD, FD_CLOEXEC);
640 fcntl(newfd, F_SETFD, FD_CLOEXEC);
641 pid = do_spawn_nowait(cmd);
642 if (newfd != (*mode == 'r')) {
643 dup2(newfd, *mode == 'r'); /* Return std* back. */
651 if (p[that] < p[this]) {
652 dup2(p[this], p[that]);
656 sv = *av_fetch(fdpid,p[this],TRUE);
657 (void)SvUPGRADE(sv,SVt_IV);
660 return PerlIO_fdopen(p[this], mode);
662 #else /* USE_POPEN */
668 res = popen(cmd, mode);
670 char *shell = getenv("EMXSHELL");
672 my_setenv("EMXSHELL", sh_path);
673 res = popen(cmd, mode);
674 my_setenv("EMXSHELL", shell);
676 sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
677 (void)SvUPGRADE(sv,SVt_IV);
678 SvIVX(sv) = -1; /* A cooky. */
681 #endif /* USE_POPEN */
685 /******************************************************************/
691 die(no_func, "Unsupported function fork");
697 /*******************************************************************/
698 /* not implemented in EMX 0.9a */
700 void * ctermid(x) { return 0; }
702 #ifdef MYTTYNAME /* was not in emx0.9a */
703 void * ttyname(x) { return 0; }
706 /******************************************************************/
707 /* my socket forwarders - EMX lib only provides static forwarders */
709 static HMODULE htcp = 0;
717 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
719 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
720 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
721 return (void *) ((void * (*)(void)) fcn) ();
726 tcp1(char *name, int arg)
731 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
733 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
734 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
735 ((void (*)(int)) fcn) (arg);
738 void * gethostent() { return tcp0("GETHOSTENT"); }
739 void * getnetent() { return tcp0("GETNETENT"); }
740 void * getprotoent() { return tcp0("GETPROTOENT"); }
741 void * getservent() { return tcp0("GETSERVENT"); }
742 void sethostent(x) { tcp1("SETHOSTENT", x); }
743 void setnetent(x) { tcp1("SETNETENT", x); }
744 void setprotoent(x) { tcp1("SETPROTOENT", x); }
745 void setservent(x) { tcp1("SETSERVENT", x); }
746 void endhostent() { tcp0("ENDHOSTENT"); }
747 void endnetent() { tcp0("ENDNETENT"); }
748 void endprotoent() { tcp0("ENDPROTOENT"); }
749 void endservent() { tcp0("ENDSERVENT"); }
751 /*****************************************************************************/
752 /* not implemented in C Set++ */
755 int setuid(x) { errno = EINVAL; return -1; }
756 int setgid(x) { errno = EINVAL; return -1; }
759 /*****************************************************************************/
760 /* stat() hack for char/block device */
764 /* First attempt used DosQueryFSAttach which crashed the system when
765 used with 5.001. Now just look for /dev/. */
768 os2_stat(char *name, struct stat *st)
770 static int ino = SHRT_MAX;
772 if (stricmp(name, "/dev/con") != 0
773 && stricmp(name, "/dev/tty") != 0)
774 return stat(name, st);
776 memset(st, 0, sizeof *st);
777 st->st_mode = S_IFCHR|0666;
778 st->st_ino = (ino-- & 0x7FFF);
787 /* SBRK() emulation, mostly moved to malloc.c. */
790 sys_alloc(int size) {
792 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
794 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
796 } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
800 #endif /* USE_PERL_SBRK */
804 char *tmppath = TMPPATH1;
809 char *p = getenv("TMP"), *tpath;
812 if (!p) p = getenv("TEMP");
815 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
818 strcpy(tpath + len + 1, TMPPATH1);
824 XS(XS_File__Copy_syscopy)
827 if (items < 2 || items > 3)
828 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
830 char * src = (char *)SvPV(ST(0),na);
831 char * dst = (char *)SvPV(ST(1),na);
838 flag = (unsigned long)SvIV(ST(2));
841 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
842 ST(0) = sv_newmortal();
843 sv_setiv(ST(0), (IV)RETVAL);
852 static char fname[9];
853 int pos = 6, len, avlen;
854 unsigned int sum = 0;
859 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
861 if (SvTYPE(sv) != SVt_PVAV)
862 croak("Not array reference given to mod2fname");
864 avlen = av_len((AV*)sv);
866 croak("Empty array reference given to mod2fname");
868 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
869 strncpy(fname, s, 8);
871 if (len < 6) pos = len;
873 sum = 33 * sum + *(s++); /* Checksumming first chars to
874 * get the capitalization into c.s. */
878 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
880 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
885 sum++; /* Avoid conflict of DLLs in memory. */
887 fname[pos] = 'A' + (sum % 26);
888 fname[pos + 1] = 'A' + (sum / 26 % 26);
889 fname[pos + 2] = '\0';
890 return (char *)fname;
893 XS(XS_DynaLoader_mod2fname)
897 croak("Usage: DynaLoader::mod2fname(sv)");
902 RETVAL = mod2fname(sv);
903 ST(0) = sv_newmortal();
904 sv_setpv((SV*)ST(0), RETVAL);
912 static char buf[300];
915 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
918 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
919 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
926 perllib_mangle(char *s, unsigned int l)
928 static char *newp, *oldp;
929 static int newl, oldl, notfound;
930 static char ret[STATIC_FILE_LENGTH+1];
932 if (!newp && !notfound) {
933 newp = getenv("PERLLIB_PREFIX");
938 while (*newp && !isSPACE(*newp) && *newp != ';') {
939 newp++; oldl++; /* Skip digits. */
941 while (*newp && (isSPACE(*newp) || *newp == ';')) {
942 newp++; /* Skip whitespace. */
945 if (newl == 0 || oldl == 0) {
946 die("Malformed PERLLIB_PREFIX");
951 if (*s == '\\') *s = '/';
964 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
967 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
968 die("Malformed PERLLIB_PREFIX");
970 strcpy(ret + newl, s + oldl);
974 extern void dlopen();
975 void *fakedl = &dlopen; /* Pull in dynaloading part. */
977 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
978 && ((path)[2] == '/' || (path)[2] == '\\'))
979 #define sys_is_rooted _fnisabs
980 #define sys_is_relative _fnisrel
981 #define current_drive _getdrive
983 #undef chdir /* Was _chdir2. */
984 #define sys_chdir(p) (chdir(p) == 0)
985 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
987 XS(XS_Cwd_current_drive)
991 croak("Usage: Cwd::current_drive()");
995 RETVAL = current_drive();
996 ST(0) = sv_newmortal();
997 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1002 XS(XS_Cwd_sys_chdir)
1006 croak("Usage: Cwd::sys_chdir(path)");
1008 char * path = (char *)SvPV(ST(0),na);
1011 RETVAL = sys_chdir(path);
1012 ST(0) = boolSV(RETVAL);
1013 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1018 XS(XS_Cwd_change_drive)
1022 croak("Usage: Cwd::change_drive(d)");
1024 char d = (char)*SvPV(ST(0),na);
1027 RETVAL = change_drive(d);
1028 ST(0) = boolSV(RETVAL);
1029 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1034 XS(XS_Cwd_sys_is_absolute)
1038 croak("Usage: Cwd::sys_is_absolute(path)");
1040 char * path = (char *)SvPV(ST(0),na);
1043 RETVAL = sys_is_absolute(path);
1044 ST(0) = boolSV(RETVAL);
1045 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1050 XS(XS_Cwd_sys_is_rooted)
1054 croak("Usage: Cwd::sys_is_rooted(path)");
1056 char * path = (char *)SvPV(ST(0),na);
1059 RETVAL = sys_is_rooted(path);
1060 ST(0) = boolSV(RETVAL);
1061 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1066 XS(XS_Cwd_sys_is_relative)
1070 croak("Usage: Cwd::sys_is_relative(path)");
1072 char * path = (char *)SvPV(ST(0),na);
1075 RETVAL = sys_is_relative(path);
1076 ST(0) = boolSV(RETVAL);
1077 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1086 croak("Usage: Cwd::sys_cwd()");
1090 RETVAL = _getcwd2(p, MAXPATHLEN);
1091 ST(0) = sv_newmortal();
1092 sv_setpv((SV*)ST(0), RETVAL);
1097 XS(XS_Cwd_sys_abspath)
1100 if (items < 1 || items > 2)
1101 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1103 char * path = (char *)SvPV(ST(0),na);
1111 dir = (char *)SvPV(ST(1),na);
1113 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1117 if (_abspath(p, path, MAXPATHLEN) == 0) {
1123 /* Absolute with drive: */
1124 if ( sys_is_absolute(path) ) {
1125 if (_abspath(p, path, MAXPATHLEN) == 0) {
1130 } else if (path[0] == '/' || path[0] == '\\') {
1131 /* Rooted, but maybe on different drive. */
1132 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1133 char p1[MAXPATHLEN];
1135 /* Need to prepend the drive. */
1138 Copy(path, p1 + 2, strlen(path) + 1, char);
1140 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1145 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1151 /* Either path is relative, or starts with a drive letter. */
1152 /* If the path starts with a drive letter, then dir is
1154 a/b) it is absolute/x:relative on the same drive.
1155 c) path is on current drive, and dir is rooted
1156 In all the cases it is safe to drop the drive part
1158 if ( !sys_is_relative(path) ) {
1161 if ( ( ( sys_is_absolute(dir)
1162 || (isALPHA(dir[0]) && dir[1] == ':'
1163 && strnicmp(dir, path,1) == 0))
1164 && strnicmp(dir, path,1) == 0)
1165 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1166 && toupper(path[0]) == current_drive())) {
1168 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1169 RETVAL = p; goto done;
1171 RETVAL = NULL; goto done;
1175 /* Need to prepend the absolute path of dir. */
1176 char p1[MAXPATHLEN];
1178 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1181 if (p1[ l - 1 ] != '/') {
1185 Copy(path, p1 + l, strlen(path) + 1, char);
1186 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1198 ST(0) = sv_newmortal();
1199 sv_setpv((SV*)ST(0), RETVAL);
1203 typedef APIRET (*PELP)(PSZ path, ULONG type);
1206 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1208 loadByOrd(ord); /* Guarantied to load or die! */
1209 return (*(PELP)ExtFCN[ord])(path, type);
1212 #define extLibpath(type) \
1213 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1214 : BEGIN_LIBPATH))) \
1217 #define extLibpath_set(p,type) \
1218 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1221 XS(XS_Cwd_extLibpath)
1224 if (items < 0 || items > 1)
1225 croak("Usage: Cwd::extLibpath(type = 0)");
1235 type = (int)SvIV(ST(0));
1238 RETVAL = extLibpath(type);
1239 ST(0) = sv_newmortal();
1240 sv_setpv((SV*)ST(0), RETVAL);
1245 XS(XS_Cwd_extLibpath_set)
1248 if (items < 1 || items > 2)
1249 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1251 char * s = (char *)SvPV(ST(0),na);
1259 type = (int)SvIV(ST(1));
1262 RETVAL = extLibpath_set(s, type);
1263 ST(0) = boolSV(RETVAL);
1264 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1272 char *file = __FILE__;
1276 if (_emx_env & 0x200) { /* OS/2 */
1277 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
1278 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
1279 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
1281 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
1282 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
1283 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
1284 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
1285 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
1286 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
1287 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
1288 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
1289 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
1290 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1293 sv_setiv(GvSV(gv), 1);
1298 OS2_Perl_data_t OS2_Perl_data;
1301 Perl_OS2_init(char **env)
1307 OS2_Perl_data.xs_init = &Xs_OS2_init;
1308 if (environ == NULL) {
1311 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
1312 New(1304, sh_path, strlen(SH_PATH) + 1, char);
1313 strcpy(sh_path, SH_PATH);
1314 sh_path[0] = shell[0];
1315 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
1316 int l = strlen(shell), i;
1317 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1320 New(1304, sh_path, l + 8, char);
1321 strncpy(sh_path, shell, l);
1322 strcpy(sh_path + l, "/sh.exe");
1323 for (i = 0; i < l; i++) {
1324 if (sh_path[i] == '\\') sh_path[i] = '/';
1327 MUTEX_INIT(&start_thread_mutex);
1334 my_tmpnam (char *str)
1336 char *p = getenv("TMP"), *tpath;
1339 if (!p) p = getenv("TEMP");
1340 tpath = tempnam(p, "pltmp");
1354 if (s.st_mode & S_IWOTH) {
1357 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
1363 /* This code was contributed by Rocco Caputo. */
1365 my_flock(int handle, int o)
1367 FILELOCK rNull, rFull;
1368 ULONG timeout, handle_type, flag_word;
1370 int blocking, shared;
1371 static int use_my = -1;
1374 char *s = getenv("USE_PERL_FLOCK");
1380 if (!(_emx_env & 0x200) || !use_my)
1381 return flock(handle, o); /* Delegate to EMX. */
1384 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
1385 (handle_type & 0xFF))
1390 // set lock/unlock ranges
1391 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
1392 rFull.lRange = 0x7FFFFFFF;
1393 // set timeout for blocking
1394 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
1395 // shared or exclusive?
1396 shared = (o & LOCK_SH) ? 1 : 0;
1397 // do not block the unlock
1398 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
1399 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
1404 case ERROR_INVALID_HANDLE:
1407 case ERROR_SHARING_BUFFER_EXCEEDED:
1410 case ERROR_LOCK_VIOLATION:
1411 break; // not an error
1412 case ERROR_INVALID_PARAMETER:
1413 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1414 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1417 case ERROR_INTERRUPT:
1426 if (o & (LOCK_SH | LOCK_EX)) {
1427 // for blocking operations
1441 case ERROR_INVALID_HANDLE:
1444 case ERROR_SHARING_BUFFER_EXCEEDED:
1447 case ERROR_LOCK_VIOLATION:
1449 errno = EWOULDBLOCK;
1453 case ERROR_INVALID_PARAMETER:
1454 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1455 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1458 case ERROR_INTERRUPT:
1465 // give away timeslice