Use ~-expanded version of privlib
[p5sagit/p5-mst-13.2.git] / os2 / os2.c
index f6c7608..a518c41 100644 (file)
--- a/os2/os2.c
+++ b/os2/os2.c
@@ -1,5 +1,10 @@
 #define INCL_DOS
 #define INCL_NOPM
+#define INCL_DOSFILEMGR
+#ifndef NO_SYS_ALLOC 
+#  define INCL_DOSMEMMGR
+#  define INCL_DOSERRORS
+#endif /* ! defined NO_SYS_ALLOC */
 #include <os2.h>
 
 /*
@@ -41,12 +46,14 @@ result(int flag, int pid)
        Signal_t (*ihand)();     /* place to save signal during system() */
        Signal_t (*qhand)();     /* place to save signal during system() */
 
-       if (pid < 0 || flag != 0)
+       if (pid < 0 || flag != 0) 
                return pid;
 
        ihand = signal(SIGINT, SIG_IGN);
        qhand = signal(SIGQUIT, SIG_IGN);
-       r = waitpid(pid, &status, 0);
+       do {
+           r = wait4pid(pid, &status, 0);
+       } while (r == -1 && errno == EINTR);
        signal(SIGINT, ihand);
        signal(SIGQUIT, qhand);
 
@@ -88,6 +95,8 @@ register SV **sp;
        if (flag == P_WAIT)
                flag = P_NOWAIT;
 
+       if (*Argv[0] != '/' && *Argv[0] != '\\') /* will swawnvp use PATH? */
+           TAINT_ENV();        /* testing IFS here is overkill, probably */
        if (really && *(tmps = SvPV(really, na)))
            rc = result(trueflag, spawnvp(flag,tmps,Argv));
        else
@@ -95,6 +104,7 @@ register SV **sp;
 
        if (rc < 0 && dowarn)
            warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
+       if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
     } else
        rc = -1;
     do_execfree();
@@ -111,30 +121,56 @@ char *cmd;
     char *shell, *copt;
     int rc;
 
-    if ((shell = getenv("SHELL")) != NULL)
+#ifdef TRYSHELL
+    if ((shell = getenv("EMXSHELL")) != NULL)
+       copt = "-c";
+    else if ((shell = getenv("SHELL")) != NULL)
        copt = "-c";
     else if ((shell = getenv("COMSPEC")) != NULL)
        copt = "/C";
     else
        shell = "cmd.exe";
+#else
+    /* Consensus on perl5-porters is that it is _very_ important to
+       have a shell which will not change between computers with the
+       same architecture, to avoid "action on a distance". 
+       And to have simple build, this shell should be sh. */
+    shell = "sh.exe";
+    copt = "-c";
+#endif 
+
+    while (*cmd && isSPACE(*cmd))
+       cmd++;
 
     /* save an extra exec if possible */
     /* see if there are shell metacharacters in it */
 
-    /*SUPPRESS 530*/
-    if (*cmd == '@') {
-       ++cmd;
-       goto shell_cmd;
-    }
+    if (*cmd == '.' && isSPACE(cmd[1]))
+       goto doshell;
+
+    if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
+       goto doshell;
+
+    for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
+    if (*s == '=')
+       goto doshell;
+
     for (s = cmd; *s; s++) {
-       if (*s != ' ' && !isALPHA(*s) && strchr("%&|<>\n",*s)) {
+       if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
            if (*s == '\n' && !s[1]) {
                *s = '\0';
                break;
            }
-shell_cmd:  return result(P_WAIT, spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
+         doshell:
+           rc = result(P_WAIT,
+                         spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
+           if (rc < 0 && dowarn)
+               warn("Can't spawn \"%s\": %s", shell, Strerror(errno));
+           if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
+           return rc;
        }
     }
+
     New(402,Argv, (s - cmd) / 2 + 2, char*);
     Cmd = savepvn(cmd, s-cmd);
     a = Argv;
@@ -151,12 +187,27 @@ shell_cmd:  return result(P_WAIT, spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0)
        rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
        if (rc < 0 && dowarn)
            warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
+       if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
     } else
        rc = -1;
     do_execfree();
     return rc;
 }
 
