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 pthread_mutex_t start_thread_mutex;
52 pthread_join(pthread_t 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(pthread_t *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(pthread_t 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(pthread_cond_t *c, pthread_mutex_t *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. */
884 fname[pos] = 'A' + (sum % 26);
885 fname[pos + 1] = 'A' + (sum / 26 % 26);
886 fname[pos + 2] = '\0';
887 return (char *)fname;
890 XS(XS_DynaLoader_mod2fname)
894 croak("Usage: DynaLoader::mod2fname(sv)");
899 RETVAL = mod2fname(sv);
900 ST(0) = sv_newmortal();
901 sv_setpv((SV*)ST(0), RETVAL);
909 static char buf[300];
912 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
915 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
916 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
923 perllib_mangle(char *s, unsigned int l)
925 static char *newp, *oldp;
926 static int newl, oldl, notfound;
927 static char ret[STATIC_FILE_LENGTH+1];
929 if (!newp && !notfound) {
930 newp = getenv("PERLLIB_PREFIX");
935 while (*newp && !isSPACE(*newp) && *newp != ';') {
936 newp++; oldl++; /* Skip digits. */
938 while (*newp && (isSPACE(*newp) || *newp == ';')) {
939 newp++; /* Skip whitespace. */
942 if (newl == 0 || oldl == 0) {
943 die("Malformed PERLLIB_PREFIX");
948 if (*s == '\\') *s = '/';
961 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
964 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
965 die("Malformed PERLLIB_PREFIX");
967 strcpy(ret + newl, s + oldl);
971 extern void dlopen();
972 void *fakedl = &dlopen; /* Pull in dynaloading part. */
974 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
975 && ((path)[2] == '/' || (path)[2] == '\\'))
976 #define sys_is_rooted _fnisabs
977 #define sys_is_relative _fnisrel
978 #define current_drive _getdrive
980 #undef chdir /* Was _chdir2. */
981 #define sys_chdir(p) (chdir(p) == 0)
982 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
984 XS(XS_Cwd_current_drive)
988 croak("Usage: Cwd::current_drive()");
992 RETVAL = current_drive();
993 ST(0) = sv_newmortal();
994 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1003 croak("Usage: Cwd::sys_chdir(path)");
1005 char * path = (char *)SvPV(ST(0),na);
1008 RETVAL = sys_chdir(path);
1009 ST(0) = boolSV(RETVAL);
1010 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1015 XS(XS_Cwd_change_drive)
1019 croak("Usage: Cwd::change_drive(d)");
1021 char d = (char)*SvPV(ST(0),na);
1024 RETVAL = change_drive(d);
1025 ST(0) = boolSV(RETVAL);
1026 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1031 XS(XS_Cwd_sys_is_absolute)
1035 croak("Usage: Cwd::sys_is_absolute(path)");
1037 char * path = (char *)SvPV(ST(0),na);
1040 RETVAL = sys_is_absolute(path);
1041 ST(0) = boolSV(RETVAL);
1042 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1047 XS(XS_Cwd_sys_is_rooted)
1051 croak("Usage: Cwd::sys_is_rooted(path)");
1053 char * path = (char *)SvPV(ST(0),na);
1056 RETVAL = sys_is_rooted(path);
1057 ST(0) = boolSV(RETVAL);
1058 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1063 XS(XS_Cwd_sys_is_relative)
1067 croak("Usage: Cwd::sys_is_relative(path)");
1069 char * path = (char *)SvPV(ST(0),na);
1072 RETVAL = sys_is_relative(path);
1073 ST(0) = boolSV(RETVAL);
1074 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1083 croak("Usage: Cwd::sys_cwd()");
1087 RETVAL = _getcwd2(p, MAXPATHLEN);
1088 ST(0) = sv_newmortal();
1089 sv_setpv((SV*)ST(0), RETVAL);
1094 XS(XS_Cwd_sys_abspath)
1097 if (items < 1 || items > 2)
1098 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1100 char * path = (char *)SvPV(ST(0),na);
1108 dir = (char *)SvPV(ST(1),na);
1110 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1114 if (_abspath(p, path, MAXPATHLEN) == 0) {
1120 /* Absolute with drive: */
1121 if ( sys_is_absolute(path) ) {
1122 if (_abspath(p, path, MAXPATHLEN) == 0) {
1127 } else if (path[0] == '/' || path[0] == '\\') {
1128 /* Rooted, but maybe on different drive. */
1129 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1130 char p1[MAXPATHLEN];
1132 /* Need to prepend the drive. */
1135 Copy(path, p1 + 2, strlen(path) + 1, char);
1137 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1142 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1148 /* Either path is relative, or starts with a drive letter. */
1149 /* If the path starts with a drive letter, then dir is
1151 a/b) it is absolute/x:relative on the same drive.
1152 c) path is on current drive, and dir is rooted
1153 In all the cases it is safe to drop the drive part
1155 if ( !sys_is_relative(path) ) {
1158 if ( ( ( sys_is_absolute(dir)
1159 || (isALPHA(dir[0]) && dir[1] == ':'
1160 && strnicmp(dir, path,1) == 0))
1161 && strnicmp(dir, path,1) == 0)
1162 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1163 && toupper(path[0]) == current_drive())) {
1165 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1166 RETVAL = p; goto done;
1168 RETVAL = NULL; goto done;
1172 /* Need to prepend the absolute path of dir. */
1173 char p1[MAXPATHLEN];
1175 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1178 if (p1[ l - 1 ] != '/') {
1182 Copy(path, p1 + l, strlen(path) + 1, char);
1183 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1195 ST(0) = sv_newmortal();
1196 sv_setpv((SV*)ST(0), RETVAL);
1200 typedef APIRET (*PELP)(PSZ path, ULONG type);
1203 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1205 loadByOrd(ord); /* Guarantied to load or die! */
1206 return (*(PELP)ExtFCN[ord])(path, type);
1209 #define extLibpath(type) \
1210 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1211 : BEGIN_LIBPATH))) \
1214 #define extLibpath_set(p,type) \
1215 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1218 XS(XS_Cwd_extLibpath)
1221 if (items < 0 || items > 1)
1222 croak("Usage: Cwd::extLibpath(type = 0)");
1232 type = (int)SvIV(ST(0));
1235 RETVAL = extLibpath(type);
1236 ST(0) = sv_newmortal();
1237 sv_setpv((SV*)ST(0), RETVAL);
1242 XS(XS_Cwd_extLibpath_set)
1245 if (items < 1 || items > 2)
1246 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1248 char * s = (char *)SvPV(ST(0),na);
1256 type = (int)SvIV(ST(1));
1259 RETVAL = extLibpath_set(s, type);
1260 ST(0) = boolSV(RETVAL);
1261 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1269 char *file = __FILE__;
1273 if (_emx_env & 0x200) { /* OS/2 */
1274 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
1275 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
1276 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
1278 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
1279 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
1280 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
1281 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
1282 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
1283 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
1284 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
1285 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
1286 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
1287 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1290 sv_setiv(GvSV(gv), 1);
1295 OS2_Perl_data_t OS2_Perl_data;
1298 Perl_OS2_init(char **env)
1304 OS2_Perl_data.xs_init = &Xs_OS2_init;
1305 if (environ == NULL) {
1308 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
1309 New(1304, sh_path, strlen(SH_PATH) + 1, char);
1310 strcpy(sh_path, SH_PATH);
1311 sh_path[0] = shell[0];
1312 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
1313 int l = strlen(shell), i;
1314 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1317 New(1304, sh_path, l + 8, char);
1318 strncpy(sh_path, shell, l);
1319 strcpy(sh_path + l, "/sh.exe");
1320 for (i = 0; i < l; i++) {
1321 if (sh_path[i] == '\\') sh_path[i] = '/';
1324 MUTEX_INIT(&start_thread_mutex);
1331 my_tmpnam (char *str)
1333 char *p = getenv("TMP"), *tpath;
1336 if (!p) p = getenv("TEMP");
1337 tpath = tempnam(p, "pltmp");
1351 if (s.st_mode & S_IWOTH) {
1354 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
1360 /* This code was contributed by Rocco Caputo. */
1362 my_flock(int handle, int o)
1364 FILELOCK rNull, rFull;
1365 ULONG timeout, handle_type, flag_word;
1367 int blocking, shared;
1368 static int use_my = -1;
1371 char *s = getenv("USE_PERL_FLOCK");
1377 if (!(_emx_env & 0x200) || !use_my)
1378 return flock(handle, o); /* Delegate to EMX. */
1381 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
1382 (handle_type & 0xFF))
1387 // set lock/unlock ranges
1388 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
1389 rFull.lRange = 0x7FFFFFFF;
1390 // set timeout for blocking
1391 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
1392 // shared or exclusive?
1393 shared = (o & LOCK_SH) ? 1 : 0;
1394 // do not block the unlock
1395 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
1396 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
1401 case ERROR_INVALID_HANDLE:
1404 case ERROR_SHARING_BUFFER_EXCEEDED:
1407 case ERROR_LOCK_VIOLATION:
1408 break; // not an error
1409 case ERROR_INVALID_PARAMETER:
1410 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1411 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1414 case ERROR_INTERRUPT:
1423 if (o & (LOCK_SH | LOCK_EX)) {
1424 // for blocking operations
1438 case ERROR_INVALID_HANDLE:
1441 case ERROR_SHARING_BUFFER_EXCEEDED:
1444 case ERROR_LOCK_VIOLATION:
1446 errno = EWOULDBLOCK;
1450 case ERROR_INVALID_PARAMETER:
1451 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1452 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1455 case ERROR_INTERRUPT:
1462 // give away timeslice