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 && (rc != ERROR_INTERRUPT))
168 croak("panic: COND_WAIT: rc=%i", rc);
169 if (rc == ERROR_INTERRUPT)
171 if (m) MUTEX_LOCK(m);
175 /*****************************************************************************/
176 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
177 static PFN ExtFCN[2]; /* Labeled by ord below. */
178 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
179 #define ORD_QUERY_ELP 0
180 #define ORD_SET_ELP 1
185 if (ExtFCN[ord] == NULL) {
186 static HMODULE hdosc = 0;
191 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
192 "doscalls", &hdosc)))
193 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
194 die("This version of OS/2 does not support doscalls.%i",
198 if ((long)ExtFCN[ord] == -1) die("panic queryaddr");
202 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
204 #define QSS_INI_BUFFER 1024
207 get_sysinfo(ULONG pid, ULONG flags)
210 ULONG rc, buf_len = QSS_INI_BUFFER;
212 New(1322, pbuffer, buf_len, char);
213 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
214 rc = QuerySysState(flags, pid, pbuffer, buf_len);
215 while (rc == ERROR_BUFFER_OVERFLOW) {
216 Renew(pbuffer, buf_len *= 2, char);
217 rc = QuerySysState(flags, pid, pbuffer, buf_len);
224 return (PQTOPLEVEL)pbuffer;
227 #define PRIO_ERR 0x1111
235 psi = get_sysinfo(pid, QSS_PROCESS);
239 if (pid != psi->procdata->pid) {
241 croak("panic: wrong pid in sysinfo");
243 prio = psi->procdata->threads->priority;
249 setpriority(int which, int pid, int val)
254 prio = sys_prio(pid);
256 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
257 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
258 /* Do not change class. */
259 return CheckOSError(DosSetPriority((pid < 0)
260 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
262 (32 - val) % 32 - (prio & 0xFF),
265 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
266 /* Documentation claims one can change both class and basevalue,
267 * but I find it wrong. */
268 /* Change class, but since delta == 0 denotes absolute 0, correct. */
269 if (CheckOSError(DosSetPriority((pid < 0)
270 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
271 priors[(32 - val) >> 5] + 1,
275 if ( ((32 - val) % 32) == 0 ) return 0;
276 return CheckOSError(DosSetPriority((pid < 0)
277 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
283 /* else return CheckOSError(DosSetPriority((pid < 0) */
284 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
285 /* priors[(32 - val) >> 5] + 1, */
286 /* (32 - val) % 32 - (prio & 0xFF), */
292 getpriority(int which /* ignored */, int pid)
298 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
299 /* DosGetInfoBlocks has old priority! */
300 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
301 /* if (pid != pib->pib_ulpid) { */
303 if (ret == PRIO_ERR) {
307 /* ret = tib->tib_ptib2->tib2_ulpri; */
308 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
311 /*****************************************************************************/
313 typedef void (*Sigfunc) _((int));
316 result(int flag, int pid)
319 Signal_t (*ihand)(); /* place to save signal during system() */
320 Signal_t (*qhand)(); /* place to save signal during system() */
326 if (pid < 0 || flag != 0)
330 ihand = rsignal(SIGINT, SIG_IGN);
331 qhand = rsignal(SIGQUIT, SIG_IGN);
333 r = wait4pid(pid, &status, 0);
334 } while (r == -1 && errno == EINTR);
335 rsignal(SIGINT, ihand);
336 rsignal(SIGQUIT, qhand);
338 statusvalue = (U16)status;
341 return status & 0xFFFF;
343 ihand = rsignal(SIGINT, SIG_IGN);
344 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
345 rsignal(SIGINT, ihand);
346 statusvalue = res.codeResult << 8 | res.codeTerminate;
353 #define EXECF_SPAWN 0
355 #define EXECF_TRUEEXEC 2
356 #define EXECF_SPAWN_NOWAIT 3
358 /* Spawn/exec a program, revert to shell if needed. */
359 /* global Argv[] contains arguments. */
362 do_spawn_ve(really, flag, execf)
369 int rc, secondtry = 0, err;
371 char buf[256], *s = 0;
373 static char * fargs[4]
374 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
375 char **argsp = fargs;
382 if (strEQ(Argv[0],"/bin/sh"))
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? */
391 if (!really || !*(tmps = SvPV(really, na)))
394 rc = result(trueflag, spawnvp(flag,tmps,Argv));
396 if (execf == EXECF_TRUEEXEC)
397 rc = execvp(tmps,Argv);
398 else if (execf == EXECF_EXEC)
399 rc = spawnvp(trueflag | P_OVERLAY,tmps,Argv);
400 else if (execf == EXECF_SPAWN_NOWAIT)
401 rc = spawnvp(trueflag | P_NOWAIT,tmps,Argv);
402 else /* EXECF_SPAWN */
403 rc = result(trueflag,
404 spawnvp(trueflag | P_NOWAIT,tmps,Argv));
406 if (rc < 0 && secondtry == 0
407 && (tmps == Argv[0])) { /* Cannot transfer `really' via shell. */
409 if (err == ENOENT) { /* No such file. */
410 /* One reason may be that EMX added .exe. We suppose
411 that .exe-less files are automatically shellable.
412 It might have also been .cmd file without
415 (no_dir = strrchr(Argv[0], '/'))
416 || (no_dir = strrchr(Argv[0], '\\'))
417 || (no_dir = Argv[0]);
418 if (!strchr(no_dir, '.')) {
420 if (stat(Argv[0], &buffer) != -1) { /* File exists. */
421 /* Maybe we need to specify the full name here? */
424 /* Try adding script extensions to the file name */
426 if ((scr = find_script(Argv[0], TRUE, NULL, 0))) {
427 FILE *file = fopen(scr, "r");
433 if (!fgets(buf, sizeof buf, file)) {
437 if (fclose(file) != 0) { /* Failure */
439 warn("Error reading \"%s\": %s",
440 scr, Strerror(errno));
446 } else if (buf[0] == 'e') {
447 if (strnEQ(buf, "extproc", 7)
450 } else if (buf[0] == 'E') {
451 if (strnEQ(buf, "EXTPROC", 7)
470 while (*s && !isSPACE(*s))
477 warn("Too many args on %.*s line of \"%s\"",
488 } else if (err == ENOEXEC) { /* Need to send to shell. */
493 while (a[1]) /* Get to the end */
496 *(a + nargs) = *a; /* Argv was preallocated to be
501 Argv[nargs] = argsp[nargs];
507 if (rc < 0 && dowarn)
508 warn("Can't %s \"%s\": %s\n",
509 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
511 Argv[0], Strerror(err));
512 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
513 && ((trueflag & 0xFF) == P_WAIT))
514 rc = 255 << 8; /* Emulate the fork(). */
520 do_aspawn(really,mark,sp)
529 int flag = P_WAIT, trueflag, err, secondtry = 0;
532 New(1301,Argv, sp - mark + 3, char*);
535 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
540 while (++mark <= sp) {
542 *a++ = SvPVx(*mark, na);
548 rc = do_spawn_ve(really, flag, EXECF_SPAWN);
555 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
557 do_spawn2(cmd, execf)
564 char *shell, *copt, *news = NULL;
565 int rc, added_shell = 0, err, seenspace = 0;
566 char fullcmd[MAXNAMLEN + 1];
569 if ((shell = getenv("EMXSHELL")) != NULL)
571 else if ((shell = getenv("SHELL")) != NULL)
573 else if ((shell = getenv("COMSPEC")) != NULL)
578 /* Consensus on perl5-porters is that it is _very_ important to
579 have a shell which will not change between computers with the
580 same architecture, to avoid "action on a distance".
581 And to have simple build, this shell should be sh. */
586 while (*cmd && isSPACE(*cmd))
589 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
590 STRLEN l = strlen(sh_path);
592 New(1302, news, strlen(cmd) - 7 + l + 1, char);
593 strcpy(news, sh_path);
594 strcpy(news + l, cmd + 7);
599 /* save an extra exec if possible */
600 /* see if there are shell metacharacters in it */
602 if (*cmd == '.' && isSPACE(cmd[1]))
605 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
608 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
612 for (s = cmd; *s; s++) {
613 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
614 if (*s == '\n' && s[1] == '\0') {
617 } else if (*s == '\\' && !seenspace) {
618 continue; /* Allow backslashes in names */
620 /* We do not convert this to do_spawn_ve since shell
621 should be smart enough to start itself gloriously. */
623 if (execf == EXECF_TRUEEXEC)
624 return execl(shell,shell,copt,cmd,(char*)0);
625 else if (execf == EXECF_EXEC)
626 return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
627 else if (execf == EXECF_SPAWN_NOWAIT)
628 return spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
629 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
631 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
632 if (rc < 0 && dowarn)
633 warn("Can't %s \"%s\": %s",
634 (execf == EXECF_SPAWN ? "spawn" : "exec"),
635 shell, Strerror(errno));
636 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
637 if (news) Safefree(news);
639 } else if (*s == ' ' || *s == '\t') {
644 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
645 New(1303,Argv, (s - cmd + 11) / 2, char*);
646 Cmd = savepvn(cmd, s-cmd);
649 while (*s && isSPACE(*s)) s++;
652 while (*s && !isSPACE(*s)) s++;
658 rc = do_spawn_ve(NULL, 0, execf);
661 if (news) Safefree(news);
670 return do_spawn2(cmd, EXECF_SPAWN);
677 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
684 return do_spawn2(cmd, EXECF_EXEC);
691 return do_spawn2(cmd, EXECF_TRUEEXEC);
695 my_syspopen(cmd,mode)
702 register I32 this, that, newfd;
703 register I32 pid, rc;
707 /* `this' is what we use in the parent, `that' in the child. */
708 this = (*mode == 'w');
712 taint_proper("Insecure %s%s", "EXEC");
716 /* Now we need to spawn the child. */
717 newfd = dup(*mode == 'r'); /* Preserve std* */
718 if (p[that] != (*mode == 'r')) {
719 dup2(p[that], *mode == 'r');
722 /* Where is `this' and newfd now? */
723 fcntl(p[this], F_SETFD, FD_CLOEXEC);
724 fcntl(newfd, F_SETFD, FD_CLOEXEC);
725 pid = do_spawn_nowait(cmd);
726 if (newfd != (*mode == 'r')) {
727 dup2(newfd, *mode == 'r'); /* Return std* back. */
730 if (p[that] == (*mode == 'r'))
736 if (p[that] < p[this]) {
737 dup2(p[this], p[that]);
741 sv = *av_fetch(fdpid,p[this],TRUE);
742 (void)SvUPGRADE(sv,SVt_IV);
745 return PerlIO_fdopen(p[this], mode);
747 #else /* USE_POPEN */
753 res = popen(cmd, mode);
755 char *shell = getenv("EMXSHELL");
757 my_setenv("EMXSHELL", sh_path);
758 res = popen(cmd, mode);
759 my_setenv("EMXSHELL", shell);
761 sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
762 (void)SvUPGRADE(sv,SVt_IV);
763 SvIVX(sv) = -1; /* A cooky. */
766 #endif /* USE_POPEN */
770 /******************************************************************/
776 die(no_func, "Unsupported function fork");
782 /*******************************************************************/
783 /* not implemented in EMX 0.9a */
785 void * ctermid(x) { return 0; }
787 #ifdef MYTTYNAME /* was not in emx0.9a */
788 void * ttyname(x) { return 0; }
791 /******************************************************************/
792 /* my socket forwarders - EMX lib only provides static forwarders */
794 static HMODULE htcp = 0;
802 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
804 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
805 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
806 return (void *) ((void * (*)(void)) fcn) ();
811 tcp1(char *name, int arg)
816 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
818 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
819 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
820 ((void (*)(int)) fcn) (arg);
823 void * gethostent() { return tcp0("GETHOSTENT"); }
824 void * getnetent() { return tcp0("GETNETENT"); }
825 void * getprotoent() { return tcp0("GETPROTOENT"); }
826 void * getservent() { return tcp0("GETSERVENT"); }
827 void sethostent(x) { tcp1("SETHOSTENT", x); }
828 void setnetent(x) { tcp1("SETNETENT", x); }
829 void setprotoent(x) { tcp1("SETPROTOENT", x); }
830 void setservent(x) { tcp1("SETSERVENT", x); }
831 void endhostent() { tcp0("ENDHOSTENT"); }
832 void endnetent() { tcp0("ENDNETENT"); }
833 void endprotoent() { tcp0("ENDPROTOENT"); }
834 void endservent() { tcp0("ENDSERVENT"); }
836 /*****************************************************************************/
837 /* not implemented in C Set++ */
840 int setuid(x) { errno = EINVAL; return -1; }
841 int setgid(x) { errno = EINVAL; return -1; }
844 /*****************************************************************************/
845 /* stat() hack for char/block device */
849 /* First attempt used DosQueryFSAttach which crashed the system when
850 used with 5.001. Now just look for /dev/. */
853 os2_stat(char *name, struct stat *st)
855 static int ino = SHRT_MAX;
857 if (stricmp(name, "/dev/con") != 0
858 && stricmp(name, "/dev/tty") != 0)
859 return stat(name, st);
861 memset(st, 0, sizeof *st);
862 st->st_mode = S_IFCHR|0666;
863 st->st_ino = (ino-- & 0x7FFF);
872 /* SBRK() emulation, mostly moved to malloc.c. */
875 sys_alloc(int size) {
877 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
879 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
881 } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
885 #endif /* USE_PERL_SBRK */
889 char *tmppath = TMPPATH1;
894 char *p = getenv("TMP"), *tpath;
897 if (!p) p = getenv("TEMP");
900 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
903 strcpy(tpath + len + 1, TMPPATH1);
909 XS(XS_File__Copy_syscopy)
912 if (items < 2 || items > 3)
913 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
915 char * src = (char *)SvPV(ST(0),na);
916 char * dst = (char *)SvPV(ST(1),na);
923 flag = (unsigned long)SvIV(ST(2));
926 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
927 ST(0) = sv_newmortal();
928 sv_setiv(ST(0), (IV)RETVAL);
937 static char fname[9];
938 int pos = 6, len, avlen;
939 unsigned int sum = 0;
944 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
946 if (SvTYPE(sv) != SVt_PVAV)
947 croak("Not array reference given to mod2fname");
949 avlen = av_len((AV*)sv);
951 croak("Empty array reference given to mod2fname");
953 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
954 strncpy(fname, s, 8);
956 if (len < 6) pos = len;
958 sum = 33 * sum + *(s++); /* Checksumming first chars to
959 * get the capitalization into c.s. */
963 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
965 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
970 sum++; /* Avoid conflict of DLLs in memory. */
972 fname[pos] = 'A' + (sum % 26);
973 fname[pos + 1] = 'A' + (sum / 26 % 26);
974 fname[pos + 2] = '\0';
975 return (char *)fname;
978 XS(XS_DynaLoader_mod2fname)
982 croak("Usage: DynaLoader::mod2fname(sv)");
987 RETVAL = mod2fname(sv);
988 ST(0) = sv_newmortal();
989 sv_setpv((SV*)ST(0), RETVAL);
997 static char buf[300];
1000 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1003 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
1004 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
1011 perllib_mangle(char *s, unsigned int l)
1013 static char *newp, *oldp;
1014 static int newl, oldl, notfound;
1015 static char ret[STATIC_FILE_LENGTH+1];
1017 if (!newp && !notfound) {
1018 newp = getenv("PERLLIB_PREFIX");
1023 while (*newp && !isSPACE(*newp) && *newp != ';') {
1024 newp++; oldl++; /* Skip digits. */
1026 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1027 newp++; /* Skip whitespace. */
1029 newl = strlen(newp);
1030 if (newl == 0 || oldl == 0) {
1031 die("Malformed PERLLIB_PREFIX");
1036 if (*s == '\\') *s = '/';
1049 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1052 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1053 die("Malformed PERLLIB_PREFIX");
1055 strcpy(ret + newl, s + oldl);
1059 extern void dlopen();
1060 void *fakedl = &dlopen; /* Pull in dynaloading part. */
1062 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1063 && ((path)[2] == '/' || (path)[2] == '\\'))
1064 #define sys_is_rooted _fnisabs
1065 #define sys_is_relative _fnisrel
1066 #define current_drive _getdrive
1068 #undef chdir /* Was _chdir2. */
1069 #define sys_chdir(p) (chdir(p) == 0)
1070 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1072 XS(XS_Cwd_current_drive)
1076 croak("Usage: Cwd::current_drive()");
1080 RETVAL = current_drive();
1081 ST(0) = sv_newmortal();
1082 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1087 XS(XS_Cwd_sys_chdir)
1091 croak("Usage: Cwd::sys_chdir(path)");
1093 char * path = (char *)SvPV(ST(0),na);
1096 RETVAL = sys_chdir(path);
1097 ST(0) = boolSV(RETVAL);
1098 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1103 XS(XS_Cwd_change_drive)
1107 croak("Usage: Cwd::change_drive(d)");
1109 char d = (char)*SvPV(ST(0),na);
1112 RETVAL = change_drive(d);
1113 ST(0) = boolSV(RETVAL);
1114 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1119 XS(XS_Cwd_sys_is_absolute)
1123 croak("Usage: Cwd::sys_is_absolute(path)");
1125 char * path = (char *)SvPV(ST(0),na);
1128 RETVAL = sys_is_absolute(path);
1129 ST(0) = boolSV(RETVAL);
1130 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1135 XS(XS_Cwd_sys_is_rooted)
1139 croak("Usage: Cwd::sys_is_rooted(path)");
1141 char * path = (char *)SvPV(ST(0),na);
1144 RETVAL = sys_is_rooted(path);
1145 ST(0) = boolSV(RETVAL);
1146 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1151 XS(XS_Cwd_sys_is_relative)
1155 croak("Usage: Cwd::sys_is_relative(path)");
1157 char * path = (char *)SvPV(ST(0),na);
1160 RETVAL = sys_is_relative(path);
1161 ST(0) = boolSV(RETVAL);
1162 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1171 croak("Usage: Cwd::sys_cwd()");
1175 RETVAL = _getcwd2(p, MAXPATHLEN);
1176 ST(0) = sv_newmortal();
1177 sv_setpv((SV*)ST(0), RETVAL);
1182 XS(XS_Cwd_sys_abspath)
1185 if (items < 1 || items > 2)
1186 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1188 char * path = (char *)SvPV(ST(0),na);
1196 dir = (char *)SvPV(ST(1),na);
1198 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1202 if (_abspath(p, path, MAXPATHLEN) == 0) {
1208 /* Absolute with drive: */
1209 if ( sys_is_absolute(path) ) {
1210 if (_abspath(p, path, MAXPATHLEN) == 0) {
1215 } else if (path[0] == '/' || path[0] == '\\') {
1216 /* Rooted, but maybe on different drive. */
1217 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1218 char p1[MAXPATHLEN];
1220 /* Need to prepend the drive. */
1223 Copy(path, p1 + 2, strlen(path) + 1, char);
1225 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1230 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1236 /* Either path is relative, or starts with a drive letter. */
1237 /* If the path starts with a drive letter, then dir is
1239 a/b) it is absolute/x:relative on the same drive.
1240 c) path is on current drive, and dir is rooted
1241 In all the cases it is safe to drop the drive part
1243 if ( !sys_is_relative(path) ) {
1246 if ( ( ( sys_is_absolute(dir)
1247 || (isALPHA(dir[0]) && dir[1] == ':'
1248 && strnicmp(dir, path,1) == 0))
1249 && strnicmp(dir, path,1) == 0)
1250 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1251 && toupper(path[0]) == current_drive())) {
1253 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1254 RETVAL = p; goto done;
1256 RETVAL = NULL; goto done;
1260 /* Need to prepend the absolute path of dir. */
1261 char p1[MAXPATHLEN];
1263 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1266 if (p1[ l - 1 ] != '/') {
1270 Copy(path, p1 + l, strlen(path) + 1, char);
1271 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1283 ST(0) = sv_newmortal();
1284 sv_setpv((SV*)ST(0), RETVAL);
1288 typedef APIRET (*PELP)(PSZ path, ULONG type);
1291 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1293 loadByOrd(ord); /* Guarantied to load or die! */
1294 return (*(PELP)ExtFCN[ord])(path, type);
1297 #define extLibpath(type) \
1298 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1299 : BEGIN_LIBPATH))) \
1302 #define extLibpath_set(p,type) \
1303 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1306 XS(XS_Cwd_extLibpath)
1309 if (items < 0 || items > 1)
1310 croak("Usage: Cwd::extLibpath(type = 0)");
1320 type = (int)SvIV(ST(0));
1323 RETVAL = extLibpath(type);
1324 ST(0) = sv_newmortal();
1325 sv_setpv((SV*)ST(0), RETVAL);
1330 XS(XS_Cwd_extLibpath_set)
1333 if (items < 1 || items > 2)
1334 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1336 char * s = (char *)SvPV(ST(0),na);
1344 type = (int)SvIV(ST(1));
1347 RETVAL = extLibpath_set(s, type);
1348 ST(0) = boolSV(RETVAL);
1349 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1357 char *file = __FILE__;
1361 if (_emx_env & 0x200) { /* OS/2 */
1362 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
1363 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
1364 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
1366 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
1367 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
1368 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
1369 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
1370 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
1371 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
1372 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
1373 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
1374 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
1375 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1378 sv_setiv(GvSV(gv), 1);
1383 OS2_Perl_data_t OS2_Perl_data;
1386 Perl_OS2_init(char **env)
1392 OS2_Perl_data.xs_init = &Xs_OS2_init;
1393 if (environ == NULL) {
1396 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
1397 New(1304, sh_path, strlen(SH_PATH) + 1, char);
1398 strcpy(sh_path, SH_PATH);
1399 sh_path[0] = shell[0];
1400 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
1401 int l = strlen(shell), i;
1402 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1405 New(1304, sh_path, l + 8, char);
1406 strncpy(sh_path, shell, l);
1407 strcpy(sh_path + l, "/sh.exe");
1408 for (i = 0; i < l; i++) {
1409 if (sh_path[i] == '\\') sh_path[i] = '/';
1412 MUTEX_INIT(&start_thread_mutex);
1419 my_tmpnam (char *str)
1421 char *p = getenv("TMP"), *tpath;
1424 if (!p) p = getenv("TEMP");
1425 tpath = tempnam(p, "pltmp");
1439 if (s.st_mode & S_IWOTH) {
1442 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
1448 /* This code was contributed by Rocco Caputo. */
1450 my_flock(int handle, int o)
1452 FILELOCK rNull, rFull;
1453 ULONG timeout, handle_type, flag_word;
1455 int blocking, shared;
1456 static int use_my = -1;
1459 char *s = getenv("USE_PERL_FLOCK");
1465 if (!(_emx_env & 0x200) || !use_my)
1466 return flock(handle, o); /* Delegate to EMX. */
1469 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
1470 (handle_type & 0xFF))
1475 // set lock/unlock ranges
1476 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
1477 rFull.lRange = 0x7FFFFFFF;
1478 // set timeout for blocking
1479 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
1480 // shared or exclusive?
1481 shared = (o & LOCK_SH) ? 1 : 0;
1482 // do not block the unlock
1483 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
1484 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
1489 case ERROR_INVALID_HANDLE:
1492 case ERROR_SHARING_BUFFER_EXCEEDED:
1495 case ERROR_LOCK_VIOLATION:
1496 break; // not an error
1497 case ERROR_INVALID_PARAMETER:
1498 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1499 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1502 case ERROR_INTERRUPT:
1511 if (o & (LOCK_SH | LOCK_EX)) {
1512 // for blocking operations
1526 case ERROR_INVALID_HANDLE:
1529 case ERROR_SHARING_BUFFER_EXCEEDED:
1532 case ERROR_LOCK_VIOLATION:
1534 errno = EWOULDBLOCK;
1538 case ERROR_INVALID_PARAMETER:
1539 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1540 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1543 case ERROR_INTERRUPT:
1550 // give away timeslice