+FILE *
+my_popen(cmd,mode)
+char   *cmd;
+char   *mode;
+{
+    char *shell = getenv("EMXSHELL");
+    FILE *res;
+    
+    my_setenv("EMXSHELL", "sh.exe");
+    res = popen(cmd, mode);
+    my_setenv("EMXSHELL", shell);
+    return res;
+}
+
 /*****************************************************************************/
 
 #ifndef HAS_FORK
@@ -173,7 +224,10 @@ fork(void)
 /* not implemented in EMX 0.9a */
 
 void * ctermid(x)      { return 0; }
+
+#ifdef MYTTYNAME /* was not in emx0.9a */
 void * ttyname(x)      { return 0; }
+#endif
 
 void * gethostent()    { return 0; }
 void * getnetent()     { return 0; }
@@ -213,3 +267,118 @@ os2_stat(char *name, struct stat *st)
 }
 
 #endif
+
+#ifndef NO_SYS_ALLOC
+
+static char *oldchunk;
+static long oldsize;
+
+#define _32_K (1<<15)
+#define _64_K (1<<16)
+
+/* The real problem is that DosAllocMem will grant memory on 64K-chunks
+ * boundaries only. Note that addressable space for application memory
+ * is around 240M, thus we will run out of addressable space if we
+ * allocate around 14M worth of 4K segments.
+ * Thus we allocate memory in 64K chunks, and abandon the rest of the old
+ * chunk if the new is bigger than that rest. Also, we just allocate
+ * whatever is requested if the size is bigger that 32K. With this strategy
+ * we cannot lose more than 1/2 of addressable space. */
+
+void *
+sbrk(int size)
+{
+    char *got;
+    APIRET rc;
+    int small, reqsize;
+
+    if (!size) return 0;
+    else if (size <= oldsize) {
+       got = oldchunk;
+       oldchunk += size;
+       oldsize -= size;
+       return (void *)got;
+    } else if (size >= _32_K) {
+       small = 0;
+    } else {
+       reqsize = size;
+       size = _64_K;
+       small = 1;
+    }
+    rc = DosAllocMem((void **)&got, size, PAG_COMMIT | PAG_WRITE);
+    if (rc == ERROR_NOT_ENOUGH_MEMORY) {
+       return (void *) -1;
+    } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
+    if (small) {
+       /* Chunk is small, register the rest for future allocs. */
+       oldchunk = got + reqsize;
+       oldsize = size - reqsize;
+    }
+    return (void *)got;
+}
+#endif /* ! defined NO_SYS_ALLOC */
+
+/* tmp path */
+
+char *tmppath = TMPPATH1;
+
+void
+settmppath()
+{
+    char *p = getenv("TMP"), *tpath;
+    int len;
+
+    if (!p) p = getenv("TEMP");
+    if (!p) return;
+    len = strlen(p);
+    tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
+    strcpy(tpath, p);
+    tpath[len] = '/';
+    strcpy(tpath + len + 1, TMPPATH1);
+    tmppath = tpath;
+}
+
+#include "XSUB.h"
+
+XS(XS_File__Copy_syscopy)
+{
+    dXSARGS;
+    if (items < 2 || items > 3)
+       croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
+    {
+       char *  src = (char *)SvPV(ST(0),na);
+       char *  dst = (char *)SvPV(ST(1),na);
+       U32     flag;
+       int     RETVAL, rc;
+
+       if (items < 3)
+           flag = 0;
+       else {
+           flag = (unsigned long)SvIV(ST(2));
+       }
+
+       errno = DosCopy(src, dst, flag);
+       RETVAL = !errno;
+       ST(0) = sv_newmortal();
+       sv_setiv(ST(0), (IV)RETVAL);
+    }
+    XSRETURN(1);
+}
+
+OS2_Perl_data_t OS2_Perl_data;
+
+int
+Xs_OS2_init()
+{
+    char *file = __FILE__;
+    {
+        newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
+    }
+}
+
+void
+Perl_OS2_init()
+{
+    settmppath();
+    OS2_Perl_data.xs_init = &Xs_OS2_init;
+}