From 3f9543d07809ceaee098c226837cfbd825352682 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Wed, 18 Jun 2003 17:06:21 -0400
Subject: [PATCH] ENH: Added documentation to interface.  Finished process exit
 code interpretation implementation prototype.

---
 Process.h.in   | 305 +++++++++++++++++++++++++++++++++----------------
 ProcessUNIX.c  |  93 +++++++++++----
 ProcessWin32.c | 111 ++++++++++++++----
 test1.cxx      |   3 +-
 4 files changed, 367 insertions(+), 145 deletions(-)

diff --git a/Process.h.in b/Process.h.in
index 076bd17..d496710 100644
--- a/Process.h.in
+++ b/Process.h.in
@@ -17,119 +17,223 @@
 #ifndef @KWSYS_NAMESPACE@_Process_h
 #define @KWSYS_NAMESPACE@_Process_h
 
+/* Redefine all public interface symbol names to be in the proper
+   namespace.  These macros are used internally to kwsys only, and are
+   not visible to user code.  Use kwsysHeaderDump.pl to reproduce
+   these macros after making changes to the interface.  */
 #define kwsys(x) @KWSYS_NAMESPACE@##x
-#define kwsysProcess_STDOUT kwsys(Process_STDOUT)
-#define kwsysProcess_STDERR kwsys(Process_STDERR)
-#define kwsysProcess_Timeout kwsys(Process_Timeout)
-#define kwsysProcess_Starting kwsys(Process_Starting)
-#define kwsysProcess_Executing kwsys(Process_Executing)
-#define kwsysProcess_Expired kwsys(Process_Expired)
-#define kwsysProcess_Exited kwsys(Process_Exited)
-#define kwsysProcess_Killed kwsys(Process_Killed)
-#define kwsysProcess_Signalled kwsys(Process_Signalled)
-#define kwsysProcess_Error kwsys(Process_Error)
-#define kwsysProcess_State kwsys(Process_State)
-#define kwsysProcess_Pipes_e kwsys(Process_Pipes_e)
-#define kwsysProcess_State_e kwsys(Process_State_e)
-#define kwsysProcess_s kwsys(Process_s)
-#define kwsysProcess kwsys(Process)
-#define kwsysProcess_New kwsys(Process_New)
-#define kwsysProcess_Delete kwsys(Process_Delete)
-#define kwsysProcess_SetCommand kwsys(Process_SetCommand)
-#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout)
-#define kwsysProcess_GetState kwsys(Process_GetState)
-#define kwsysProcess_GetExitCode kwsys(Process_GetExitCode)
-#define kwsysProcess_GetErrorString kwsys(Process_GetErrorString)
-#define kwsysProcess_Execute kwsys(Process_Execute)
-#define kwsysProcess_WaitForData kwsys(Process_WaitForData)
-#define kwsysProcess_WaitForExit kwsys(Process_WaitForExit)
-#define kwsysProcess_Kill kwsys(Process_Kill)
+#define kwsysProcess                     kwsys(Process)
+#define kwsysProcess_s                   kwsys(Process_s)
+#define kwsysProcess_New                 kwsys(Process_New)
+#define kwsysProcess_Delete              kwsys(Process_Delete)
+#define kwsysProcess_SetCommand          kwsys(Process_SetCommand)
+#define kwsysProcess_SetTimeout          kwsys(Process_SetTimeout)
+#define kwsysProcess_State_Starting      kwsys(Process_State_Starting)
+#define kwsysProcess_State_Error         kwsys(Process_State_Error)
+#define kwsysProcess_State_Exception     kwsys(Process_State_Exception)
+#define kwsysProcess_State_Executing     kwsys(Process_State_Executing)
+#define kwsysProcess_State_Exited        kwsys(Process_State_Exited)
+#define kwsysProcess_State_Expired       kwsys(Process_State_Expired)
+#define kwsysProcess_State_Killed        kwsys(Process_State_Killed)
+#define kwsysProcess_GetState            kwsys(Process_GetState)
+#define kwsysProcess_State_e             kwsys(Process_State_e)
+#define kwsysProcess_Exception_None      kwsys(Process_Exception_None)
+#define kwsysProcess_Exception_Abort     kwsys(Process_Exception_Abort)
+#define kwsysProcess_Exception_Fault     kwsys(Process_Exception_Fault)
+#define kwsysProcess_Exception_Illegal   kwsys(Process_Exception_Illegal)
+#define kwsysProcess_Exception_Interrupt kwsys(Process_Exception_Interrupt)
+#define kwsysProcess_Exception_Numerical kwsys(Process_Exception_Numerical)
+#define kwsysProcess_Exception_Other     kwsys(Process_Exception_Other)
+#define kwsysProcess_GetExitException    kwsys(Process_GetExitException)
+#define kwsysProcess_Exception_e         kwsys(Process_Exception_e)
+#define kwsysProcess_GetExitCode         kwsys(Process_GetExitCode)
+#define kwsysProcess_GetExitValue        kwsys(Process_GetExitValue)
+#define kwsysProcess_GetErrorString      kwsys(Process_GetErrorString)
+#define kwsysProcess_Execute             kwsys(Process_Execute)
+#define kwsysProcess_WaitForData         kwsys(Process_WaitForData)
+#define kwsysProcess_Pipes_e             kwsys(Process_Pipes_e)
+#define kwsysProcess_Pipe_STDOUT         kwsys(Process_Pipe_STDOUT)
+#define kwsysProcess_Pipe_STDERR         kwsys(Process_Pipe_STDERR)
+#define kwsysProcess_Pipe_Timeout        kwsys(Process_Pipe_Timeout)
+#define kwsysProcess_WaitForExit         kwsys(Process_WaitForExit)
+#define kwsysProcess_Kill                kwsys(Process_Kill)
 
 #if defined(__cplusplus)
 extern "C"
 {
 #endif
 
-typedef enum kwsysProcess_Pipes_e
-{
-  kwsysProcess_STDOUT=1,
-  kwsysProcess_STDERR=2,
-  kwsysProcess_Timeout=255
-} kwsysProcess_Pipes;
-
-typedef enum kwsysProcess_State_e
-{
-  kwsysProcess_Starting,  /* Between New and Execute; No process run yet */
-  kwsysProcess_Executing, /* Process is running */
-  kwsysProcess_Expired,   /* Process timeout expired and was killed */
-  kwsysProcess_Exited,    /* Process exited */
-  kwsysProcess_Killed,    /* Process was killed by Kill */
-  kwsysProcess_Signalled, /* Process was terminated by a signal (crash / ctrl-C) */
-  kwsysProcess_Error      /* Internal error of Process */
-} kwsysProcess_State;
-
+/**
+ * Process control data structure.
+ */
 typedef struct kwsysProcess_s kwsysProcess;
 
+/**
+ * Create a new Process instance.
+ */
 kwsysProcess* kwsysProcess_New();
 
+/**
+ * Delete an existing Process instance.  If the instance is currently
+ * executing a process, this blocks until the process terminates.
+ */
 void kwsysProcess_Delete(kwsysProcess* cp);
 
+/**
+ * Set the command line to be executed.  Argument is an array of
+ * pointers to the command and each argument.  Ths array must end with
+ * a NULL pointer.
+ */
 void kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command);
 
