From f1d26e68a342d7238bc7852c1b23981a8b1e33f1 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Tue, 16 Dec 2003 17:20:01 -0500
Subject: [PATCH] ENH: Added SetPipeShared method to allow stdout and stderr
 pipes to be shared with the parent process.

---
 Process.h.in   | 10 ++++++
 ProcessUNIX.c  | 95 +++++++++++++++++++++++++++++++++++++++++++++-----
 ProcessWin32.c | 81 ++++++++++++++++++++++++++++++++++++++----
 3 files changed, 171 insertions(+), 15 deletions(-)

diff --git a/Process.h.in b/Process.h.in
index e25c502f..7b77bb9f 100644
--- a/Process.h.in
+++ b/Process.h.in
@@ -31,6 +31,7 @@
 #define kwsysProcess_SetTimeout          kwsys(Process_SetTimeout)
 #define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory)
 #define kwsysProcess_SetPipeFile         kwsys(Process_SetPipeFile)
+#define kwsysProcess_SetPipeShared       kwsys(Process_SetPipeShared)
 #define kwsysProcess_Option_HideWindow   kwsys(Process_Option_HideWindow)
 #define kwsysProcess_GetOption           kwsys(Process_GetOption)
 #define kwsysProcess_SetOption           kwsys(Process_SetOption)
@@ -129,6 +130,14 @@ kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
 kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
                                          const char* file);
 
+/**
+ * Set whether the given pipe in the child is shared with the parent
+ * process.  The default is no for Pipe_STDOUT and Pipe_STDERR and yes
+ * for Pipe_STDIN.
+ */
+kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
+                                            int shared);
+
 /**
  * Get/Set a platform-specific option.  Possible options are:
  *
@@ -301,6 +310,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
 # undef kwsysProcess_SetTimeout
 # undef kwsysProcess_SetWorkingDirectory
 # undef kwsysProcess_SetPipeFile
+# undef kwsysProcess_SetPipeShared
 # undef kwsysProcess_Option_HideWindow
 # undef kwsysProcess_GetOption
 # undef kwsysProcess_SetOption
diff --git a/ProcessUNIX.c b/ProcessUNIX.c
index 51781f42..59b96611 100644
--- a/ProcessUNIX.c
+++ b/ProcessUNIX.c
@@ -169,6 +169,11 @@ struct kwsysProcess_s
   char* PipeFileSTDOUT;
   char* PipeFileSTDERR;
 
+  /* Whether each pipe is shared with the parent process.  */
+  int PipeSharedSTDIN;
+  int PipeSharedSTDOUT;
+  int PipeSharedSTDERR;
+
   /* The real working directory of this process.  */
   int RealWorkingDirectoryLength;
   char* RealWorkingDirectory;
@@ -184,7 +189,13 @@ kwsysProcess* kwsysProcess_New()
     return 0;
     }
   memset(cp, 0, sizeof(kwsysProcess));
+
+  /* Share stdin with the parent process by default.  */
+  cp->PipeSharedSTDIN = 1;
+
+  /* Set initial status.  */
   cp->State = kwsysProcess_State_Starting;
+
   return cp;
 }
 
@@ -393,9 +404,38 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
       }
     strcpy(*pfile, file);
     }
+
+  /* If we are redirecting the pipe, do not share it.  */
+  if(*pfile)
+    {
+    kwsysProcess_SetPipeShared(cp, pipe, 0);
+    }
   return 1;
 }
 
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
+{
+  if(!cp)
+    {
+    return;
+    }
+
+  switch(pipe)
+    {
+    case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break;
+    case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break;
+    case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break;
+    default: return;
+    }
+
+  /* If we are sharing the pipe, do not redirect it to a file.  */
+  if(shared)
+    {
+    kwsysProcess_SetPipeFile(cp, pipe, 0);
+    }
+}
+
 /*--------------------------------------------------------------------------*/
 int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
 {
@@ -545,6 +585,14 @@ void kwsysProcess_Execute(kwsysProcess* cp)
       }
     }
 
+  /* Replace the stderr pipe with the parent's if requested.  In this
+     case the select call will report that stderr is closed
+     immediately.  */
+  if(cp->PipeSharedSTDERR)
+    {
+    kwsysProcessCleanupDescriptor(&si.StdErr);
+    si.StdErr = 2;
+    }
 
   /* The timeout period starts now.  */
   cp->StartTime = kwsysProcessTimeGetCurrent();
@@ -553,7 +601,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
 
   /* Create the pipeline of processes.  */
   {
-  int readEnd = 0;
+  int readEnd = -1;
   for(i=0; i < cp->NumberOfCommands; ++i)
     {
     if(!kwsysProcessCreate(cp, i, &si, &readEnd))
@@ -562,13 +610,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
 
       /* Release resources that may have been allocated for this
          process before an error occurred.  */
-      if(i > 0 || si.StdIn > 0)
+      kwsysProcessCleanupDescriptor(&readEnd);
+      if(si.StdIn != 0)
         {
         kwsysProcessCleanupDescriptor(&si.StdIn);
         }
-      kwsysProcessCleanupDescriptor(&readEnd);
-      kwsysProcessCleanupDescriptor(&si.StdOut);
-      kwsysProcessCleanupDescriptor(&si.StdErr);
+      if(si.StdOut != 1)
+        {
+        kwsysProcessCleanupDescriptor(&si.StdOut);
+        }
+      if(si.StdErr != 2)
+        {
+        kwsysProcessCleanupDescriptor(&si.StdErr);
+        }
       kwsysProcessCleanupDescriptor(&si.TermPipe);
       kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
       kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
@@ -1106,10 +1160,14 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
       return 0;
       }
     }
