[win32] provide our own popen()/pclose() to fix problems with qx//:
Gurusamy Sarathy [Sat, 7 Mar 1998 06:49:49 +0000 (06:49 +0000)]
 - qx// used to always invoke the shell, now does so only when needed
 - qx// didn't respect PERL5SHELL, now does

p4raw-id: //depot/win32/perl@797

lib/ExtUtils/typemap
win32/config_h.PL
win32/win32.c

index 20cc96f..03ba050 100644 (file)
@@ -262,7 +262,7 @@ T_ARRAY
                ST(ix_$var) = sv_newmortal();
        DO_ARRAY_ELEM
        }
-       sp += $var.size - 1;
+       SP += $var.size - 1;
 T_IN
        {
            GV *gv = newGVgen("$Package");
index 471c43c..f317e5a 100644 (file)
@@ -27,6 +27,7 @@ eval $str;
 die "$str:$@" if $@;
 
 open(H,">$file.new") || die "Cannot open $file.new:$!";
+binmode H;             # no CRs (which cause a spurious rebuild)
 while (<SH>)
  {
   last if /^$term$/o;
index 9f678f2..1ee0587 100644 (file)
@@ -72,6 +72,20 @@ long w32_num_children = 0;
 HANDLE w32_child_pids[MAXIMUM_WAIT_OBJECTS];
 #endif
 
+#ifndef FOPEN_MAX
+#  ifdef _NSTREAM_
+#    define FOPEN_MAX _NSTREAM_
+#  elsif _NFILE_
+#    define FOPEN_MAX _NFILE_
+#  elsif _NFILE
+#    define FOPEN_MAX _NFILE
+#  endif
+#endif
+
+#ifndef USE_CRT_POPEN
+int    w32_popen_pids[FOPEN_MAX];
+#endif
+
 #ifdef USE_THREADS
 #  ifdef USE_DECLSPEC_THREAD
 __declspec(thread) char        strerror_buffer[512];
@@ -188,10 +202,8 @@ my_popen(char *cmd, char *mode)
 #define fixcmd(x)
 #endif
     fixcmd(cmd);
-#ifdef __BORLANDC__ /* workaround a Borland stdio bug */
     win32_fflush(stdout);
     win32_fflush(stderr);
-#endif
     return win32_popen(cmd, mode);
 }
 
@@ -335,15 +347,18 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
                               (const char* const*)argv);
     }
 
-    if (status < 0) {
-       if (dowarn)
-           warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
-       status = 255 * 256;
+    if (flag != P_NOWAIT) {
+       if (status < 0) {
+           if (dowarn)
+               warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
+           status = 255 * 256;
+       }
+       else
+           status *= 256;
+       statusvalue = status;
     }
-    else if (flag != P_NOWAIT)
-       status *= 256;
     Safefree(argv);
-    return (statusvalue = status);
+    return (status);
 }
 
 static int
@@ -419,16 +434,19 @@ do_spawn2(char *cmd, int exectype)
        cmd = argv[0];
        Safefree(argv);
     }
-    if (status < 0) {
-       if (dowarn)
-           warn("Can't %s \"%s\": %s",
-                (exectype == EXECF_EXEC ? "exec" : "spawn"),
-                cmd, strerror(errno));
-       status = 255 * 256;
+    if (exectype != EXECF_SPAWN_NOWAIT) {
+       if (status < 0) {
+           if (dowarn)
+               warn("Can't %s \"%s\": %s",
+                    (exectype == EXECF_EXEC ? "exec" : "spawn"),
+                    cmd, strerror(errno));
+           status = 255 * 256;
+       }
+       else
+           status *= 256;
+       statusvalue = status;
     }
-    else if (exectype != EXECF_SPAWN_NOWAIT)
-       status *= 256;
-    return (statusvalue = status);
+    return (status);
 }
 
 int
@@ -1397,16 +1415,125 @@ win32_pipe(int *pfd, unsigned int size, int mode)
     return _pipe(pfd, size, mode);
 }
 
+/*
+ * a popen() clone that respects PERL5SHELL
+ */
+
 DllExport FILE*
 win32_popen(const char *command, const char *mode)
 {
+#ifdef USE_CRT_POPEN
     return _popen(command, mode);
+#else
+    int p[2];
+    int parent, child;
+    int stdfd, oldfd;
+    int ourmode;
+    int childpid;
+
+    /* establish which ends read and write */
+    if (strchr(mode,'w')) {
+        stdfd = 0;             /* stdin */
+        parent = 1;
+        child = 0;
+    }
+    else if (strchr(mode,'r')) {
+        stdfd = 1;             /* stdout */
+        parent = 0;
+        child = 1;
+    }
+    else
+        return NULL;
+
+    /* set the correct mode */
+    if (strchr(mode,'b'))
+        ourmode = O_BINARY;
+    else if (strchr(mode,'t'))
+        ourmode = O_TEXT;
+    else
+        ourmode = _fmode & (O_TEXT | O_BINARY);
+
+    /* the child doesn't inherit handles */
+    ourmode |= O_NOINHERIT;
+
+    if (win32_pipe( p, 512, ourmode) == -1)
+        return NULL;
+
+    /* save current stdfd */
+    if ((oldfd = win32_dup(stdfd)) == -1)
+        goto cleanup;
+
+    /* make stdfd go to child end of pipe (implicitly closes stdfd) */
+    /* stdfd will be inherited by the child */
+    if (win32_dup2(p[child], stdfd) == -1)
+        goto cleanup;
+
+    /* close the child end in parent */
+    win32_close(p[child]);
+
+    /* start the child */
+    if ((childpid = do_spawn_nowait((char*)command)) == -1)
+        goto cleanup;
+
+    /* revert stdfd to whatever it was before */
+    if (win32_dup2(oldfd, stdfd) == -1)
+        goto cleanup;
+
+    /* close saved handle */
+    win32_close(oldfd);
+
+    w32_popen_pids[p[parent]] = childpid;
+
+    /* we have an fd, return a file stream */
+    return (win32_fdopen(p[parent], (char *)mode));
+
+cleanup:
+    /* we don't need to check for errors here */
+    win32_close(p[0]);
+    win32_close(p[1]);
+    if (oldfd != -1) {
+        win32_dup2(oldfd, stdfd);
+        win32_close(oldfd);
+    }
+    return (NULL);
+
+#endif /* USE_CRT_POPEN */
 }
 
+/*
+ * pclose() clone
+ */
+
 DllExport int
 win32_pclose(FILE *pf)
 {
+#ifdef USE_CRT_POPEN
     return _pclose(pf);
+#else
+    int fd, childpid, status;
+
+    fd = win32_fileno(pf);
+    childpid = w32_popen_pids[fd];
+
+    if (!childpid) {
+       errno = EBADF;
+        return -1;
+    }
+
+    win32_fclose(pf);
+    w32_popen_pids[fd] = 0;
+
+    /* wait for the child */
+    if (cwait(&status, childpid, WAIT_CHILD) == -1)
+        return (-1);
+    /* cwait() returns differently on Borland */
+#ifdef __BORLANDC__
+    return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
+#else
+    return (status);
+#endif
+
+#endif /* USE_CRT_OPEN */
 }
 
 DllExport int
@@ -1728,7 +1855,7 @@ XS(w32_GetCwd)
      */
     if (SvCUR(sv))
        SvPOK_on(sv);
-    EXTEND(sp,1);
+    EXTEND(SP,1);
     ST(0) = sv;
     XSRETURN(1);
 }