+/**
+ * Set the timeout for the child process.  The timeout period begins
+ * when the child is executed.  If the child has not terminated when
+ * the timeout expires, it will be killed.  A non-positive (<= 0)
+ * value will disable the timeout.
+ */
 void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout);
 
-/*
- * Get the current internal state of the kwsysProcess instance
+/**
+ * Get the current state of the Process instance.  Possible states are:
+ *
+ *  kwsysProcess_State_Starting  = Execute has not yet been called.
+ *  kwsysProcess_State_Error     = Error administrating the child process.
+ *  kwsysProcess_State_Exception = Child process exited abnormally.
+ *  kwsysProcess_State_Executing = Child process is currently running.
+ *  kwsysProcess_State_Exited    = Child process exited normally.
+ *  kwsysProcess_State_Expired   = Child process's timeout expired.
+ *  kwsysProcess_State_Killed    = Child process terminated by Kill method.
  */
 int kwsysProcess_GetState(kwsysProcess* cp);
+typedef enum kwsysProcess_State_e
+{
+  kwsysProcess_State_Starting,
+  kwsysProcess_State_Error,
+  kwsysProcess_State_Exception,
+  kwsysProcess_State_Executing,
+  kwsysProcess_State_Exited,
+  kwsysProcess_State_Expired,
+  kwsysProcess_State_Killed
+};
+
+/**
+ * When GetState returns "Exception", this method returns a
+ * platform-independent description of the exceptional behavior that
+ * caused the child to terminate abnormally.  Possible exceptions are:
+ *
+ *  kwsysProcess_Exception_None      = No exceptional behavior occurred.
+ *  kwsysProcess_Exception_Abort     = Child exited with abort call.
+ *  kwsysProcess_Exception_Fault     = Child crashed with a memory fault.
+ *  kwsysProcess_Exception_Illegal   = Child crashed with an illegal instruction.
+ *  kwsysProcess_Exception_Interrupt = Child was interrupted by user (Cntl-C/Break).
+ *  kwsysProcess_Exception_Numerical = Child crashed with a numerical exception.
+ *  kwsysProcess_Exception_Other     = Child terminated for another reason.
+ */
+int kwsysProcess_GetExitException(kwsysProcess* cp);
+typedef enum kwsysProcess_Exception_e
+{
+  kwsysProcess_Exception_None,
+  kwsysProcess_Exception_Abort,
+  kwsysProcess_Exception_Fault,
+  kwsysProcess_Exception_Illegal,
+  kwsysProcess_Exception_Interrupt,
+  kwsysProcess_Exception_Numerical,
+  kwsysProcess_Exception_Other
+};
 