-  else
+  else if(cp->PipeSharedSTDIN)
     {
     si->StdIn = 0;
     }
+  else
+    {
+    si->StdIn = -1;
+    }
 
   /* Setup the process's stdout.  */
   {
@@ -1140,6 +1198,15 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
       }
     }
 
+  /* Replace the stdout pipe with the parent's if requested.  In this
+     case the select call will report that stderr is closed
+     immediately.  */
+  if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
+    {
+    kwsysProcessCleanupDescriptor(&si->StdOut);
+    si->StdOut = 1;
+    }
+
   /* Create the error reporting pipe.  */
   if(pipe(si->ErrorPipe) < 0)
     {
@@ -1165,12 +1232,22 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
     close(si->ErrorPipe[0]);
 
     /* Setup the stdin, stdout, and stderr pipes.  */
-    if(index > 0 || si->StdIn > 0)
+    if(si->StdIn > 0)
       {
       dup2(si->StdIn, 0);
       }
-    dup2(si->StdOut, 1);
-    dup2(si->StdErr, 2);
+    else if(si->StdIn < 0)
+      {
+      close(0);
+      }
+    if(si->StdOut != 1)
+      {
+      dup2(si->StdOut, 1);
+      }
+    if(si->StdErr != 2)
+      {
+      dup2(si->StdErr, 2);
+      }
 
     /* Clear the close-on-exec flag for stdin, stdout, and stderr.
        Also clear it for the termination pipe.  All other pipe handles
diff --git a/ProcessWin32.c b/ProcessWin32.c
index dc2eeadd..964a5442 100644
--- a/ProcessWin32.c
+++ b/ProcessWin32.c
@@ -184,6 +184,11 @@ struct kwsysProcess_s
   char* PipeFileSTDOUT;
   char* PipeFileSTDERR;
 
+  /* Whether each pipe is shared with the parent process.  */
+  int PipeSharedSTDIN;
+  int PipeSharedSTDOUT;
+  int PipeSharedSTDERR;
+
   /* Handle to automatically delete the Win9x forwarding executable.  */
   HANDLE Win9xHandle;
 
@@ -264,6 +269,9 @@ kwsysProcess* kwsysProcess_New()
     }
   ZeroMemory(cp, sizeof(*cp));
 
+  /* Share stdin with the parent process by default.  */
+  cp->PipeSharedSTDIN = 1;
+
   /* Set initial status.  */
   cp->State = kwsysProcess_State_Starting;
 
@@ -805,9 +813,39 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
       }
     strcpy(*pfile, file);
     }
+
+  /* If we are redirecting the pipe, do not share it.  */
+  if(*pfile)
+    {
+    kwsysProcess_SetPipeShared(cp, pipe, 0);
+    }
+
   return 1;
 }
 
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
+{
+  if(!cp)
+    {
+    return;
+    }
+
+  switch(pipe)
+    {
+    case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break;
+    case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break;
+    case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break;
+    default: return;
+    }
+
+  /* If we are sharing the pipe, do not redirect it to a file.  */
+  if(shared)
+    {
+    kwsysProcess_SetPipeFile(cp, pipe, 0);
+    }
+}
+
 /*--------------------------------------------------------------------------*/
 int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
 {
@@ -973,6 +1011,15 @@ void kwsysProcess_Execute(kwsysProcess* cp)
       }
     }
 
+  /* Replace the stderr pipe with the parent process's if requested.
+     In this case the pipe thread will still run but never report
+     data.  */
+  if(cp->PipeSharedSTDERR)
+    {
+    kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+    si.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+    }
+
   /* Create the pipeline of processes.  */
   {
   HANDLE readEnd = 0;
@@ -989,12 +1036,18 @@ void kwsysProcess_Execute(kwsysProcess* cp)
       /* Release resources that may have been allocated for this
          process before an error occurred.  */
       kwsysProcessCleanupHandle(&readEnd);
-      if(i > 0)
+      if(si.StartupInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE))
         {
         kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
         }
-      kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
-      kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+      if(si.StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
+        {
+        kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
+        }
+      if(si.StartupInfo.hStdOutput != GetStdHandle(STD_ERROR_HANDLE))
+        {
+        kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+        }
       kwsysProcessCleanupHandle(&si.ErrorPipeRead);
       kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
       return;
@@ -1533,10 +1586,14 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
       }
     si->StartupInfo.hStdInput = fin;
     }
-  else
+  else if(cp->PipeSharedSTDIN)
     {
     si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     }
+  else
+    {
+    si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
+    }
 
   /* Setup the process's stdout.  */
   {
@@ -1578,6 +1635,15 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
       }
     }
 
+  /* Replace the stdout pipe with the parent process's if requested.
+     In this case the pipe thread will still run but never report
+     data.  */
+  if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
+    {
+    kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+    si->StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+    }
+
   /* Create the child process.  */
   {
   BOOL r;
@@ -1678,8 +1744,11 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
     kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
     }
 
-  /* The parent process does not need the inhertied pipe write end.  */
-  kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+  if(si->StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
+    {
+    /* The parent process does not need the inhertied pipe write end.  */
+    kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+    }
 
   return 1;
 }
-- 
GitLab