summaryrefslogtreecommitdiff
path: root/Source/kwsys/ProcessWin32.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/kwsys/ProcessWin32.c')
-rw-r--r--Source/kwsys/ProcessWin32.c407
1 files changed, 248 insertions, 159 deletions
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 97e5706764..6929c3e443 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -104,8 +104,14 @@ static void kwsysProcessDestroy(kwsysProcess* cp, int event);
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
static int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
static void kwsysProcessCleanupHandle(PHANDLE h);
+static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle);
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
+static int kwsysProcessComputeCommandLength(kwsysProcess* cp,
+ char const* const* command);
+static void kwsysProcessComputeCommandLine(kwsysProcess* cp,
+ char const* const* command,
+ char* cmd);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -205,6 +211,9 @@ struct kwsysProcess_s
/* Whether to hide the child process's window. */
int HideWindow;
+ /* Whether to treat command lines as verbatim. */
+ int Verbatim;
+
/* On Win9x platforms, the path to the forwarding executable. */
char* Win9x;
@@ -645,7 +654,7 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
char** newCommands;
/* Make sure we have a command to add. */
- if(!cp || !command)
+ if(!cp || !command || !*command)
{
return 0;
}
@@ -675,66 +684,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
because they come before the closing double-quote for the
argument. */
{
- char* cmd;
- char const* const* arg;
- int length = 0;
/* First determine the length of the final string. */
- for(arg = command; *arg; ++arg)
- {
- /* Keep track of how many backslashes have been encountered in a
- row in this argument. */
- int backslashes = 0;
- int spaces = 0;
- const char* c;
-
- /* Scan the string for spaces. If there are no spaces, we can
- pass the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- if(*c == ' ' || *c == '\t')
- {
- spaces = 1;
- break;
- }
- }
-
- /* Add the length of the argument, plus 1 for the space
- separating the arguments. */
- length += (int)strlen(*arg) + 1;
-
- if(spaces)
- {
- /* Add 2 for double quotes since spaces are present. */
- length += 2;
-
- /* Scan the string to find characters that need escaping. */
- for(c=*arg; *c; ++c)
- {
- if(*c == '\\')
- {
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
- }
- else if(*c == '"')
- {
- /* Found a double-quote. We need to escape it and all
- immediately preceding backslashes. */
- length += backslashes + 1;
- backslashes = 0;
- }
- else
- {
- /* Found another character. This eliminates the possibility
- that any immediately preceding backslashes will be
- escaped. */
- backslashes = 0;
- }
- }
-
- /* We need to escape all ending backslashes. */
- length += backslashes;
- }
- }
+ int length = kwsysProcessComputeCommandLength(cp, command);
/* Allocate enough space for the command. We do not need an extra
byte for the terminating null because we allocated a space for
@@ -748,94 +699,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
}
/* Construct the command line in the allocated buffer. */
- cmd = newCommands[cp->NumberOfCommands];
- for(arg = command; *arg; ++arg)
- {
- /* Keep track of how many backslashes have been encountered in a
- row in an argument. */
- int backslashes = 0;
- int spaces = 0;
- const char* c;
-
- /* Scan the string for spaces. If there are no spaces, we can
- pass the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- if(*c == ' ' || *c == '\t')
- {
- spaces = 1;
- break;
- }
- }
-
- /* Add the separating space if this is not the first argument. */
- if(arg != command)
- {
- *cmd++ = ' ';
- }
-
- if(spaces)
- {
- /* Add the opening double-quote for this argument. */
- *cmd++ = '"';
-
- /* Add the characters of the argument, possibly escaping them. */
- for(c=*arg; *c; ++c)
- {
- if(*c == '\\')
- {
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
- *cmd++ = '\\';
- }
- else if(*c == '"')
- {
- /* Add enough backslashes to escape any that preceded the
- double-quote. */
- while(backslashes > 0)
- {
- --backslashes;
- *cmd++ = '\\';
- }
-
- /* Add the backslash to escape the double-quote. */
- *cmd++ = '\\';
-
- /* Add the double-quote itself. */
- *cmd++ = '"';
- }
- else
- {
- /* We encountered a normal character. This eliminates any
- escaping needed for preceding backslashes. Add the
- character. */
- backslashes = 0;
- *cmd++ = *c;
- }
- }
-
- /* Add enough backslashes to escape any trailing ones. */
- while(backslashes > 0)
- {
- --backslashes;
- *cmd++ = '\\';
- }
-
- /* Add the closing double-quote for this argument. */
- *cmd++ = '"';
- }
- else
- {
- /* No spaces. Add the argument verbatim. */
- for(c=*arg; *c; ++c)
- {
- *cmd++ = *c;
- }
- }
- }
-
- /* Add the terminating null character to the command line. */
- *cmd = 0;
+ kwsysProcessComputeCommandLine(cp, command,
+ newCommands[cp->NumberOfCommands]);
}
/* Save the new array of commands. */
@@ -967,6 +832,7 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
case kwsysProcess_Option_Detach: return cp->OptionDetach;
case kwsysProcess_Option_HideWindow: return cp->HideWindow;
+ case kwsysProcess_Option_Verbatim: return cp->Verbatim;
default: return 0;
}
}
@@ -983,6 +849,7 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
+ case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
default: break;
}
}
@@ -1145,7 +1012,8 @@ void kwsysProcess_Execute(kwsysProcess* cp)
&si.StartupInfo.hStdError))
{
kwsysProcessCleanup(cp, 1);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
+ STD_ERROR_HANDLE);
return;
}
}
@@ -1166,9 +1034,12 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* Release resources that may have been allocated for this
process before an error occurred. */
kwsysProcessCleanupHandle(&readEnd);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdInput,
+ STD_INPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdOutput,
+ STD_OUTPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
+ STD_ERROR_HANDLE);
kwsysProcessCleanupHandle(&si.ErrorPipeRead);
kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
return;
@@ -1183,7 +1054,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
processes in the pipeline. The stdout and stdin pipes are not
shared among all children and are therefore closed by
kwsysProcessCreate after each child is created. */
- kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
+ kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE);
/* Restore the working directory. */
if(cp->RealWorkingDirectory)
@@ -1493,7 +1364,7 @@ void kwsysProcess_Kill(kwsysProcess* cp)
/* Make sure we are executing a process. */
if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
- cp->Killed || cp->Terminated)
+ cp->Killed)
{
return;
}
@@ -1501,6 +1372,12 @@ void kwsysProcess_Kill(kwsysProcess* cp)
/* Disable the reading threads. */
kwsysProcessDisablePipeThreads(cp);
+ /* Skip actually killing the child if it has already terminated. */
+ if(cp->Terminated)
+ {
+ return;
+ }
+
/* Kill the children. */
cp->Killed = 1;
if(cp->Win9x)
@@ -1897,8 +1774,10 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
process's copies of the inherited stdout and stdin handles. The
stderr handle is shared among all children and is closed by
kwsysProcess_Execute after all children have been created. */
- kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
- kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
+ kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdInput,
+ STD_INPUT_HANDLE);
+ kwsysProcessCleanupHandleSafe(&si->StartupInfo.hStdOutput,
+ STD_OUTPUT_HANDLE);
return 1;
}
@@ -1984,13 +1863,27 @@ int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
/*--------------------------------------------------------------------------*/
int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
{
+ /* Check whether the handle to be shared is already inherited. */
+ DWORD flags;
+ int inherited = 0;
+ if(GetHandleInformation(GetStdHandle(nStdHandle), &flags) &&
+ (flags & HANDLE_FLAG_INHERIT))
+ {
+ inherited = 1;
+ }
+
/* Cleanup the previous handle. */
kwsysProcessCleanupHandle(handle);
- /* Duplicate the standard handle to be sure it is inherited and can
- be closed later. Do not close the original handle when
+ /* If the standard handle is not inherited then duplicate it to
+ create an inherited copy. Do not close the original handle when
duplicating! */
- if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle),
+ if(inherited)
+ {
+ *handle = GetStdHandle(nStdHandle);
+ return 1;
+ }
+ else if(DuplicateHandle(GetCurrentProcess(), GetStdHandle(nStdHandle),
GetCurrentProcess(), handle,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
@@ -2046,6 +1939,19 @@ void kwsysProcessCleanupHandle(PHANDLE h)
/*--------------------------------------------------------------------------*/
+/* Close the given handle if it is open and not a standard handle.
+ Reset its value to 0. */
+void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle)
+{
+ if(h && *h && (*h != GetStdHandle(nStdHandle)))
+ {
+ CloseHandle(*h);
+ *h = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
/* Close all handles created by kwsysProcess_Execute. */
void kwsysProcessCleanup(kwsysProcess* cp, int error)
{
@@ -2159,6 +2065,189 @@ void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
}
/*--------------------------------------------------------------------------*/
+int kwsysProcessComputeCommandLength(kwsysProcess* cp,
+ char const* const* command)
+{
+ int length = 0;
+ if(cp->Verbatim)
+ {
+ /* Treat the first argument as a verbatim command line. Use its
+ length directly and add space for the null-terminator. */
+ length = (int)strlen(*command)+1;
+ }
+ else
+ {
+ /* Compute the length of the command line when it is converted to
+ a single string. Space for the null-terminator is allocated by
+ the whitespace character allocated for the first argument that
+ will not be used. */
+ char const* const* arg;
+ for(arg = command; *arg; ++arg)
+ {
+ /* Keep track of how many backslashes have been encountered in a
+ row in this argument. */
+ int backslashes = 0;
+ int spaces = 0;
+ const char* c;
+
+ /* Scan the string for spaces. If there are no spaces, we can
+ pass the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == ' ' || *c == '\t')
+ {
+ spaces = 1;
+ break;
+ }
+ }
+
+ /* Add the length of the argument, plus 1 for the space
+ separating the arguments. */
+ length += (int)strlen(*arg) + 1;
+
+ if(spaces)
+ {
+ /* Add 2 for double quotes since spaces are present. */
+ length += 2;
+
+ /* Scan the string to find characters that need escaping. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++backslashes;
+ }
+ else if(*c == '"')
+ {
+ /* Found a double-quote. We need to escape it and all
+ immediately preceding backslashes. */
+ length += backslashes + 1;
+ backslashes = 0;
+ }
+ else
+ {
+ /* Found another character. This eliminates the possibility
+ that any immediately preceding backslashes will be
+ escaped. */
+ backslashes = 0;
+ }
+ }
+
+ /* We need to escape all ending backslashes. */
+ length += backslashes;
+ }
+ }
+ }
+
+ return length;
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcessComputeCommandLine(kwsysProcess* cp,
+ char const* const* command,
+ char* cmd)
+{
+ if(cp->Verbatim)
+ {
+ /* Copy the verbatim command line into the buffer. */
+ strcpy(cmd, *command);
+ }
+ else
+ {
+ /* Construct the command line in the allocated buffer. */
+ char const* const* arg;
+ for(arg = command; *arg; ++arg)
+ {
+ /* Keep track of how many backslashes have been encountered in a
+ row in an argument. */
+ int backslashes = 0;
+ int spaces = 0;
+ const char* c;
+
+ /* Scan the string for spaces. If there are no spaces, we can
+ pass the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == ' ' || *c == '\t')
+ {
+ spaces = 1;
+ break;
+ }
+ }
+
+ /* Add the separating space if this is not the first argument. */
+ if(arg != command)
+ {
+ *cmd++ = ' ';
+ }
+
+ if(spaces)
+ {
+ /* Add the opening double-quote for this argument. */
+ *cmd++ = '"';
+
+ /* Add the characters of the argument, possibly escaping them. */
+ for(c=*arg; *c; ++c)
+ {
+ if(*c == '\\')
+ {
+ /* Found a backslash. It may need to be escaped later. */
+ ++backslashes;
+ *cmd++ = '\\';
+ }
+ else if(*c == '"')
+ {
+ /* Add enough backslashes to escape any that preceded the
+ double-quote. */
+ while(backslashes > 0)
+ {
+ --backslashes;
+ *cmd++ = '\\';
+ }
+
+ /* Add the backslash to escape the double-quote. */
+ *cmd++ = '\\';
+
+ /* Add the double-quote itself. */
+ *cmd++ = '"';
+ }
+ else
+ {
+ /* We encountered a normal character. This eliminates any
+ escaping needed for preceding backslashes. Add the
+ character. */
+ backslashes = 0;
+ *cmd++ = *c;
+ }
+ }
+
+ /* Add enough backslashes to escape any trailing ones. */
+ while(backslashes > 0)
+ {
+ --backslashes;
+ *cmd++ = '\\';
+ }
+
+ /* Add the closing double-quote for this argument. */
+ *cmd++ = '"';
+ }
+ else
+ {
+ /* No spaces. Add the argument verbatim. */
+ for(c=*arg; *c; ++c)
+ {
+ *cmd++ = *c;
+ }
+ }
+ }
+
+ /* Add the terminating null character to the command line. */
+ *cmd = 0;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
/* Get the time at which either the process or user timeout will
expire. Returns 1 if the user timeout is first, and 0 otherwise. */
int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,