-/*
- * Get process return code or when signalled, get the signal code 
+/**
+ * When GetState returns "Exited" or "Exception", this method returns
+ * the platform-specific raw exit code of the process.  UNIX platforms
+ * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access
+ * this value.  Windows users should compare the value to the various
+ * EXCEPTION_* values.
+ *
+ * If GetState returns "Exited", use GetExitValue to get the
+ * platform-independent child return value.
  */
 int kwsysProcess_GetExitCode(kwsysProcess* cp);
 
-/*
- * On kwsysProcess_Error get the error message
+/**
+ * When GetState returns "Exited", this method returns the child's
+ * platform-independent exit code (such as the value returned by the
+ * child's main).
+ */
+int kwsysProcess_GetExitValue(kwsysProcess* cp);
+
+/**
+ * When GetState returns "Error", this method returns a string
+ * describing the problem.  Otherwise, it returns NULL.
  */
 const char* kwsysProcess_GetErrorString(kwsysProcess* cp);
 
+/**
+ * Start executing the child process.
+ */
 void kwsysProcess_Execute(kwsysProcess* cp);
 
-/*
- * Block until data available on requested pipe or one of the timeouts expired,
- * or the process exits. If the pipe is not specified, data on that pipe are
- * ignored.
+/**
+ * Block until data are available on a requested pipe, a timeout
+ * expires, or the child process terminates.  Arguments are as
+ * follows:
+ *
+ *  pipes   = Flags for the child output pipes of interest to the caller.
+ *            Possible values are Pipe_STDOUT and Pipe_STDERR.  Multiple
+ *            pipes may be specified by using the bitwise OR operator '|'.
+ *  data    = If data are read, the pointer to which this points is
+ *            set to point to the data.
+ *  length  = If data are read, the integer to which this points is
+ *            set to the length of the data read.
+ *  timeout = Specifies the maximum time this call may block.  Upon
+ *            return after reading data, the time elapsed is subtracted
+ *            from the timeout value.  If this timeout expires, the
+ *            value is set to 0.  A NULL pointer passed for this argument
+ *            indicates no timeout for the call.
+ *
+ * Return value will be one of:
+ *
+ *   0            = No more data will be available from the child process,
+ *                  or no process has been executed.  WaitForExit should
+ *                  be called to wait for the process to terminate.
+ *   Pipe_STDOUT  = Data have been read from the child's stdout pipe.
+ *   Pipe_STDERR  = Data have been read from the child's stderr pipe.
+ *   Pipe_Timeout = No data available within timeout specified for the
+ *                  call.  Time elapsed has been subtracted from timeout
+ *                  argument.
+ */
+int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data,
+                             int* length, double* timeout);
+typedef enum kwsysProcess_Pipes_e
+{
+  kwsysProcess_Pipe_STDOUT=1,
+  kwsysProcess_Pipe_STDERR=2,
+  kwsysProcess_Pipe_Timeout=255
+};
+
+/**
+ * Block until the child process terminates or the given timeout
+ * expires.  If no process is running, returns immediatly.  The
+ * argument is:
  *
- * pipes - a list of interested pipes - kwsysProcess_STDOUT | kwsysProcess_STDERR
- * data - returns pointer to data if read, NULL otherwise
- * length - length of the returned data
- * userTimeout - timeout for the current kwsysProcess_WaitForData call
- *     the userTimeout will contain the remaining time
+ *  timeout = Specifies the maximum time this call may block.  Upon
+ *            returning due to child termination, the elapsed time
+ *            is subtracted from the given value.  A NULL pointer
+ *            passed for this argument indicates no timeout for the
+ *            call.
  *
- * Returns:
- *    0 - Process exited or killed or process timeout expired with no data
- *        available, or no process running.
- *    PIPE id otherwise:
- *       kwsysProcess_STDOUT - if stdout is returned
- *       kwsysProcess_STDERR - if stderr is returned
- *       kwsysProcess_Timeout - if user timeout expired
- */ 
-int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* length,
-                          double* userTimeout);
-
-/*
- * Block until the process exits or the timeout expires. If no process is
- * running, return immediatly.
+ * Return value will be one of:
  *
- * Returns:
- *    0 - When user timeout expires
- *    1 - Otherwise
+ *    0 = Child did not terminate within timeout specified for
+ *        the call.  Time elapsed has been subtracted from timeout
+ *        argument.
+ *    1 = Child has terminated or was not running.
  */
