Re: [PATCH for _66] Makefile.SH problem on dos/djgpp
[p5sagit/p5-mst-13.2.git] / os2 / os2.c
CommitLineData
4633a7c4 1#define INCL_DOS
2#define INCL_NOPM
7a2f0d5b 3#define INCL_DOSFILEMGR
760ac839 4#define INCL_DOSMEMMGR
5#define INCL_DOSERRORS
4633a7c4 6#include <os2.h>
7
8/*
9 * Various Unix compatibility functions for OS/2
10 */
11
12#include <stdio.h>
13#include <errno.h>
14#include <limits.h>
15#include <process.h>
72ea3524 16#include <fcntl.h>
4633a7c4 17
18#include "EXTERN.h"
19#include "perl.h"
20
dd96f567 21#ifdef USE_THREADS
22
23typedef void (*emx_startroutine)(void *);
24typedef void* (*pthreads_startroutine)(void *);
25
26enum pthreads_state {
27 pthreads_st_none = 0,
28 pthreads_st_run,
29 pthreads_st_exited,
30 pthreads_st_detached,
31 pthreads_st_waited,
32};
33const char *pthreads_states[] = {
34 "uninit",
35 "running",
36 "exited",
37 "detached",
38 "waited for",
39};
40
41typedef struct {
42 void *status;
3aefca04 43 perl_cond cond;
dd96f567 44 enum pthreads_state state;
45} thread_join_t;
46
47thread_join_t *thread_join_data;
48int thread_join_count;
3aefca04 49perl_mutex start_thread_mutex;
dd96f567 50
51int
3aefca04 52pthread_join(perl_os_thread tid, void **status)
dd96f567 53{
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;
60 break;
61 case pthreads_st_waited:
62 MUTEX_UNLOCK(&start_thread_mutex);
63 croak("join with a thread with a waiter");
64 break;
65 case pthreads_st_run:
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;
73 break;
74 default:
75 MUTEX_UNLOCK(&start_thread_mutex);
76 croak("join: unknown thread state: '%s'",
77 pthreads_states[thread_join_data[tid].state]);
78 break;
79 }
80 return 0;
81}
82
83void
84pthread_startit(void *arg)
85{
86 /* Thread is already started, we need to transfer control only */
87 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
88 int tid = pthread_self();
89 void *retval;
90
91 arg = ((void**)arg)[1];
92 if (tid >= thread_join_count) {
93 int oc = thread_join_count;
94
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);
99 } else {
100 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
101 }
102 }
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);
112 break;
113 default:
114 thread_join_data[tid].state = pthreads_st_exited;
115 break;
116 }
117}
118
119int
3aefca04 120pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
dd96f567 121 void *(*start_routine)(void*), void *arg)
122{
123 void *args[2];
124
125 args[0] = (void*)start_routine;
126 args[1] = arg;
127
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;
134}
135
136int
3aefca04 137pthread_detach(perl_os_thread tid)
dd96f567 138{
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");
144 break;
145 case pthreads_st_run:
146 thread_join_data[tid].state = pthreads_st_detached;
147 MUTEX_UNLOCK(&start_thread_mutex);
148 break;
149 default:
150 MUTEX_UNLOCK(&start_thread_mutex);
151 croak("detach: unknown thread state: '%s'",
152 pthreads_states[thread_join_data[tid].state]);
153 break;
154 }
155 return 0;
156}
157
158/* This is a very bastardized version: */
159int
3aefca04 160os2_cond_wait(perl_cond *c, perl_mutex *m)
dd96f567 161{
162 int rc;
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);
91643db9 166 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
167 && (rc != ERROR_INTERRUPT))
dd96f567 168 croak("panic: COND_WAIT: rc=%i", rc);
91643db9 169 if (rc == ERROR_INTERRUPT)
170 errno = EINTR;
dd96f567 171 if (m) MUTEX_LOCK(m);
172}
173#endif
174
4633a7c4 175/*****************************************************************************/
72ea3524 176/* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
177static PFN ExtFCN[2]; /* Labeled by ord below. */
178static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
179#define ORD_QUERY_ELP 0
180#define ORD_SET_ELP 1
181
182APIRET
183loadByOrd(ULONG ord)
184{
185 if (ExtFCN[ord] == NULL) {
186 static HMODULE hdosc = 0;
187 BYTE buf[20];
188 PFN fcn;
189 APIRET rc;
190
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",
195 loadOrd[ord]);
196 ExtFCN[ord] = fcn;
197 }
198 if ((long)ExtFCN[ord] == -1) die("panic queryaddr");
199}
200
4633a7c4 201/* priorities */
6f064249 202static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
203 self inverse. */
204#define QSS_INI_BUFFER 1024
4633a7c4 205
6f064249 206PQTOPLEVEL
207get_sysinfo(ULONG pid, ULONG flags)
4633a7c4 208{
6f064249 209 char *pbuffer;
210 ULONG rc, buf_len = QSS_INI_BUFFER;
211
fc36a67e 212 New(1322, pbuffer, buf_len, char);
6f064249 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);
df3ef7a9 217 rc = QuerySysState(flags, pid, pbuffer, buf_len);
6f064249 218 }
219 if (rc) {
220 FillOSError(rc);
221 Safefree(pbuffer);
222 return 0;
223 }
224 return (PQTOPLEVEL)pbuffer;
225}
226
227#define PRIO_ERR 0x1111
228
229static ULONG
230sys_prio(pid)
231{
232 ULONG prio;
233 PQTOPLEVEL psi;
234
235 psi = get_sysinfo(pid, QSS_PROCESS);
236 if (!psi) {
237 return PRIO_ERR;
238 }
239 if (pid != psi->procdata->pid) {
240 Safefree(psi);
241 croak("panic: wrong pid in sysinfo");
242 }
243 prio = psi->procdata->threads->priority;
244 Safefree(psi);
245 return prio;
246}
247
248int
249setpriority(int which, int pid, int val)
250{
251 ULONG rc, prio;
252 PQTOPLEVEL psi;
253
254 prio = sys_prio(pid);
255
55497cff 256 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
6f064249 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,
261 0,
262 (32 - val) % 32 - (prio & 0xFF),
263 abs(pid)))
264 ? -1 : 0;
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,
272 0,
273 abs(pid))))
274 return -1;
275 if ( ((32 - val) % 32) == 0 ) return 0;
276 return CheckOSError(DosSetPriority((pid < 0)
277 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
278 0,
279 (32 - val) % 32,
280 abs(pid)))
281 ? -1 : 0;
282 }
283/* else return CheckOSError(DosSetPriority((pid < 0) */
284/* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
285/* priors[(32 - val) >> 5] + 1, */
286/* (32 - val) % 32 - (prio & 0xFF), */
287/* abs(pid))) */
288/* ? -1 : 0; */
4633a7c4 289}
290
6f064249 291int
292getpriority(int which /* ignored */, int pid)
4633a7c4 293{
294 TIB *tib;
295 PIB *pib;
6f064249 296 ULONG rc, ret;
297
55497cff 298 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
6f064249 299 /* DosGetInfoBlocks has old priority! */
300/* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
301/* if (pid != pib->pib_ulpid) { */
302 ret = sys_prio(pid);
303 if (ret == PRIO_ERR) {
304 return -1;
305 }
306/* } else */
307/* ret = tib->tib_ptib2->tib2_ulpri; */
308 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
4633a7c4 309}
310
311/*****************************************************************************/
312/* spawn */
72ea3524 313typedef void (*Sigfunc) _((int));
314
4633a7c4 315static int
316result(int flag, int pid)
317{
318 int r, status;
319 Signal_t (*ihand)(); /* place to save signal during system() */
320 Signal_t (*qhand)(); /* place to save signal during system() */
760ac839 321#ifndef __EMX__
322 RESULTCODES res;
323 int rpid;
324#endif
4633a7c4 325
760ac839 326 if (pid < 0 || flag != 0)
4633a7c4 327 return pid;
328
760ac839 329#ifdef __EMX__
72ea3524 330 ihand = rsignal(SIGINT, SIG_IGN);
331 qhand = rsignal(SIGQUIT, SIG_IGN);
c0c09dfd 332 do {
333 r = wait4pid(pid, &status, 0);
334 } while (r == -1 && errno == EINTR);
72ea3524 335 rsignal(SIGINT, ihand);
336 rsignal(SIGQUIT, qhand);
4633a7c4 337
338 statusvalue = (U16)status;
339 if (r < 0)
340 return -1;
341 return status & 0xFFFF;
760ac839 342#else
72ea3524 343 ihand = rsignal(SIGINT, SIG_IGN);
760ac839 344 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
72ea3524 345 rsignal(SIGINT, ihand);
760ac839 346 statusvalue = res.codeResult << 8 | res.codeTerminate;
347 if (r)
348 return -1;
349 return statusvalue;
350#endif
4633a7c4 351}
352
491527d0 353#define EXECF_SPAWN 0
354#define EXECF_EXEC 1
355#define EXECF_TRUEEXEC 2
356#define EXECF_SPAWN_NOWAIT 3
357
358/* Spawn/exec a program, revert to shell if needed. */
359/* global Argv[] contains arguments. */
360
4633a7c4 361int
91643db9 362do_spawn_ve(really, flag, execf)
4633a7c4 363SV *really;
491527d0 364U32 flag;
365U32 execf;
4633a7c4 366{
dd96f567 367 dTHR;
491527d0 368 int trueflag = flag;
369 int rc, secondtry = 0, err;
370 char *tmps;
371 char buf[256], *s = 0;
372 char *args[4];
373 static char * fargs[4]
374 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
375 char **argsp = fargs;
376 char nargs = 4;
377
4633a7c4 378 if (flag == P_WAIT)
379 flag = P_NOWAIT;
380
491527d0 381 retry:
382 if (strEQ(Argv[0],"/bin/sh"))
383 Argv[0] = sh_path;
3bbf9c2b 384
385 if (Argv[0][0] != '/' && Argv[0][0] != '\\'
386 && !(Argv[0][0] && Argv[0][1] == ':'
387 && (Argv[0][2] == '/' || Argv[0][2] != '\\'))
760ac839 388 ) /* will swawnvp use PATH? */
c0c09dfd 389 TAINT_ENV(); /* testing IFS here is overkill, probably */
760ac839 390 /* We should check PERL_SH* and PERLLIB_* as well? */
491527d0 391 if (!really || !*(tmps = SvPV(really, na)))
392 tmps = Argv[0];
393#if 0
394 rc = result(trueflag, spawnvp(flag,tmps,Argv));
395#else
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));
405#endif
e29f6e02 406 if (rc < 0 && secondtry == 0
491527d0 407 && (tmps == Argv[0])) { /* Cannot transfer `really' via shell. */
e29f6e02 408 err = errno;
409 if (err == ENOENT) { /* No such file. */
410 /* One reason may be that EMX added .exe. We suppose
491527d0 411 that .exe-less files are automatically shellable.
412 It might have also been .cmd file without
413 extension. */
e29f6e02 414 char *no_dir;
415 (no_dir = strrchr(Argv[0], '/'))
416 || (no_dir = strrchr(Argv[0], '\\'))
417 || (no_dir = Argv[0]);
418 if (!strchr(no_dir, '.')) {
419 struct stat buffer;
420 if (stat(Argv[0], &buffer) != -1) { /* File exists. */
421 /* Maybe we need to specify the full name here? */
422 goto doshell;
491527d0 423 } else {
424 /* Try adding script extensions to the file name */
425 char *scr;
426 if ((scr = find_script(Argv[0], TRUE, NULL, 0))) {
427 FILE *file = fopen(scr, "r");
428 char *s = 0, *s1;
429
430 Argv[0] = scr;
431 if (!file)
432 goto panic_file;
433 if (!fgets(buf, sizeof buf, file)) {
434 fclose(file);
435 goto panic_file;
436 }
437 if (fclose(file) != 0) { /* Failure */
438 panic_file:
439 warn("Error reading \"%s\": %s",
440 scr, Strerror(errno));
441 goto doshell;
442 }
443 if (buf[0] == '#') {
444 if (buf[1] == '!')
445 s = buf + 2;
446 } else if (buf[0] == 'e') {
447 if (strnEQ(buf, "extproc", 7)
448 && isSPACE(buf[7]))
449 s = buf + 8;
450 } else if (buf[0] == 'E') {
451 if (strnEQ(buf, "EXTPROC", 7)
452 && isSPACE(buf[7]))
453 s = buf + 8;
454 }
455 if (!s)
456 goto doshell;
457 s1 = s;
458 nargs = 0;
459 argsp = args;
460 while (1) {
461 while (isSPACE(*s))
462 s++;
463 if (*s == 0)
464 break;
465 if (nargs == 4) {
466 nargs = -1;
467 break;
468 }
469 args[nargs++] = s;
470 while (*s && !isSPACE(*s))
471 s++;
472 if (*s == 0)
473 break;
474 *s++ = 0;
475 }
476 if (nargs == -1) {
477 warn("Too many args on %.*s line of \"%s\"",
478 s1 - buf, buf, scr);
479 nargs = 4;
480 argsp = fargs;
481 }
482 goto doshell;
483 }
e29f6e02 484 }
485 }
491527d0 486 /* Restore errno */
487 errno = err;
e29f6e02 488 } else if (err == ENOEXEC) { /* Need to send to shell. */
489 doshell:
491527d0 490 {
491 char **a = Argv;
492
493 while (a[1]) /* Get to the end */
494 a++;
e29f6e02 495 while (a >= Argv) {
491527d0 496 *(a + nargs) = *a; /* Argv was preallocated to be
497 long enough. */
e29f6e02 498 a--;
499 }
491527d0 500 while (nargs-- >= 0)
501 Argv[nargs] = argsp[nargs];
e29f6e02 502 secondtry = 1;
503 goto retry;
491527d0 504 }
e29f6e02 505 }
506 }
4633a7c4 507 if (rc < 0 && dowarn)
491527d0 508 warn("Can't %s \"%s\": %s\n",
509 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
510 ? "spawn" : "exec"),
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(). */
515
516 return rc;
517}
518
519int
520do_aspawn(really,mark,sp)
521SV *really;
522register SV **mark;
523register SV **sp;
524{
525 dTHR;
526 register char **a;
527 char *tmps = NULL;
528 int rc;
529 int flag = P_WAIT, trueflag, err, secondtry = 0;
530
531 if (sp > mark) {
532 New(1301,Argv, sp - mark + 3, char*);
533 a = Argv;
534
535 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
536 ++mark;
537 flag = SvIVx(*mark);
538 }
539
540 while (++mark <= sp) {
541 if (*mark)
542 *a++ = SvPVx(*mark, na);
543 else
544 *a++ = "";
545 }
546 *a = Nullch;
547
548 rc = do_spawn_ve(really, flag, EXECF_SPAWN);
4633a7c4 549 } else
550 rc = -1;
551 do_execfree();
552 return rc;
553}
554
491527d0 555/* Try converting 1-arg form to (usually shell-less) multi-arg form. */
4633a7c4 556int
760ac839 557do_spawn2(cmd, execf)
4633a7c4 558char *cmd;
760ac839 559int execf;
4633a7c4 560{
561 register char **a;
562 register char *s;
563 char flags[10];
3bbf9c2b 564 char *shell, *copt, *news = NULL;
a0914d8e 565 int rc, added_shell = 0, err, seenspace = 0;
e29f6e02 566 char fullcmd[MAXNAMLEN + 1];
4633a7c4 567
c0c09dfd 568#ifdef TRYSHELL
569 if ((shell = getenv("EMXSHELL")) != NULL)
570 copt = "-c";
571 else if ((shell = getenv("SHELL")) != NULL)
4633a7c4 572 copt = "-c";
573 else if ((shell = getenv("COMSPEC")) != NULL)
574 copt = "/C";
575 else
576 shell = "cmd.exe";
c0c09dfd 577#else
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. */
ff68c719 582 shell = sh_path;
c0c09dfd 583 copt = "-c";
584#endif
585
586 while (*cmd && isSPACE(*cmd))
587 cmd++;
4633a7c4 588
3bbf9c2b 589 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
ff68c719 590 STRLEN l = strlen(sh_path);
3bbf9c2b 591
2cc2f81f 592 New(1302, news, strlen(cmd) - 7 + l + 1, char);
ff68c719 593 strcpy(news, sh_path);
3bbf9c2b 594 strcpy(news + l, cmd + 7);
595 cmd = news;
e29f6e02 596 added_shell = 1;
3bbf9c2b 597 }
598
4633a7c4 599 /* save an extra exec if possible */
600 /* see if there are shell metacharacters in it */
601
c0c09dfd 602 if (*cmd == '.' && isSPACE(cmd[1]))
603 goto doshell;
604
605 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
606 goto doshell;
607
608 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
609 if (*s == '=')
610 goto doshell;
611
4633a7c4 612 for (s = cmd; *s; s++) {
c0c09dfd 613 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
3bbf9c2b 614 if (*s == '\n' && s[1] == '\0') {
4633a7c4 615 *s = '\0';
616 break;
a0914d8e 617 } else if (*s == '\\' && !seenspace) {
618 continue; /* Allow backslashes in names */
4633a7c4 619 }
491527d0 620 /* We do not convert this to do_spawn_ve since shell
621 should be smart enough to start itself gloriously. */
c0c09dfd 622 doshell:
760ac839 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);
72ea3524 627 else if (execf == EXECF_SPAWN_NOWAIT)
628 return spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
760ac839 629 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
c0c09dfd 630 rc = result(P_WAIT,
760ac839 631 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
c0c09dfd 632 if (rc < 0 && dowarn)
760ac839 633 warn("Can't %s \"%s\": %s",
634 (execf == EXECF_SPAWN ? "spawn" : "exec"),
635 shell, Strerror(errno));
c0c09dfd 636 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
3bbf9c2b 637 if (news) Safefree(news);
c0c09dfd 638 return rc;
a0914d8e 639 } else if (*s == ' ' || *s == '\t') {
640 seenspace = 1;
4633a7c4 641 }
642 }
c0c09dfd 643
491527d0 644 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
645 New(1303,Argv, (s - cmd + 11) / 2, char*);
4633a7c4 646 Cmd = savepvn(cmd, s-cmd);
647 a = Argv;
648 for (s = Cmd; *s;) {
649 while (*s && isSPACE(*s)) s++;
650 if (*s)
651 *(a++) = s;
652 while (*s && !isSPACE(*s)) s++;
653 if (*s)
654 *s++ = '\0';
655 }
656 *a = Nullch;
491527d0 657 if (Argv[0])
658 rc = do_spawn_ve(NULL, 0, execf);
659 else
4633a7c4 660 rc = -1;
3bbf9c2b 661 if (news) Safefree(news);
4633a7c4 662 do_execfree();
663 return rc;
664}
665
760ac839 666int
667do_spawn(cmd)
668char *cmd;
669{
670 return do_spawn2(cmd, EXECF_SPAWN);
671}
672
72ea3524 673int
674do_spawn_nowait(cmd)
675char *cmd;
676{
677 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
678}
679
760ac839 680bool
681do_exec(cmd)
682char *cmd;
683{
684 return do_spawn2(cmd, EXECF_EXEC);
685}
686
687bool
688os2exec(cmd)
689char *cmd;
690{
691 return do_spawn2(cmd, EXECF_TRUEEXEC);
692}
693
3bbf9c2b 694PerlIO *
695my_syspopen(cmd,mode)
c0c09dfd 696char *cmd;
697char *mode;
698{
72ea3524 699#ifndef USE_POPEN
700
701 int p[2];
702 register I32 this, that, newfd;
703 register I32 pid, rc;
3bbf9c2b 704 PerlIO *res;
705 SV *sv;
72ea3524 706
72ea3524 707 /* `this' is what we use in the parent, `that' in the child. */
708 this = (*mode == 'w');
709 that = !this;
710 if (tainting) {
711 taint_env();
712 taint_proper("Insecure %s%s", "EXEC");
713 }
c2267164 714 if (pipe(p) < 0)
715 return Nullfp;
72ea3524 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');
720 close(p[that]);
721 }
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. */
728 close(newfd);
729 }
491527d0 730 if (p[that] == (*mode == 'r'))
731 close(p[that]);
72ea3524 732 if (pid == -1) {
733 close(p[this]);
734 return NULL;
735 }
736 if (p[that] < p[this]) {
737 dup2(p[this], p[that]);
738 close(p[this]);
739 p[this] = p[that];
740 }
741 sv = *av_fetch(fdpid,p[this],TRUE);
742 (void)SvUPGRADE(sv,SVt_IV);
743 SvIVX(sv) = pid;
744 forkprocess = pid;
745 return PerlIO_fdopen(p[this], mode);
3bbf9c2b 746
72ea3524 747#else /* USE_POPEN */
748
749 PerlIO *res;
750 SV *sv;
751
752# ifdef TRYSHELL
3bbf9c2b 753 res = popen(cmd, mode);
72ea3524 754# else
c0c09dfd 755 char *shell = getenv("EMXSHELL");
3bbf9c2b 756
ff68c719 757 my_setenv("EMXSHELL", sh_path);
c0c09dfd 758 res = popen(cmd, mode);
759 my_setenv("EMXSHELL", shell);
72ea3524 760# endif
3bbf9c2b 761 sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
762 (void)SvUPGRADE(sv,SVt_IV);
763 SvIVX(sv) = -1; /* A cooky. */
764 return res;
72ea3524 765
766#endif /* USE_POPEN */
767
c0c09dfd 768}
769
3bbf9c2b 770/******************************************************************/
4633a7c4 771
772#ifndef HAS_FORK
773int
774fork(void)
775{
776 die(no_func, "Unsupported function fork");
777 errno = EINVAL;
778 return -1;
779}
780#endif
781
3bbf9c2b 782/*******************************************************************/
4633a7c4 783/* not implemented in EMX 0.9a */
784
785void * ctermid(x) { return 0; }
eacfb5f1 786
787#ifdef MYTTYNAME /* was not in emx0.9a */
4633a7c4 788void * ttyname(x) { return 0; }
eacfb5f1 789#endif
4633a7c4 790
3bbf9c2b 791/******************************************************************/
760ac839 792/* my socket forwarders - EMX lib only provides static forwarders */
793
794static HMODULE htcp = 0;
795
796static void *
797tcp0(char *name)
798{
799 static BYTE buf[20];
800 PFN fcn;
55497cff 801
802 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
760ac839 803 if (!htcp)
804 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
805 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
806 return (void *) ((void * (*)(void)) fcn) ();
807 return 0;
808}
809
810static void
811tcp1(char *name, int arg)
812{
813 static BYTE buf[20];
814 PFN fcn;
55497cff 815
816 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
760ac839 817 if (!htcp)
818 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
819 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
820 ((void (*)(int)) fcn) (arg);
821}
822
823void * gethostent() { return tcp0("GETHOSTENT"); }
824void * getnetent() { return tcp0("GETNETENT"); }
825void * getprotoent() { return tcp0("GETPROTOENT"); }
826void * getservent() { return tcp0("GETSERVENT"); }
827void sethostent(x) { tcp1("SETHOSTENT", x); }
828void setnetent(x) { tcp1("SETNETENT", x); }
829void setprotoent(x) { tcp1("SETPROTOENT", x); }
830void setservent(x) { tcp1("SETSERVENT", x); }
831void endhostent() { tcp0("ENDHOSTENT"); }
832void endnetent() { tcp0("ENDNETENT"); }
833void endprotoent() { tcp0("ENDPROTOENT"); }
834void endservent() { tcp0("ENDSERVENT"); }
835
836/*****************************************************************************/
837/* not implemented in C Set++ */
838
839#ifndef __EMX__
840int setuid(x) { errno = EINVAL; return -1; }
841int setgid(x) { errno = EINVAL; return -1; }
842#endif
4633a7c4 843
844/*****************************************************************************/
845/* stat() hack for char/block device */
846
847#if OS2_STAT_HACK
848
849 /* First attempt used DosQueryFSAttach which crashed the system when
850 used with 5.001. Now just look for /dev/. */
851
852int
853os2_stat(char *name, struct stat *st)
854{
855 static int ino = SHRT_MAX;
856
857 if (stricmp(name, "/dev/con") != 0
858 && stricmp(name, "/dev/tty") != 0)
859 return stat(name, st);
860
861 memset(st, 0, sizeof *st);
862 st->st_mode = S_IFCHR|0666;
863 st->st_ino = (ino-- & 0x7FFF);
864 st->st_nlink = 1;
865 return 0;
866}
867
868#endif
c0c09dfd 869
760ac839 870#ifdef USE_PERL_SBRK
c0c09dfd 871
760ac839 872/* SBRK() emulation, mostly moved to malloc.c. */
c0c09dfd 873
874void *
760ac839 875sys_alloc(int size) {
876 void *got;
877 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
878
c0c09dfd 879 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
880 return (void *) -1;
881 } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
760ac839 882 return got;
c0c09dfd 883}
760ac839 884
885#endif /* USE_PERL_SBRK */
c0c09dfd 886
887/* tmp path */
888
889char *tmppath = TMPPATH1;
890
891void
892settmppath()
893{
894 char *p = getenv("TMP"), *tpath;
895 int len;
896
897 if (!p) p = getenv("TEMP");
898 if (!p) return;
899 len = strlen(p);
900 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
901 strcpy(tpath, p);
902 tpath[len] = '/';
903 strcpy(tpath + len + 1, TMPPATH1);
904 tmppath = tpath;
905}
7a2f0d5b 906
907#include "XSUB.h"
908
909XS(XS_File__Copy_syscopy)
910{
911 dXSARGS;
912 if (items < 2 || items > 3)
913 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
914 {
915 char * src = (char *)SvPV(ST(0),na);
916 char * dst = (char *)SvPV(ST(1),na);
917 U32 flag;
918 int RETVAL, rc;
919
920 if (items < 3)
921 flag = 0;
922 else {
923 flag = (unsigned long)SvIV(ST(2));
924 }
925
6f064249 926 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
7a2f0d5b 927 ST(0) = sv_newmortal();
928 sv_setiv(ST(0), (IV)RETVAL);
929 }
930 XSRETURN(1);
931}
932
6f064249 933char *
934mod2fname(sv)
935 SV *sv;
936{
937 static char fname[9];
760ac839 938 int pos = 6, len, avlen;
939 unsigned int sum = 0;
6f064249 940 AV *av;
941 SV *svp;
942 char *s;
943
944 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
945 sv = SvRV(sv);
946 if (SvTYPE(sv) != SVt_PVAV)
947 croak("Not array reference given to mod2fname");
760ac839 948
949 avlen = av_len((AV*)sv);
950 if (avlen < 0)
6f064249 951 croak("Empty array reference given to mod2fname");
760ac839 952
953 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
6f064249 954 strncpy(fname, s, 8);
760ac839 955 len = strlen(s);
956 if (len < 6) pos = len;
957 while (*s) {
958 sum = 33 * sum + *(s++); /* Checksumming first chars to
959 * get the capitalization into c.s. */
960 }
961 avlen --;
962 while (avlen >= 0) {
963 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
964 while (*s) {
965 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
966 }
967 avlen --;
968 }
3aefca04 969#ifdef USE_THREADS
970 sum++; /* Avoid conflict of DLLs in memory. */
971#endif
760ac839 972 fname[pos] = 'A' + (sum % 26);
973 fname[pos + 1] = 'A' + (sum / 26 % 26);
974 fname[pos + 2] = '\0';
6f064249 975 return (char *)fname;
976}
977
978XS(XS_DynaLoader_mod2fname)
979{
980 dXSARGS;
981 if (items != 1)
982 croak("Usage: DynaLoader::mod2fname(sv)");
983 {
984 SV * sv = ST(0);
985 char * RETVAL;
986
987 RETVAL = mod2fname(sv);
988 ST(0) = sv_newmortal();
989 sv_setpv((SV*)ST(0), RETVAL);
990 }
991 XSRETURN(1);
992}
993
994char *
995os2error(int rc)
996{
997 static char buf[300];
998 ULONG len;
999
55497cff 1000 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
6f064249 1001 if (rc == 0)
1002 return NULL;
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);
1005 else
1006 buf[len] = '\0';
1007 return buf;
1008}
1009
760ac839 1010char *
1011perllib_mangle(char *s, unsigned int l)
1012{
1013 static char *newp, *oldp;
1014 static int newl, oldl, notfound;
1015 static char ret[STATIC_FILE_LENGTH+1];
1016
1017 if (!newp && !notfound) {
1018 newp = getenv("PERLLIB_PREFIX");
1019 if (newp) {
ff68c719 1020 char *s;
1021
760ac839 1022 oldp = newp;
89078e0f 1023 while (*newp && !isSPACE(*newp) && *newp != ';') {
760ac839 1024 newp++; oldl++; /* Skip digits. */
1025 }
1026 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1027 newp++; /* Skip whitespace. */
1028 }
1029 newl = strlen(newp);
1030 if (newl == 0 || oldl == 0) {
1031 die("Malformed PERLLIB_PREFIX");
1032 }
ff68c719 1033 strcpy(ret, newp);
1034 s = ret;
1035 while (*s) {
1036 if (*s == '\\') *s = '/';
1037 s++;
1038 }
760ac839 1039 } else {
1040 notfound = 1;
1041 }
1042 }
1043 if (!newp) {
1044 return s;
1045 }
1046 if (l == 0) {
1047 l = strlen(s);
1048 }
3bbf9c2b 1049 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
760ac839 1050 return s;
1051 }
1052 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1053 die("Malformed PERLLIB_PREFIX");
1054 }
89078e0f 1055 strcpy(ret + newl, s + oldl);
760ac839 1056 return ret;
1057}
6f064249 1058
1059extern void dlopen();
1060void *fakedl = &dlopen; /* Pull in dynaloading part. */
3bbf9c2b 1061
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
1067
1068#undef chdir /* Was _chdir2. */
1069#define sys_chdir(p) (chdir(p) == 0)
1070#define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1071
1072XS(XS_Cwd_current_drive)
1073{
1074 dXSARGS;
1075 if (items != 0)
1076 croak("Usage: Cwd::current_drive()");
1077 {
1078 char RETVAL;
1079
1080 RETVAL = current_drive();
1081 ST(0) = sv_newmortal();
1082 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1083 }
1084 XSRETURN(1);
1085}
1086
1087XS(XS_Cwd_sys_chdir)
1088{
1089 dXSARGS;
1090 if (items != 1)
1091 croak("Usage: Cwd::sys_chdir(path)");
1092 {
1093 char * path = (char *)SvPV(ST(0),na);
1094 bool RETVAL;
1095
1096 RETVAL = sys_chdir(path);
54310121 1097 ST(0) = boolSV(RETVAL);
3bbf9c2b 1098 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1099 }
1100 XSRETURN(1);
1101}
1102
1103XS(XS_Cwd_change_drive)
1104{
1105 dXSARGS;
1106 if (items != 1)
1107 croak("Usage: Cwd::change_drive(d)");
1108 {
1109 char d = (char)*SvPV(ST(0),na);
1110 bool RETVAL;
1111
1112 RETVAL = change_drive(d);
54310121 1113 ST(0) = boolSV(RETVAL);
3bbf9c2b 1114 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1115 }
1116 XSRETURN(1);
1117}
1118
1119XS(XS_Cwd_sys_is_absolute)
1120{
1121 dXSARGS;
1122 if (items != 1)
1123 croak("Usage: Cwd::sys_is_absolute(path)");
1124 {
1125 char * path = (char *)SvPV(ST(0),na);
1126 bool RETVAL;
1127
1128 RETVAL = sys_is_absolute(path);
54310121 1129 ST(0) = boolSV(RETVAL);
3bbf9c2b 1130 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1131 }
1132 XSRETURN(1);
1133}
1134
1135XS(XS_Cwd_sys_is_rooted)
1136{
1137 dXSARGS;
1138 if (items != 1)
1139 croak("Usage: Cwd::sys_is_rooted(path)");
1140 {
1141 char * path = (char *)SvPV(ST(0),na);
1142 bool RETVAL;
1143
1144 RETVAL = sys_is_rooted(path);
54310121 1145 ST(0) = boolSV(RETVAL);
3bbf9c2b 1146 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1147 }
1148 XSRETURN(1);
1149}
1150
1151XS(XS_Cwd_sys_is_relative)
1152{
1153 dXSARGS;
1154 if (items != 1)
1155 croak("Usage: Cwd::sys_is_relative(path)");
1156 {
1157 char * path = (char *)SvPV(ST(0),na);
1158 bool RETVAL;
1159
1160 RETVAL = sys_is_relative(path);
54310121 1161 ST(0) = boolSV(RETVAL);
3bbf9c2b 1162 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1163 }
1164 XSRETURN(1);
1165}
1166
1167XS(XS_Cwd_sys_cwd)
1168{
1169 dXSARGS;
1170 if (items != 0)
1171 croak("Usage: Cwd::sys_cwd()");
1172 {
1173 char p[MAXPATHLEN];
1174 char * RETVAL;
1175 RETVAL = _getcwd2(p, MAXPATHLEN);
1176 ST(0) = sv_newmortal();
1177 sv_setpv((SV*)ST(0), RETVAL);
1178 }
1179 XSRETURN(1);
1180}
1181
1182XS(XS_Cwd_sys_abspath)
1183{
1184 dXSARGS;
1185 if (items < 1 || items > 2)
1186 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1187 {
1188 char * path = (char *)SvPV(ST(0),na);
1189 char * dir;
1190 char p[MAXPATHLEN];
1191 char * RETVAL;
1192
1193 if (items < 2)
1194 dir = NULL;
1195 else {
1196 dir = (char *)SvPV(ST(1),na);
1197 }
1198 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1199 path += 2;
1200 }
1201 if (dir == NULL) {
1202 if (_abspath(p, path, MAXPATHLEN) == 0) {
1203 RETVAL = p;
1204 } else {
1205 RETVAL = NULL;
1206 }
1207 } else {
1208 /* Absolute with drive: */
1209 if ( sys_is_absolute(path) ) {
1210 if (_abspath(p, path, MAXPATHLEN) == 0) {
1211 RETVAL = p;
1212 } else {
1213 RETVAL = NULL;
1214 }
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];
1219
1220 /* Need to prepend the drive. */
1221 p1[0] = dir[0];
1222 p1[1] = dir[1];
1223 Copy(path, p1 + 2, strlen(path) + 1, char);
1224 RETVAL = p;
1225 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1226 RETVAL = p;
1227 } else {
1228 RETVAL = NULL;
1229 }
1230 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1231 RETVAL = p;
1232 } else {
1233 RETVAL = NULL;
1234 }
1235 } else {
1236 /* Either path is relative, or starts with a drive letter. */
1237 /* If the path starts with a drive letter, then dir is
1238 relevant only if
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
1242 of the path. */
1243 if ( !sys_is_relative(path) ) {
1244 int is_drived;
1245
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())) {
1252 path += 2;
1253 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1254 RETVAL = p; goto done;
1255 } else {
1256 RETVAL = NULL; goto done;
1257 }
1258 }
1259 {
1260 /* Need to prepend the absolute path of dir. */
1261 char p1[MAXPATHLEN];
1262
1263 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1264 int l = strlen(p1);
1265
1266 if (p1[ l - 1 ] != '/') {
1267 p1[ l ] = '/';
1268 l++;
1269 }
1270 Copy(path, p1 + l, strlen(path) + 1, char);
1271 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1272 RETVAL = p;
1273 } else {
1274 RETVAL = NULL;
1275 }
1276 } else {
1277 RETVAL = NULL;
1278 }
1279 }
1280 done:
1281 }
1282 }
1283 ST(0) = sv_newmortal();
1284 sv_setpv((SV*)ST(0), RETVAL);
1285 }
1286 XSRETURN(1);
1287}
72ea3524 1288typedef APIRET (*PELP)(PSZ path, ULONG type);
1289
1290APIRET
1291ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1292{
1293 loadByOrd(ord); /* Guarantied to load or die! */
1294 return (*(PELP)ExtFCN[ord])(path, type);
1295}
3bbf9c2b 1296
72ea3524 1297#define extLibpath(type) \
1298 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1299 : BEGIN_LIBPATH))) \
3bbf9c2b 1300 ? NULL : to )
1301
1302#define extLibpath_set(p,type) \
72ea3524 1303 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1304 : BEGIN_LIBPATH))))
3bbf9c2b 1305
1306XS(XS_Cwd_extLibpath)
1307{
1308 dXSARGS;
1309 if (items < 0 || items > 1)
1310 croak("Usage: Cwd::extLibpath(type = 0)");
1311 {
1312 bool type;
1313 char to[1024];
1314 U32 rc;
1315 char * RETVAL;
1316
1317 if (items < 1)
1318 type = 0;
1319 else {
1320 type = (int)SvIV(ST(0));
1321 }
1322
1323 RETVAL = extLibpath(type);
1324 ST(0) = sv_newmortal();
1325 sv_setpv((SV*)ST(0), RETVAL);
1326 }
1327 XSRETURN(1);
1328}
1329
1330XS(XS_Cwd_extLibpath_set)
1331{
1332 dXSARGS;
1333 if (items < 1 || items > 2)
1334 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1335 {
1336 char * s = (char *)SvPV(ST(0),na);
1337 bool type;
1338 U32 rc;
1339 bool RETVAL;
1340
1341 if (items < 2)
1342 type = 0;
1343 else {
1344 type = (int)SvIV(ST(1));
1345 }
1346
1347 RETVAL = extLibpath_set(s, type);
54310121 1348 ST(0) = boolSV(RETVAL);
3bbf9c2b 1349 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1350 }
1351 XSRETURN(1);
1352}
1353
1354int
1355Xs_OS2_init()
1356{
1357 char *file = __FILE__;
1358 {
1359 GV *gv;
55497cff 1360
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);
1365 }
3bbf9c2b 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);
3bbf9c2b 1375 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1376 GvMULTI_on(gv);
1377#ifdef PERL_IS_AOUT
1378 sv_setiv(GvSV(gv), 1);
1379#endif
1380 }
1381}
1382
1383OS2_Perl_data_t OS2_Perl_data;
1384
1385void
aa689395 1386Perl_OS2_init(char **env)
3bbf9c2b 1387{
1388 char *shell;
1389
18f739ee 1390 MALLOC_INIT;
3bbf9c2b 1391 settmppath();
1392 OS2_Perl_data.xs_init = &Xs_OS2_init;
aa689395 1393 if (environ == NULL) {
1394 environ = env;
1395 }
3bbf9c2b 1396 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
fc36a67e 1397 New(1304, sh_path, strlen(SH_PATH) + 1, char);
ff68c719 1398 strcpy(sh_path, SH_PATH);
3bbf9c2b 1399 sh_path[0] = shell[0];
1400 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
ff68c719 1401 int l = strlen(shell), i;
3bbf9c2b 1402 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1403 l--;
1404 }
fc36a67e 1405 New(1304, sh_path, l + 8, char);
3bbf9c2b 1406 strncpy(sh_path, shell, l);
1407 strcpy(sh_path + l, "/sh.exe");
ff68c719 1408 for (i = 0; i < l; i++) {
1409 if (sh_path[i] == '\\') sh_path[i] = '/';
1410 }
3bbf9c2b 1411 }
dd96f567 1412 MUTEX_INIT(&start_thread_mutex);
3bbf9c2b 1413}
1414
55497cff 1415#undef tmpnam
1416#undef tmpfile
1417
1418char *
1419my_tmpnam (char *str)
1420{
1421 char *p = getenv("TMP"), *tpath;
1422 int len;
1423
1424 if (!p) p = getenv("TEMP");
1425 tpath = tempnam(p, "pltmp");
1426 if (str && tpath) {
1427 strcpy(str, tpath);
1428 return str;
1429 }
1430 return tpath;
1431}
1432
1433FILE *
1434my_tmpfile ()
1435{
1436 struct stat s;
1437
1438 stat(".", &s);
1439 if (s.st_mode & S_IWOTH) {
1440 return tmpfile();
1441 }
1442 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
1443 grants TMP. */
1444}
367f3c24 1445
1446#undef flock
1447
1448/* This code was contributed by Rocco Caputo. */
1449int
dd96f567 1450my_flock(int handle, int o)
367f3c24 1451{
1452 FILELOCK rNull, rFull;
1453 ULONG timeout, handle_type, flag_word;
1454 APIRET rc;
1455 int blocking, shared;
1456 static int use_my = -1;
1457
1458 if (use_my == -1) {
1459 char *s = getenv("USE_PERL_FLOCK");
1460 if (s)
1461 use_my = atoi(s);
1462 else
1463 use_my = 1;
1464 }
1465 if (!(_emx_env & 0x200) || !use_my)
dd96f567 1466 return flock(handle, o); /* Delegate to EMX. */
367f3c24 1467
1468 // is this a file?
1469 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
1470 (handle_type & 0xFF))
1471 {
1472 errno = EBADF;
1473 return -1;
1474 }
1475 // set lock/unlock ranges
1476 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
1477 rFull.lRange = 0x7FFFFFFF;
1478 // set timeout for blocking
dd96f567 1479 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
367f3c24 1480 // shared or exclusive?
dd96f567 1481 shared = (o & LOCK_SH) ? 1 : 0;
367f3c24 1482 // do not block the unlock
dd96f567 1483 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
367f3c24 1484 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
1485 switch (rc) {
1486 case 0:
1487 errno = 0;
1488 return 0;
1489 case ERROR_INVALID_HANDLE:
1490 errno = EBADF;
1491 return -1;
1492 case ERROR_SHARING_BUFFER_EXCEEDED:
1493 errno = ENOLCK;
1494 return -1;
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:
1500 errno = EINVAL;
1501 return -1;
1502 case ERROR_INTERRUPT:
1503 errno = EINTR;
1504 return -1;
1505 default:
1506 errno = EINVAL;
1507 return -1;
1508 }
1509 }
1510 // lock may block
dd96f567 1511 if (o & (LOCK_SH | LOCK_EX)) {
367f3c24 1512 // for blocking operations
1513 for (;;) {
1514 rc =
1515 DosSetFileLocks(
1516 handle,
1517 &rNull,
1518 &rFull,
1519 timeout,
1520 shared
1521 );
1522 switch (rc) {
1523 case 0:
1524 errno = 0;
1525 return 0;
1526 case ERROR_INVALID_HANDLE:
1527 errno = EBADF;
1528 return -1;
1529 case ERROR_SHARING_BUFFER_EXCEEDED:
1530 errno = ENOLCK;
1531 return -1;
1532 case ERROR_LOCK_VIOLATION:
1533 if (!blocking) {
1534 errno = EWOULDBLOCK;
1535 return -1;
1536 }
1537 break;
1538 case ERROR_INVALID_PARAMETER:
1539 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
1540 case ERROR_READ_LOCKS_NOT_SUPPORTED:
1541 errno = EINVAL;
1542 return -1;
1543 case ERROR_INTERRUPT:
1544 errno = EINTR;
1545 return -1;
1546 default:
1547 errno = EINVAL;
1548 return -1;
1549 }
1550 // give away timeslice
1551 DosSleep(1);
1552 }
1553 }
1554
1555 errno = 0;
1556 return 0;
1557}