[shell changes from patch from perl5.003_22 to perl5.003_23]
[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
21/*****************************************************************************/
72ea3524 22/* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
23static PFN ExtFCN[2]; /* Labeled by ord below. */
24static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
25#define ORD_QUERY_ELP 0
26#define ORD_SET_ELP 1
27
28APIRET
29loadByOrd(ULONG ord)
30{
31 if (ExtFCN[ord] == NULL) {
32 static HMODULE hdosc = 0;
33 BYTE buf[20];
34 PFN fcn;
35 APIRET rc;
36
37 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
38 "doscalls", &hdosc)))
39 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
40 die("This version of OS/2 does not support doscalls.%i",
41 loadOrd[ord]);
42 ExtFCN[ord] = fcn;
43 }
44 if ((long)ExtFCN[ord] == -1) die("panic queryaddr");
45}
46
4633a7c4 47/* priorities */
6f064249 48static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
49 self inverse. */
50#define QSS_INI_BUFFER 1024
4633a7c4 51
6f064249 52PQTOPLEVEL
53get_sysinfo(ULONG pid, ULONG flags)
4633a7c4 54{
6f064249 55 char *pbuffer;
56 ULONG rc, buf_len = QSS_INI_BUFFER;
57
58 New(1022, pbuffer, buf_len, char);
59 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
60 rc = QuerySysState(flags, pid, pbuffer, buf_len);
61 while (rc == ERROR_BUFFER_OVERFLOW) {
62 Renew(pbuffer, buf_len *= 2, char);
df3ef7a9 63 rc = QuerySysState(flags, pid, pbuffer, buf_len);
6f064249 64 }
65 if (rc) {
66 FillOSError(rc);
67 Safefree(pbuffer);
68 return 0;
69 }
70 return (PQTOPLEVEL)pbuffer;
71}
72
73#define PRIO_ERR 0x1111
74
75static ULONG
76sys_prio(pid)
77{
78 ULONG prio;
79 PQTOPLEVEL psi;
80
81 psi = get_sysinfo(pid, QSS_PROCESS);
82 if (!psi) {
83 return PRIO_ERR;
84 }
85 if (pid != psi->procdata->pid) {
86 Safefree(psi);
87 croak("panic: wrong pid in sysinfo");
88 }
89 prio = psi->procdata->threads->priority;
90 Safefree(psi);
91 return prio;
92}
93
94int
95setpriority(int which, int pid, int val)
96{
97 ULONG rc, prio;
98 PQTOPLEVEL psi;
99
100 prio = sys_prio(pid);
101
55497cff 102 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
6f064249 103 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
104 /* Do not change class. */
105 return CheckOSError(DosSetPriority((pid < 0)
106 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
107 0,
108 (32 - val) % 32 - (prio & 0xFF),
109 abs(pid)))
110 ? -1 : 0;
111 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
112 /* Documentation claims one can change both class and basevalue,
113 * but I find it wrong. */
114 /* Change class, but since delta == 0 denotes absolute 0, correct. */
115 if (CheckOSError(DosSetPriority((pid < 0)
116 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
117 priors[(32 - val) >> 5] + 1,
118 0,
119 abs(pid))))
120 return -1;
121 if ( ((32 - val) % 32) == 0 ) return 0;
122 return CheckOSError(DosSetPriority((pid < 0)
123 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
124 0,
125 (32 - val) % 32,
126 abs(pid)))
127 ? -1 : 0;
128 }
129/* else return CheckOSError(DosSetPriority((pid < 0) */
130/* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
131/* priors[(32 - val) >> 5] + 1, */
132/* (32 - val) % 32 - (prio & 0xFF), */
133/* abs(pid))) */
134/* ? -1 : 0; */
4633a7c4 135}
136
6f064249 137int
138getpriority(int which /* ignored */, int pid)
4633a7c4 139{
140 TIB *tib;
141 PIB *pib;
6f064249 142 ULONG rc, ret;
143
55497cff 144 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
6f064249 145 /* DosGetInfoBlocks has old priority! */
146/* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
147/* if (pid != pib->pib_ulpid) { */
148 ret = sys_prio(pid);
149 if (ret == PRIO_ERR) {
150 return -1;
151 }
152/* } else */
153/* ret = tib->tib_ptib2->tib2_ulpri; */
154 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
4633a7c4 155}
156
157/*****************************************************************************/
158/* spawn */
72ea3524 159typedef void (*Sigfunc) _((int));
160
4633a7c4 161static int
162result(int flag, int pid)
163{
164 int r, status;
165 Signal_t (*ihand)(); /* place to save signal during system() */
166 Signal_t (*qhand)(); /* place to save signal during system() */
760ac839 167#ifndef __EMX__
168 RESULTCODES res;
169 int rpid;
170#endif
4633a7c4 171
760ac839 172 if (pid < 0 || flag != 0)
4633a7c4 173 return pid;
174
760ac839 175#ifdef __EMX__
72ea3524 176 ihand = rsignal(SIGINT, SIG_IGN);
177 qhand = rsignal(SIGQUIT, SIG_IGN);
c0c09dfd 178 do {
179 r = wait4pid(pid, &status, 0);
180 } while (r == -1 && errno == EINTR);
72ea3524 181 rsignal(SIGINT, ihand);
182 rsignal(SIGQUIT, qhand);
4633a7c4 183
184 statusvalue = (U16)status;
185 if (r < 0)
186 return -1;
187 return status & 0xFFFF;
760ac839 188#else
72ea3524 189 ihand = rsignal(SIGINT, SIG_IGN);
760ac839 190 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
72ea3524 191 rsignal(SIGINT, ihand);
760ac839 192 statusvalue = res.codeResult << 8 | res.codeTerminate;
193 if (r)
194 return -1;
195 return statusvalue;
196#endif
4633a7c4 197}
198
199int
200do_aspawn(really,mark,sp)
201SV *really;
202register SV **mark;
203register SV **sp;
204{
205 register char **a;
206 char *tmps;
207 int rc;
208 int flag = P_WAIT, trueflag;
209
210 if (sp > mark) {
211 New(401,Argv, sp - mark + 1, char*);
212 a = Argv;
213
760ac839 214 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
4633a7c4 215 ++mark;
216 flag = SvIVx(*mark);
217 }
218
219 while (++mark <= sp) {
220 if (*mark)
221 *a++ = SvPVx(*mark, na);
222 else
223 *a++ = "";
224 }
225 *a = Nullch;
226
227 trueflag = flag;
228 if (flag == P_WAIT)
229 flag = P_NOWAIT;
230
ff68c719 231 if (strEQ(Argv[0],"/bin/sh")) Argv[0] = sh_path;
3bbf9c2b 232
233 if (Argv[0][0] != '/' && Argv[0][0] != '\\'
234 && !(Argv[0][0] && Argv[0][1] == ':'
235 && (Argv[0][2] == '/' || Argv[0][2] != '\\'))
760ac839 236 ) /* will swawnvp use PATH? */
c0c09dfd 237 TAINT_ENV(); /* testing IFS here is overkill, probably */
760ac839 238 /* We should check PERL_SH* and PERLLIB_* as well? */
4633a7c4 239 if (really && *(tmps = SvPV(really, na)))
240 rc = result(trueflag, spawnvp(flag,tmps,Argv));
241 else
242 rc = result(trueflag, spawnvp(flag,Argv[0],Argv));
243
244 if (rc < 0 && dowarn)
245 warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
c0c09dfd 246 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
4633a7c4 247 } else
248 rc = -1;
249 do_execfree();
250 return rc;
251}
252
760ac839 253#define EXECF_SPAWN 0
254#define EXECF_EXEC 1
255#define EXECF_TRUEEXEC 2
72ea3524 256#define EXECF_SPAWN_NOWAIT 3
760ac839 257
4633a7c4 258int
760ac839 259do_spawn2(cmd, execf)
4633a7c4 260char *cmd;
760ac839 261int execf;
4633a7c4 262{
263 register char **a;
264 register char *s;
265 char flags[10];
3bbf9c2b 266 char *shell, *copt, *news = NULL;
4633a7c4 267 int rc;
268
c0c09dfd 269#ifdef TRYSHELL
270 if ((shell = getenv("EMXSHELL")) != NULL)
271 copt = "-c";
272 else if ((shell = getenv("SHELL")) != NULL)
4633a7c4 273 copt = "-c";
274 else if ((shell = getenv("COMSPEC")) != NULL)
275 copt = "/C";
276 else
277 shell = "cmd.exe";
c0c09dfd 278#else
279 /* Consensus on perl5-porters is that it is _very_ important to
280 have a shell which will not change between computers with the
281 same architecture, to avoid "action on a distance".
282 And to have simple build, this shell should be sh. */
ff68c719 283 shell = sh_path;
c0c09dfd 284 copt = "-c";
285#endif
286
287 while (*cmd && isSPACE(*cmd))
288 cmd++;
4633a7c4 289
3bbf9c2b 290 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
ff68c719 291 STRLEN l = strlen(sh_path);
3bbf9c2b 292
293 New(4545, news, strlen(cmd) - 7 + l, char);
ff68c719 294 strcpy(news, sh_path);
3bbf9c2b 295 strcpy(news + l, cmd + 7);
296 cmd = news;
297 }
298
4633a7c4 299 /* save an extra exec if possible */
300 /* see if there are shell metacharacters in it */
301
c0c09dfd 302 if (*cmd == '.' && isSPACE(cmd[1]))
303 goto doshell;
304
305 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
306 goto doshell;
307
308 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
309 if (*s == '=')
310 goto doshell;
311
4633a7c4 312 for (s = cmd; *s; s++) {
c0c09dfd 313 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
3bbf9c2b 314 if (*s == '\n' && s[1] == '\0') {
4633a7c4 315 *s = '\0';
316 break;
317 }
c0c09dfd 318 doshell:
760ac839 319 if (execf == EXECF_TRUEEXEC)
320 return execl(shell,shell,copt,cmd,(char*)0);
321 else if (execf == EXECF_EXEC)
322 return spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
72ea3524 323 else if (execf == EXECF_SPAWN_NOWAIT)
324 return spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
760ac839 325 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
c0c09dfd 326 rc = result(P_WAIT,
760ac839 327 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
c0c09dfd 328 if (rc < 0 && dowarn)
760ac839 329 warn("Can't %s \"%s\": %s",
330 (execf == EXECF_SPAWN ? "spawn" : "exec"),
331 shell, Strerror(errno));
c0c09dfd 332 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
3bbf9c2b 333 if (news) Safefree(news);
c0c09dfd 334 return rc;
4633a7c4 335 }
336 }
c0c09dfd 337
4633a7c4 338 New(402,Argv, (s - cmd) / 2 + 2, char*);
339 Cmd = savepvn(cmd, s-cmd);
340 a = Argv;
341 for (s = Cmd; *s;) {
342 while (*s && isSPACE(*s)) s++;
343 if (*s)
344 *(a++) = s;
345 while (*s && !isSPACE(*s)) s++;
346 if (*s)
347 *s++ = '\0';
348 }
349 *a = Nullch;
350 if (Argv[0]) {
760ac839 351 if (execf == EXECF_TRUEEXEC)
352 rc = execvp(Argv[0],Argv);
353 else if (execf == EXECF_EXEC)
354 rc = spawnvp(P_OVERLAY,Argv[0],Argv);
72ea3524 355 else if (execf == EXECF_SPAWN_NOWAIT)
356 rc = spawnvp(P_NOWAIT,Argv[0],Argv);
760ac839 357 else
358 rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
4633a7c4 359 if (rc < 0 && dowarn)
760ac839 360 warn("Can't %s \"%s\": %s",
361 (execf == EXECF_SPAWN ? "spawn" : "exec"),
362 Argv[0], Strerror(errno));
c0c09dfd 363 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
4633a7c4 364 } else
365 rc = -1;
3bbf9c2b 366 if (news) Safefree(news);
4633a7c4 367 do_execfree();
368 return rc;
369}
370
760ac839 371int
372do_spawn(cmd)
373char *cmd;
374{
375 return do_spawn2(cmd, EXECF_SPAWN);
376}
377
72ea3524 378int
379do_spawn_nowait(cmd)
380char *cmd;
381{
382 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
383}
384
760ac839 385bool
386do_exec(cmd)
387char *cmd;
388{
389 return do_spawn2(cmd, EXECF_EXEC);
390}
391
392bool
393os2exec(cmd)
394char *cmd;
395{
396 return do_spawn2(cmd, EXECF_TRUEEXEC);
397}
398
3bbf9c2b 399PerlIO *
400my_syspopen(cmd,mode)
c0c09dfd 401char *cmd;
402char *mode;
403{
72ea3524 404#ifndef USE_POPEN
405
406 int p[2];
407 register I32 this, that, newfd;
408 register I32 pid, rc;
3bbf9c2b 409 PerlIO *res;
410 SV *sv;
72ea3524 411
412 if (pipe(p) < 0)
413 return Nullfp;
414 /* `this' is what we use in the parent, `that' in the child. */
415 this = (*mode == 'w');
416 that = !this;
417 if (tainting) {
418 taint_env();
419 taint_proper("Insecure %s%s", "EXEC");
420 }
421 /* Now we need to spawn the child. */
422 newfd = dup(*mode == 'r'); /* Preserve std* */
423 if (p[that] != (*mode == 'r')) {
424 dup2(p[that], *mode == 'r');
425 close(p[that]);
426 }
427 /* Where is `this' and newfd now? */
428 fcntl(p[this], F_SETFD, FD_CLOEXEC);
429 fcntl(newfd, F_SETFD, FD_CLOEXEC);
430 pid = do_spawn_nowait(cmd);
431 if (newfd != (*mode == 'r')) {
432 dup2(newfd, *mode == 'r'); /* Return std* back. */
433 close(newfd);
434 }
435 close(p[that]);
436 if (pid == -1) {
437 close(p[this]);
438 return NULL;
439 }
440 if (p[that] < p[this]) {
441 dup2(p[this], p[that]);
442 close(p[this]);
443 p[this] = p[that];
444 }
445 sv = *av_fetch(fdpid,p[this],TRUE);
446 (void)SvUPGRADE(sv,SVt_IV);
447 SvIVX(sv) = pid;
448 forkprocess = pid;
449 return PerlIO_fdopen(p[this], mode);
3bbf9c2b 450
72ea3524 451#else /* USE_POPEN */
452
453 PerlIO *res;
454 SV *sv;
455
456# ifdef TRYSHELL
3bbf9c2b 457 res = popen(cmd, mode);
72ea3524 458# else
c0c09dfd 459 char *shell = getenv("EMXSHELL");
3bbf9c2b 460
ff68c719 461 my_setenv("EMXSHELL", sh_path);
c0c09dfd 462 res = popen(cmd, mode);
463 my_setenv("EMXSHELL", shell);
72ea3524 464# endif
3bbf9c2b 465 sv = *av_fetch(fdpid, PerlIO_fileno(res), TRUE);
466 (void)SvUPGRADE(sv,SVt_IV);
467 SvIVX(sv) = -1; /* A cooky. */
468 return res;
72ea3524 469
470#endif /* USE_POPEN */
471
c0c09dfd 472}
473
3bbf9c2b 474/******************************************************************/
4633a7c4 475
476#ifndef HAS_FORK
477int
478fork(void)
479{
480 die(no_func, "Unsupported function fork");
481 errno = EINVAL;
482 return -1;
483}
484#endif
485
3bbf9c2b 486/*******************************************************************/
4633a7c4 487/* not implemented in EMX 0.9a */
488
489void * ctermid(x) { return 0; }
eacfb5f1 490
491#ifdef MYTTYNAME /* was not in emx0.9a */
4633a7c4 492void * ttyname(x) { return 0; }
eacfb5f1 493#endif
4633a7c4 494
3bbf9c2b 495/******************************************************************/
760ac839 496/* my socket forwarders - EMX lib only provides static forwarders */
497
498static HMODULE htcp = 0;
499
500static void *
501tcp0(char *name)
502{
503 static BYTE buf[20];
504 PFN fcn;
55497cff 505
506 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
760ac839 507 if (!htcp)
508 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
509 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
510 return (void *) ((void * (*)(void)) fcn) ();
511 return 0;
512}
513
514static void
515tcp1(char *name, int arg)
516{
517 static BYTE buf[20];
518 PFN fcn;
55497cff 519
520 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
760ac839 521 if (!htcp)
522 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
523 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
524 ((void (*)(int)) fcn) (arg);
525}
526
527void * gethostent() { return tcp0("GETHOSTENT"); }
528void * getnetent() { return tcp0("GETNETENT"); }
529void * getprotoent() { return tcp0("GETPROTOENT"); }
530void * getservent() { return tcp0("GETSERVENT"); }
531void sethostent(x) { tcp1("SETHOSTENT", x); }
532void setnetent(x) { tcp1("SETNETENT", x); }
533void setprotoent(x) { tcp1("SETPROTOENT", x); }
534void setservent(x) { tcp1("SETSERVENT", x); }
535void endhostent() { tcp0("ENDHOSTENT"); }
536void endnetent() { tcp0("ENDNETENT"); }
537void endprotoent() { tcp0("ENDPROTOENT"); }
538void endservent() { tcp0("ENDSERVENT"); }
539
540/*****************************************************************************/
541/* not implemented in C Set++ */
542
543#ifndef __EMX__
544int setuid(x) { errno = EINVAL; return -1; }
545int setgid(x) { errno = EINVAL; return -1; }
546#endif
4633a7c4 547
548/*****************************************************************************/
549/* stat() hack for char/block device */
550
551#if OS2_STAT_HACK
552
553 /* First attempt used DosQueryFSAttach which crashed the system when
554 used with 5.001. Now just look for /dev/. */
555
556int
557os2_stat(char *name, struct stat *st)
558{
559 static int ino = SHRT_MAX;
560
561 if (stricmp(name, "/dev/con") != 0
562 && stricmp(name, "/dev/tty") != 0)
563 return stat(name, st);
564
565 memset(st, 0, sizeof *st);
566 st->st_mode = S_IFCHR|0666;
567 st->st_ino = (ino-- & 0x7FFF);
568 st->st_nlink = 1;
569 return 0;
570}
571
572#endif
c0c09dfd 573
760ac839 574#ifdef USE_PERL_SBRK
c0c09dfd 575
760ac839 576/* SBRK() emulation, mostly moved to malloc.c. */
c0c09dfd 577
578void *
760ac839 579sys_alloc(int size) {
580 void *got;
581 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
582
c0c09dfd 583 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
584 return (void *) -1;
585 } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
760ac839 586 return got;
c0c09dfd 587}
760ac839 588
589#endif /* USE_PERL_SBRK */
c0c09dfd 590
591/* tmp path */
592
593char *tmppath = TMPPATH1;
594
595void
596settmppath()
597{
598 char *p = getenv("TMP"), *tpath;
599 int len;
600
601 if (!p) p = getenv("TEMP");
602 if (!p) return;
603 len = strlen(p);
604 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
605 strcpy(tpath, p);
606 tpath[len] = '/';
607 strcpy(tpath + len + 1, TMPPATH1);
608 tmppath = tpath;
609}
7a2f0d5b 610
611#include "XSUB.h"
612
613XS(XS_File__Copy_syscopy)
614{
615 dXSARGS;
616 if (items < 2 || items > 3)
617 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
618 {
619 char * src = (char *)SvPV(ST(0),na);
620 char * dst = (char *)SvPV(ST(1),na);
621 U32 flag;
622 int RETVAL, rc;
623
624 if (items < 3)
625 flag = 0;
626 else {
627 flag = (unsigned long)SvIV(ST(2));
628 }
629
6f064249 630 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
7a2f0d5b 631 ST(0) = sv_newmortal();
632 sv_setiv(ST(0), (IV)RETVAL);
633 }
634 XSRETURN(1);
635}
636
6f064249 637char *
638mod2fname(sv)
639 SV *sv;
640{
641 static char fname[9];
760ac839 642 int pos = 6, len, avlen;
643 unsigned int sum = 0;
6f064249 644 AV *av;
645 SV *svp;
646 char *s;
647
648 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
649 sv = SvRV(sv);
650 if (SvTYPE(sv) != SVt_PVAV)
651 croak("Not array reference given to mod2fname");
760ac839 652
653 avlen = av_len((AV*)sv);
654 if (avlen < 0)
6f064249 655 croak("Empty array reference given to mod2fname");
760ac839 656
657 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
6f064249 658 strncpy(fname, s, 8);
760ac839 659 len = strlen(s);
660 if (len < 6) pos = len;
661 while (*s) {
662 sum = 33 * sum + *(s++); /* Checksumming first chars to
663 * get the capitalization into c.s. */
664 }
665 avlen --;
666 while (avlen >= 0) {
667 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), na);
668 while (*s) {
669 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
670 }
671 avlen --;
672 }
673 fname[pos] = 'A' + (sum % 26);
674 fname[pos + 1] = 'A' + (sum / 26 % 26);
675 fname[pos + 2] = '\0';
6f064249 676 return (char *)fname;
677}
678
679XS(XS_DynaLoader_mod2fname)
680{
681 dXSARGS;
682 if (items != 1)
683 croak("Usage: DynaLoader::mod2fname(sv)");
684 {
685 SV * sv = ST(0);
686 char * RETVAL;
687
688 RETVAL = mod2fname(sv);
689 ST(0) = sv_newmortal();
690 sv_setpv((SV*)ST(0), RETVAL);
691 }
692 XSRETURN(1);
693}
694
695char *
696os2error(int rc)
697{
698 static char buf[300];
699 ULONG len;
700
55497cff 701 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
6f064249 702 if (rc == 0)
703 return NULL;
704 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
705 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
706 else
707 buf[len] = '\0';
708 return buf;
709}
710
760ac839 711char *
712perllib_mangle(char *s, unsigned int l)
713{
714 static char *newp, *oldp;
715 static int newl, oldl, notfound;
716 static char ret[STATIC_FILE_LENGTH+1];
717
718 if (!newp && !notfound) {
719 newp = getenv("PERLLIB_PREFIX");
720 if (newp) {
ff68c719 721 char *s;
722
760ac839 723 oldp = newp;
89078e0f 724 while (*newp && !isSPACE(*newp) && *newp != ';') {
760ac839 725 newp++; oldl++; /* Skip digits. */
726 }
727 while (*newp && (isSPACE(*newp) || *newp == ';')) {
728 newp++; /* Skip whitespace. */
729 }
730 newl = strlen(newp);
731 if (newl == 0 || oldl == 0) {
732 die("Malformed PERLLIB_PREFIX");
733 }
ff68c719 734 strcpy(ret, newp);
735 s = ret;
736 while (*s) {
737 if (*s == '\\') *s = '/';
738 s++;
739 }
760ac839 740 } else {
741 notfound = 1;
742 }
743 }
744 if (!newp) {
745 return s;
746 }
747 if (l == 0) {
748 l = strlen(s);
749 }
3bbf9c2b 750 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
760ac839 751 return s;
752 }
753 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
754 die("Malformed PERLLIB_PREFIX");
755 }
89078e0f 756 strcpy(ret + newl, s + oldl);
760ac839 757 return ret;
758}
6f064249 759
760extern void dlopen();
761void *fakedl = &dlopen; /* Pull in dynaloading part. */
3bbf9c2b 762
763#define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
764 && ((path)[2] == '/' || (path)[2] == '\\'))
765#define sys_is_rooted _fnisabs
766#define sys_is_relative _fnisrel
767#define current_drive _getdrive
768
769#undef chdir /* Was _chdir2. */
770#define sys_chdir(p) (chdir(p) == 0)
771#define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
772
773XS(XS_Cwd_current_drive)
774{
775 dXSARGS;
776 if (items != 0)
777 croak("Usage: Cwd::current_drive()");
778 {
779 char RETVAL;
780
781 RETVAL = current_drive();
782 ST(0) = sv_newmortal();
783 sv_setpvn(ST(0), (char *)&RETVAL, 1);
784 }
785 XSRETURN(1);
786}
787
788XS(XS_Cwd_sys_chdir)
789{
790 dXSARGS;
791 if (items != 1)
792 croak("Usage: Cwd::sys_chdir(path)");
793 {
794 char * path = (char *)SvPV(ST(0),na);
795 bool RETVAL;
796
797 RETVAL = sys_chdir(path);
798 ST(0) = RETVAL ? &sv_yes : &sv_no;
799 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
800 }
801 XSRETURN(1);
802}
803
804XS(XS_Cwd_change_drive)
805{
806 dXSARGS;
807 if (items != 1)
808 croak("Usage: Cwd::change_drive(d)");
809 {
810 char d = (char)*SvPV(ST(0),na);
811 bool RETVAL;
812
813 RETVAL = change_drive(d);
814 ST(0) = RETVAL ? &sv_yes : &sv_no;
815 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
816 }
817 XSRETURN(1);
818}
819
820XS(XS_Cwd_sys_is_absolute)
821{
822 dXSARGS;
823 if (items != 1)
824 croak("Usage: Cwd::sys_is_absolute(path)");
825 {
826 char * path = (char *)SvPV(ST(0),na);
827 bool RETVAL;
828
829 RETVAL = sys_is_absolute(path);
830 ST(0) = RETVAL ? &sv_yes : &sv_no;
831 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
832 }
833 XSRETURN(1);
834}
835
836XS(XS_Cwd_sys_is_rooted)
837{
838 dXSARGS;
839 if (items != 1)
840 croak("Usage: Cwd::sys_is_rooted(path)");
841 {
842 char * path = (char *)SvPV(ST(0),na);
843 bool RETVAL;
844
845 RETVAL = sys_is_rooted(path);
846 ST(0) = RETVAL ? &sv_yes : &sv_no;
847 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
848 }
849 XSRETURN(1);
850}
851
852XS(XS_Cwd_sys_is_relative)
853{
854 dXSARGS;
855 if (items != 1)
856 croak("Usage: Cwd::sys_is_relative(path)");
857 {
858 char * path = (char *)SvPV(ST(0),na);
859 bool RETVAL;
860
861 RETVAL = sys_is_relative(path);
862 ST(0) = RETVAL ? &sv_yes : &sv_no;
863 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
864 }
865 XSRETURN(1);
866}
867
868XS(XS_Cwd_sys_cwd)
869{
870 dXSARGS;
871 if (items != 0)
872 croak("Usage: Cwd::sys_cwd()");
873 {
874 char p[MAXPATHLEN];
875 char * RETVAL;
876 RETVAL = _getcwd2(p, MAXPATHLEN);
877 ST(0) = sv_newmortal();
878 sv_setpv((SV*)ST(0), RETVAL);
879 }
880 XSRETURN(1);
881}
882
883XS(XS_Cwd_sys_abspath)
884{
885 dXSARGS;
886 if (items < 1 || items > 2)
887 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
888 {
889 char * path = (char *)SvPV(ST(0),na);
890 char * dir;
891 char p[MAXPATHLEN];
892 char * RETVAL;
893
894 if (items < 2)
895 dir = NULL;
896 else {
897 dir = (char *)SvPV(ST(1),na);
898 }
899 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
900 path += 2;
901 }
902 if (dir == NULL) {
903 if (_abspath(p, path, MAXPATHLEN) == 0) {
904 RETVAL = p;
905 } else {
906 RETVAL = NULL;
907 }
908 } else {
909 /* Absolute with drive: */
910 if ( sys_is_absolute(path) ) {
911 if (_abspath(p, path, MAXPATHLEN) == 0) {
912 RETVAL = p;
913 } else {
914 RETVAL = NULL;
915 }
916 } else if (path[0] == '/' || path[0] == '\\') {
917 /* Rooted, but maybe on different drive. */
918 if (isALPHA(dir[0]) && dir[1] == ':' ) {
919 char p1[MAXPATHLEN];
920
921 /* Need to prepend the drive. */
922 p1[0] = dir[0];
923 p1[1] = dir[1];
924 Copy(path, p1 + 2, strlen(path) + 1, char);
925 RETVAL = p;
926 if (_abspath(p, p1, MAXPATHLEN) == 0) {
927 RETVAL = p;
928 } else {
929 RETVAL = NULL;
930 }
931 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
932 RETVAL = p;
933 } else {
934 RETVAL = NULL;
935 }
936 } else {
937 /* Either path is relative, or starts with a drive letter. */
938 /* If the path starts with a drive letter, then dir is
939 relevant only if
940 a/b) it is absolute/x:relative on the same drive.
941 c) path is on current drive, and dir is rooted
942 In all the cases it is safe to drop the drive part
943 of the path. */
944 if ( !sys_is_relative(path) ) {
945 int is_drived;
946
947 if ( ( ( sys_is_absolute(dir)
948 || (isALPHA(dir[0]) && dir[1] == ':'
949 && strnicmp(dir, path,1) == 0))
950 && strnicmp(dir, path,1) == 0)
951 || ( !(isALPHA(dir[0]) && dir[1] == ':')
952 && toupper(path[0]) == current_drive())) {
953 path += 2;
954 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
955 RETVAL = p; goto done;
956 } else {
957 RETVAL = NULL; goto done;
958 }
959 }
960 {
961 /* Need to prepend the absolute path of dir. */
962 char p1[MAXPATHLEN];
963
964 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
965 int l = strlen(p1);
966
967 if (p1[ l - 1 ] != '/') {
968 p1[ l ] = '/';
969 l++;
970 }
971 Copy(path, p1 + l, strlen(path) + 1, char);
972 if (_abspath(p, p1, MAXPATHLEN) == 0) {
973 RETVAL = p;
974 } else {
975 RETVAL = NULL;
976 }
977 } else {
978 RETVAL = NULL;
979 }
980 }
981 done:
982 }
983 }
984 ST(0) = sv_newmortal();
985 sv_setpv((SV*)ST(0), RETVAL);
986 }
987 XSRETURN(1);
988}
72ea3524 989typedef APIRET (*PELP)(PSZ path, ULONG type);
990
991APIRET
992ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
993{
994 loadByOrd(ord); /* Guarantied to load or die! */
995 return (*(PELP)ExtFCN[ord])(path, type);
996}
3bbf9c2b 997
72ea3524 998#define extLibpath(type) \
999 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1000 : BEGIN_LIBPATH))) \
3bbf9c2b 1001 ? NULL : to )
1002
1003#define extLibpath_set(p,type) \
72ea3524 1004 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1005 : BEGIN_LIBPATH))))
3bbf9c2b 1006
1007XS(XS_Cwd_extLibpath)
1008{
1009 dXSARGS;
1010 if (items < 0 || items > 1)
1011 croak("Usage: Cwd::extLibpath(type = 0)");
1012 {
1013 bool type;
1014 char to[1024];
1015 U32 rc;
1016 char * RETVAL;
1017
1018 if (items < 1)
1019 type = 0;
1020 else {
1021 type = (int)SvIV(ST(0));
1022 }
1023
1024 RETVAL = extLibpath(type);
1025 ST(0) = sv_newmortal();
1026 sv_setpv((SV*)ST(0), RETVAL);
1027 }
1028 XSRETURN(1);
1029}
1030
1031XS(XS_Cwd_extLibpath_set)
1032{
1033 dXSARGS;
1034 if (items < 1 || items > 2)
1035 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1036 {
1037 char * s = (char *)SvPV(ST(0),na);
1038 bool type;
1039 U32 rc;
1040 bool RETVAL;
1041
1042 if (items < 2)
1043 type = 0;
1044 else {
1045 type = (int)SvIV(ST(1));
1046 }
1047
1048 RETVAL = extLibpath_set(s, type);
1049 ST(0) = RETVAL ? &sv_yes : &sv_no;
1050 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1051 }
1052 XSRETURN(1);
1053}
1054
1055int
1056Xs_OS2_init()
1057{
1058 char *file = __FILE__;
1059 {
1060 GV *gv;
55497cff 1061
1062 if (_emx_env & 0x200) { /* OS/2 */
1063 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
1064 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
1065 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
1066 }
3bbf9c2b 1067 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
1068 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
1069 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
1070 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
1071 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
1072 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
1073 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
1074 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
1075 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
3bbf9c2b 1076 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1077 GvMULTI_on(gv);
1078#ifdef PERL_IS_AOUT
1079 sv_setiv(GvSV(gv), 1);
1080#endif
1081 }
1082}
1083
1084OS2_Perl_data_t OS2_Perl_data;
1085
1086void
1087Perl_OS2_init()
1088{
1089 char *shell;
1090
1091 settmppath();
1092 OS2_Perl_data.xs_init = &Xs_OS2_init;
1093 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
ff68c719 1094 New(404, sh_path, strlen(SH_PATH) + 1, char);
1095 strcpy(sh_path, SH_PATH);
3bbf9c2b 1096 sh_path[0] = shell[0];
1097 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
ff68c719 1098 int l = strlen(shell), i;
3bbf9c2b 1099 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1100 l--;
1101 }
ff68c719 1102 New(404, sh_path, l + 8, char);
3bbf9c2b 1103 strncpy(sh_path, shell, l);
1104 strcpy(sh_path + l, "/sh.exe");
ff68c719 1105 for (i = 0; i < l; i++) {
1106 if (sh_path[i] == '\\') sh_path[i] = '/';
1107 }
3bbf9c2b 1108 }
1109}
1110
55497cff 1111#undef tmpnam
1112#undef tmpfile
1113
1114char *
1115my_tmpnam (char *str)
1116{
1117 char *p = getenv("TMP"), *tpath;
1118 int len;
1119
1120 if (!p) p = getenv("TEMP");
1121 tpath = tempnam(p, "pltmp");
1122 if (str && tpath) {
1123 strcpy(str, tpath);
1124 return str;
1125 }
1126 return tpath;
1127}
1128
1129FILE *
1130my_tmpfile ()
1131{
1132 struct stat s;
1133
1134 stat(".", &s);
1135 if (s.st_mode & S_IWOTH) {
1136 return tmpfile();
1137 }
1138 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
1139 grants TMP. */
1140}