-int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout);
+int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout);
 
-/* 
- * Kills the process.  kwsysProcess_WaitForExit should still be called
- * after kwsysProcess_Kill.
+/**
+ * Forcefully terminate the child process that is currently running.
+ * The caller should call WaitForExit after this returns to wait for
+ * the child to terminate.
  */
 void kwsysProcess_Kill(kwsysProcess* cp);
 
@@ -137,34 +241,43 @@ void kwsysProcess_Kill(kwsysProcess* cp);
 } /* extern "C" */
 #endif
 
-
-/* If we are building a kwsysProcess .c file, let it use these macros.  */
+/* If we are building a kwsysProcess .c file, let it use these macros.
+   Otherwise, undefine them to keep the namespace clean.  */
 #if !defined(KWSYS_IN_PROCESS_C)
 # undef kwsys
-# undef kwsysProcess_STDOUT
-# undef kwsysProcess_STDERR
-# undef kwsysProcess_Timeout
-# undef kwsysProcess_Starting
-# undef kwsysProcess_Executing
-# undef kwsysProcess_Expired
-# undef kwsysProcess_Exited
-# undef kwsysProcess_Killed
-# undef kwsysProcess_Signalled
-# undef kwsysProcess_Error
-# undef kwsysProcess_State
-# undef kwsysProcess_Pipes_e
-# undef kwsysProcess_State_e
-# undef kwsysProcess_s
 # undef kwsysProcess
+# undef kwsysProcess_s
 # undef kwsysProcess_New
 # undef kwsysProcess_Delete
 # undef kwsysProcess_SetCommand
 # undef kwsysProcess_SetTimeout
+# undef kwsysProcess_State_Starting
+# undef kwsysProcess_State_Error
+# undef kwsysProcess_State_Exception
+# undef kwsysProcess_State_Executing
+# undef kwsysProcess_State_Exited
+# undef kwsysProcess_State_Expired
+# undef kwsysProcess_State_Killed
 # undef kwsysProcess_GetState
+# undef kwsysProcess_State_e
+# undef kwsysProcess_Exception_None
+# undef kwsysProcess_Exception_Abort
+# undef kwsysProcess_Exception_Fault
+# undef kwsysProcess_Exception_Illegal
+# undef kwsysProcess_Exception_Interrupt
+# undef kwsysProcess_Exception_Numerical
+# undef kwsysProcess_Exception_Other
+# undef kwsysProcess_GetExitException
+# undef kwsysProcess_Exception_e
 # undef kwsysProcess_GetExitCode
+# undef kwsysProcess_GetExitValue
 # undef kwsysProcess_GetErrorString
 # undef kwsysProcess_Execute
 # undef kwsysProcess_WaitForData
+# undef kwsysProcess_Pipes_e
+# undef kwsysProcess_Pipe_STDOUT
+# undef kwsysProcess_Pipe_STDERR
+# undef kwsysProcess_Pipe_Timeout
 # undef kwsysProcess_WaitForExit
 # undef kwsysProcess_Kill
 #endif
diff --git a/ProcessUNIX.c b/ProcessUNIX.c
index c19a196..461db7f 100644
--- a/ProcessUNIX.c
+++ b/ProcessUNIX.c
@@ -98,7 +98,7 @@ struct kwsysProcess_s
   int ChildError;
   
   /* The timeout length.  */
-  float Timeout;
+  double Timeout;
   
   /* Time at which the child started.  Negative for no timeout.  */
   kwsysProcessTime StartTime;
@@ -120,10 +120,17 @@ struct kwsysProcess_s
 
   /* The current status of the child process. */
   int State;
-
-  /* The exit code of the child process, if any.  */
+  
+  /* The exceptional behavior that terminated the child process, if
+   * any.  */
+  int ExitException;
+  
+  /* The exit code of the child process.  */
   int ExitCode;
   
+  /* The exit value of the child process, if any.  */
+  int ExitValue;
+  
   /* Whether the process was killed.  */
   int Killed;
   
@@ -142,7 +149,7 @@ kwsysProcess* kwsysProcess_New()
     return 0;
     }
   memset(cp, 0, sizeof(kwsysProcess));
-  cp->State = kwsysProcess_Starting;
+  cp->State = kwsysProcess_State_Starting;
   return cp;
 }
 
@@ -150,7 +157,7 @@ kwsysProcess* kwsysProcess_New()
 void kwsysProcess_Delete(kwsysProcess* cp)
 {
   /* If the process is executing, wait for it to finish.  */
-  if(cp->State == kwsysProcess_Executing)
+  if(cp->State == kwsysProcess_State_Executing)
     {
     kwsysProcess_WaitForExit(cp, 0);
     }
@@ -205,20 +212,32 @@ int kwsysProcess_GetState(kwsysProcess* cp)
   return cp->State;
 }
 
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+  return cp->ExitException;
+}
+
 /*--------------------------------------------------------------------------*/
 int kwsysProcess_GetExitCode(kwsysProcess* cp)
 {
   return cp->ExitCode;
 }
 
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+  return cp->ExitValue;
+}
+
 /*--------------------------------------------------------------------------*/
 const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
 {
-  if(cp->State == kwsysProcess_Error)
+  if(cp->State == kwsysProcess_State_Error)
     {
     return cp->PipeBuffer;
     }
-  return "";
+  return 0;
 }
 
 /*--------------------------------------------------------------------------*/
@@ -228,7 +247,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
   struct sigaction newSigChldAction;
   
   /* Do not execute a second copy simultaneously.  */
-  if(cp->State == kwsysProcess_Executing)
+  if(cp->State == kwsysProcess_State_Executing)
     {
     return;
     }
@@ -317,7 +336,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
   cp->PipesLeft = KWSYSPE_PIPE_COUNT;
   
   /* The process has now started.  */
-  cp->State = kwsysProcess_Executing;
+  cp->State = kwsysProcess_State_Executing;
 }
 
 /*--------------------------------------------------------------------------*/
@@ -503,7 +522,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng
     if(user)
       {
       /* The user timeout has expired.  It has no time left.  */
-      return kwsysProcess_Timeout;
+      return kwsysProcess_Pipe_Timeout;
       }
     else
       {
@@ -530,7 +549,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   int pipe = 0;
   
   /* Make sure we are executing a process.  */
-  if(cp->State != kwsysProcess_Executing)
+  if(cp->State != kwsysProcess_State_Executing)
     {
     return 1;
     }
@@ -538,7 +557,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   /* Wait for all the pipes to close.  Ignore all data.  */
   while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0)
     {
-    if(pipe == kwsysProcess_Timeout)
+    if(pipe == kwsysProcess_Pipe_Timeout)
       {
       return 0;
       }
@@ -561,7 +580,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
     /* The error message is already in its buffer.  Tell
        kwsysProcessCleanup to not create it.  */
     kwsysProcessCleanup(cp, 0);
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     return 1;
     }
   
@@ -569,30 +588,52 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   if(cp->Killed)
     {
     /* We killed the child.  */
-    cp->State = kwsysProcess_Killed;
+    cp->State = kwsysProcess_State_Killed;
     }
   else if(cp->TimeoutExpired)
     {
     /* The timeout expired.  */
-    cp->State = kwsysProcess_Expired;
+    cp->State = kwsysProcess_State_Expired;
     }
   else if(WIFEXITED(status))
     {
-    /* The child exited.  */
-    cp->State = kwsysProcess_Exited;
-    cp->ExitCode = (int)WEXITSTATUS(status);
+    /* The child exited normally.  */
+    cp->State = kwsysProcess_State_Exited;
+    cp->ExitException = kwsysProcess_Exception_None;
+    cp->ExitCode = status;
+    cp->ExitValue = (int)WEXITSTATUS(status);
     }
   else if(WIFSIGNALED(status))
     {
     /* The child received an unhandled signal.  */
-    cp->State = kwsysProcess_Signalled;
-    cp->ExitCode = (int)WTERMSIG(status);
+    cp->State = kwsysProcess_State_Exception;
+    switch ((int)WTERMSIG(status))
+      {
+#ifdef SIGSEGV
+      case SIGSEGV: cp->ExitException = kwsysProcess_Exception_Fault; break;
+#endif
+#ifdef SIGFPE
+      case SIGFPE:  cp->ExitException = kwsysProcess_Exception_Numerical; break;
+#endif
+#ifdef SIGILL
+      case SIGILL:  cp->ExitException = kwsysProcess_Exception_Illegal; break;
+#endif
+#ifdef SIGINT
+      case SIGINT:  cp->ExitException = kwsysProcess_Exception_Interrupt; break;
+#endif
+#ifdef SIGABRT
+      case SIGABRT: cp->ExitException = kwsysProcess_Exception_Abort; break;
+#endif
+      default: cp->ExitException = kwsysProcess_Exception_Other; break;
+      }
+    cp->ExitCode = status;
+    cp->ExitValue = (int)WTERMSIG(status);
     }
   else
     {
     /* Error getting the child return code.  */
     strcpy(cp->ErrorMessage, "Error getting child return code.");
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     }
   
   /* Normal cleanup.  */
@@ -604,7 +645,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
 void kwsysProcess_Kill(kwsysProcess* cp)
 {  
   /* Make sure we are executing a process.  */
-  if(cp->State != kwsysProcess_Executing)
+  if(cp->State != kwsysProcess_State_Executing)
     {
     return;
     }
@@ -633,9 +674,11 @@ static void kwsysProcessInitialize(kwsysProcess* cp)
   cp->TimeoutExpired = 0;
   cp->PipesLeft = 0;
   FD_ZERO(&cp->PipeSet);
-  cp->State = kwsysProcess_Starting;
+  cp->State = kwsysProcess_State_Starting;
   cp->Killed = 0;
-  cp->ExitCode = 0;
+  cp->ExitException = kwsysProcess_Exception_None;
+  cp->ExitCode = 1;
+  cp->ExitValue = 1;
   cp->ErrorMessage[0] = 0;
   cp->ErrorMessageLength = 0;
 }
@@ -651,7 +694,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
   if(error)
     {
     snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, "%s", strerror(errno));
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     }
   
   /* Restore the SIGCHLD handler.  */
diff --git a/ProcessWin32.c b/ProcessWin32.c
index b277891..ddf6a95 100644
--- a/ProcessWin32.c
+++ b/ProcessWin32.c
@@ -152,9 +152,15 @@ struct kwsysProcess_s
   
   /* ------------- Data managed per call to Execute ------------- */
   
-  /* The process exit code, if any.  */
+  /* The exceptional behavior that terminated the process, if any.  */
+  int ExitException;
+  
+  /* The process exit code.  */
   int ExitCode;
   
+  /* The process return code, if any.  */
+  int ExitValue;
+  
   /* Index of last pipe to report data, if any.  */
   int CurrentIndex;
   
@@ -218,7 +224,7 @@ kwsysProcess* kwsysProcess_New()
   ZeroMemory(cp, sizeof(*cp));
   
   /* Set initial status.  */
-  cp->State = kwsysProcess_Starting;
+  cp->State = kwsysProcess_State_Starting;
   
   /* Choose a method of running the child based on version of
      windows.  */
@@ -368,7 +374,7 @@ void kwsysProcess_Delete(kwsysProcess* cp)
   int i;
 
   /* If the process is executing, wait for it to finish.  */
-  if(cp->State == kwsysProcess_Executing)
+  if(cp->State == kwsysProcess_State_Executing)
     {
     kwsysProcess_WaitForExit(cp, 0);
     }
@@ -562,6 +568,18 @@ int kwsysProcess_GetState(kwsysProcess* cp)
   return cp->State;
 }
 
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitException(kwsysProcess* cp)
+{
+  return cp->ExitException;
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysProcess_GetExitValue(kwsysProcess* cp)
+{
+  return cp->ExitValue;
+}
+
 /*--------------------------------------------------------------------------*/
 int kwsysProcess_GetExitCode(kwsysProcess* cp)
 {
@@ -571,7 +589,11 @@ int kwsysProcess_GetExitCode(kwsysProcess* cp)
 /*--------------------------------------------------------------------------*/
 const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
 {
-  return cp->ErrorMessage;
+  if(cp->State == kwsysProcess_State_Error)
+    {
+    return cp->ErrorMessage;
+    }
+  return 0;
 }
 
 /*--------------------------------------------------------------------------*/
@@ -583,7 +605,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
   STARTUPINFO si;
   
   /* Do not execute a second time.  */
-  if(cp->State == kwsysProcess_Executing)
+  if(cp->State == kwsysProcess_State_Executing)
     {
     return;
     }
@@ -596,6 +618,9 @@ void kwsysProcess_Execute(kwsysProcess* cp)
   cp->TimeoutExpired = 0;
   cp->Terminated = 0;
   cp->Killed = 0;
+  cp->ExitException = kwsysProcess_Exception_None;
+  cp->ExitCode = 1;
+  cp->ExitValue = 1;
   
   /* Reset error data.  */
   cp->ErrorMessage[0] = 0;
@@ -701,7 +726,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
   cp->PipesLeft = cp->PipeCount;
   
   /* The process has now started.  */
-  cp->State = kwsysProcess_Executing;
+  cp->State = kwsysProcess_State_Executing;
 }
 
 /*--------------------------------------------------------------------------*/
@@ -721,7 +746,8 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng
   HANDLE events[2];
   
   /* Make sure we are executing a process.  */
-  if(cp->State != kwsysProcess_Executing || cp->Killed || cp->TimeoutExpired)
+  if(cp->State != kwsysProcess_State_Executing || cp->Killed ||
+     cp->TimeoutExpired)
     {
     return 0;
     }
@@ -866,7 +892,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, int pipes, char** data, int* leng
     if(user)
       {
       /* The user timeout has expired.  It has no time left.  */
-      return kwsysProcess_Timeout;
+      return kwsysProcess_Pipe_Timeout;
       }
     else
       {
@@ -890,11 +916,8 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   int i;
   int pipe = 0;
   
-  /* Buffer for child's return value.  */
-  int childReturnValue = 0;
-  
   /* Make sure we are executing a process.  */
-  if(cp->State != kwsysProcess_Executing)
+  if(cp->State != kwsysProcess_State_Executing)
     {
     return 1;
     }
@@ -902,7 +925,7 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   /* Wait for the process to terminate.  Ignore all data.  */
   while((pipe = kwsysProcess_WaitForData(cp, 0, 0, 0, userTimeout)) > 0)
     {
-    if(pipe == kwsysProcess_Timeout)
+    if(pipe == kwsysProcess_Pipe_Timeout)
       {
       /* The user timeout has expired.  */
       return 0;
@@ -936,30 +959,72 @@ int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
   if(cp->Killed)
     {
     /* We killed the child.  */
-    cp->State = kwsysProcess_Killed;
+    cp->State = kwsysProcess_State_Killed;
     }
   else if(cp->ErrorMessageLength)
     {
     /* Failed to run the process.  */
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     }
   else if(cp->TimeoutExpired)
     {
     /* The timeout expired.  */
-    cp->State = kwsysProcess_Expired;
+    cp->State = kwsysProcess_State_Expired;
     }
   else if(GetExitCodeProcess(cp->ProcessInformation.hProcess,
-                             &childReturnValue))
+                             &cp->ExitCode))
     {
     /* The child exited.  */
-    cp->State = kwsysProcess_Exited;
-    cp->ExitCode = childReturnValue;
+    cp->State = kwsysProcess_State_Exited;
+    if(cp->ExitCode & 0xC0000000)
+      {
+      /* Child terminated due to exceptional behavior.  */
+      switch (cp->ExitCode)
+        {
+        case CONTROL_C_EXIT:          
+          cp->ExitException = kwsysProcess_Exception_Interrupt; break;
+
+        case EXCEPTION_FLT_DENORMAL_OPERAND:
+        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+        case EXCEPTION_FLT_INEXACT_RESULT:
+        case EXCEPTION_FLT_INVALID_OPERATION:
+        case EXCEPTION_FLT_OVERFLOW:
+        case EXCEPTION_FLT_STACK_CHECK:
+        case EXCEPTION_FLT_UNDERFLOW:
+        case EXCEPTION_INT_DIVIDE_BY_ZERO:
+        case EXCEPTION_INT_OVERFLOW:
+          cp->ExitException = kwsysProcess_Exception_Numerical; break;
+
+        case EXCEPTION_ACCESS_VIOLATION:
+        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+        case EXCEPTION_DATATYPE_MISALIGNMENT:
+        case EXCEPTION_INVALID_DISPOSITION:
+        case EXCEPTION_IN_PAGE_ERROR:
+        case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+        case EXCEPTION_STACK_OVERFLOW:
+          cp->ExitException = kwsysProcess_Exception_Fault; break;
+
+        case EXCEPTION_ILLEGAL_INSTRUCTION:
+        case EXCEPTION_PRIV_INSTRUCTION:
+          cp->ExitException = kwsysProcess_Exception_Illegal; break;
+
+        default:
+          cp->ExitException = kwsysProcess_Exception_Other; break;
+        }
+      cp->ExitValue = 1;
+      }
+    else
+      {
+      /* Child exited normally.  */
+      cp->ExitException = kwsysProcess_Exception_None;
+      cp->ExitValue = cp->ExitCode & 0x000000FF;
+      }
     }
   else
     {
     /* Error getting the child return code.  */
     strcpy(cp->ErrorMessage, "Error getting child return code.");
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     }
   
   /* The child process is terminated.  */
@@ -974,8 +1039,8 @@ void kwsysProcess_Kill(kwsysProcess* cp)
   int i;
   
   /* Make sure we are executing a process.  */
-  if(cp->State != kwsysProcess_Executing || cp->TimeoutExpired || cp->Killed ||
-     cp->Terminated)
+  if(cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
+     cp->Killed || cp->Terminated)
     {
     return;
     }
@@ -1105,7 +1170,7 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   0, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                   cp->ErrorMessage, CMPE_PIPE_BUFFER_SIZE, 0); 
-    cp->State = kwsysProcess_Error;
+    cp->State = kwsysProcess_State_Error;
     }
   
   /* Free memory.  */
diff --git a/test1.cxx b/test1.cxx
index 0957d3a..7dd61a4 100644
--- a/test1.cxx
+++ b/test1.cxx
@@ -11,7 +11,8 @@ int main()
   kwsysProcess_Execute(kp);
   char* data = 0;
   int length = 0;
-  while(kwsysProcess_WaitForData(kp, kwsysProcess_STDOUT | kwsysProcess_STDERR,
+  while(kwsysProcess_WaitForData(kp, (kwsysProcess_Pipe_STDOUT |
+                                      kwsysProcess_Pipe_STDERR),
                                  &data, &length, 0))
     {
     kwsys_std::cout.write(data, length);
-- 
GitLab