ENH: Added Option_Verbatim to run whole command lines directly.
This commit is contained in:
parent
6071052835
commit
6438bec4c9
|
@ -36,6 +36,7 @@
|
|||
#define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared)
|
||||
#define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach)
|
||||
#define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow)
|
||||
#define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim)
|
||||
#define kwsysProcess_GetOption kwsys_ns(Process_GetOption)
|
||||
#define kwsysProcess_SetOption kwsys_ns(Process_SetOption)
|
||||
#define kwsysProcess_Option_e kwsys_ns(Process_Option_e)
|
||||
|
@ -154,6 +155,13 @@ kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe,
|
|||
* kwsysProcess_Option_HideWindow = Whether to hide window on Windows.
|
||||
* 0 = No (default)
|
||||
* 1 = Yes
|
||||
*
|
||||
* kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand
|
||||
* should treat the first argument
|
||||
* as a verbatim command line
|
||||
* and ignore the rest of the arguments.
|
||||
* 0 = No (default)
|
||||
* 1 = Yes
|
||||
*/
|
||||
kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId);
|
||||
kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
|
||||
|
@ -161,7 +169,8 @@ kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId,
|
|||
enum kwsysProcess_Option_e
|
||||
{
|
||||
kwsysProcess_Option_HideWindow,
|
||||
kwsysProcess_Option_Detach
|
||||
kwsysProcess_Option_Detach,
|
||||
kwsysProcess_Option_Verbatim
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -343,6 +352,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
|
|||
# undef kwsysProcess_SetPipeShared
|
||||
# undef kwsysProcess_Option_Detach
|
||||
# undef kwsysProcess_Option_HideWindow
|
||||
# undef kwsysProcess_Option_Verbatim
|
||||
# undef kwsysProcess_GetOption
|
||||
# undef kwsysProcess_SetOption
|
||||
# undef kwsysProcess_Option_e
|
||||
|
|
|
@ -60,6 +60,7 @@ do.
|
|||
#include <time.h> /* gettimeofday */
|
||||
#include <signal.h> /* sigaction */
|
||||
#include <dirent.h> /* DIR, dirent */
|
||||
#include <ctype.h> /* isspace */
|
||||
|
||||
/* The number of pipes for the child's output. The standard stdout
|
||||
and stderr pipes are the first two. One more pipe is used to
|
||||
|
@ -122,6 +123,7 @@ static int kwsysProcessesAdd(kwsysProcess* cp);
|
|||
static void kwsysProcessesRemove(kwsysProcess* cp);
|
||||
static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
|
||||
void* ucontext);
|
||||
static char** kwsysProcessParseVerbatimCommand(const char* command);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Structure containing data used to implement the child's execution. */
|
||||
|
@ -159,6 +161,9 @@ struct kwsysProcess_s
|
|||
/* Whether the child was created as a detached process. */
|
||||
int Detached;
|
||||
|
||||
/* Whether to treat command lines as verbatim. */
|
||||
int Verbatim;
|
||||
|
||||
/* Time at which the child started. Negative for no timeout. */
|
||||
kwsysProcessTime StartTime;
|
||||
|
||||
|
@ -309,7 +314,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;
|
||||
}
|
||||
|
@ -332,39 +337,54 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
|
|||
}
|
||||
|
||||
/* Add the new command. */
|
||||
{
|
||||
char const* const* c = command;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
while(*c++);
|
||||
n = c - command - 1;
|
||||
newCommands[cp->NumberOfCommands] = (char**)malloc((n+1)*sizeof(char*));
|
||||
if(!newCommands[cp->NumberOfCommands])
|
||||
if(cp->Verbatim)
|
||||
{
|
||||
/* Out of memory. */
|
||||
free(newCommands);
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i < n; ++i)
|
||||
{
|
||||
newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
|
||||
if(!newCommands[cp->NumberOfCommands][i])
|
||||
/* In order to run the given command line verbatim we need to
|
||||
parse it. */
|
||||
newCommands[cp->NumberOfCommands] =
|
||||
kwsysProcessParseVerbatimCommand(*command);
|
||||
if(!newCommands[cp->NumberOfCommands])
|
||||
{
|
||||
break;
|
||||
/* Out of memory. */
|
||||
free(newCommands);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(i < n)
|
||||
else
|
||||
{
|
||||
/* Out of memory. */
|
||||
for(;i > 0; --i)
|
||||
/* Copy each argument string individually. */
|
||||
char const* const* c = command;
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
while(*c++);
|
||||
n = c - command - 1;
|
||||
newCommands[cp->NumberOfCommands] = (char**)malloc((n+1)*sizeof(char*));
|
||||
if(!newCommands[cp->NumberOfCommands])
|
||||
{
|
||||
free(newCommands[cp->NumberOfCommands][i-1]);
|
||||
/* Out of memory. */
|
||||
free(newCommands);
|
||||
return 0;
|
||||
}
|
||||
free(newCommands);
|
||||
return 0;
|
||||
for(i=0; i < n; ++i)
|
||||
{
|
||||
newCommands[cp->NumberOfCommands][i] = strdup(command[i]);
|
||||
if(!newCommands[cp->NumberOfCommands][i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i < n)
|
||||
{
|
||||
/* Out of memory. */
|
||||
for(;i > 0; --i)
|
||||
{
|
||||
free(newCommands[cp->NumberOfCommands][i-1]);
|
||||
}
|
||||
free(newCommands);
|
||||
return 0;
|
||||
}
|
||||
newCommands[cp->NumberOfCommands][n] = 0;
|
||||
}
|
||||
newCommands[cp->NumberOfCommands][n] = 0;
|
||||
}
|
||||
|
||||
/* Successfully allocated new command array. Free the old array. */
|
||||
free(cp->Commands);
|
||||
|
@ -492,6 +512,7 @@ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
|
|||
switch(optionId)
|
||||
{
|
||||
case kwsysProcess_Option_Detach: return cp->OptionDetach;
|
||||
case kwsysProcess_Option_Verbatim: return cp->Verbatim;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -507,6 +528,7 @@ void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
|
|||
switch(optionId)
|
||||
{
|
||||
case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
|
||||
case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -2256,3 +2278,256 @@ static void kwsysProcessesSignalHandler(int signum, siginfo_t* info,
|
|||
write(cp->SignalPipe, &buf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int kwsysProcessAppendByte(char* local,
|
||||
char** begin, char** end,
|
||||
int* size, char c)
|
||||
{
|
||||
/* Allocate space for the character. */
|
||||
if((*end - *begin) >= *size)
|
||||
{
|
||||
int length = *end - *begin;
|
||||
char* newBuffer = (char*)malloc(*size*2);
|
||||
if(!newBuffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(newBuffer, *begin, length*sizeof(char));
|
||||
if(*begin != local)
|
||||
{
|
||||
free(*begin);
|
||||
}
|
||||
*begin = newBuffer;
|
||||
*end = *begin + length;
|
||||
*size *= 2;
|
||||
}
|
||||
|
||||
/* Store the character. */
|
||||
*(*end)++ = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int kwsysProcessAppendArgument(char** local,
|
||||
char*** begin, char*** end,
|
||||
int* size,
|
||||
char* arg_local,
|
||||
char** arg_begin, char** arg_end,
|
||||
int* arg_size)
|
||||
{
|
||||
/* Append a null-terminator to the argument string. */
|
||||
if(!kwsysProcessAppendByte(arg_local, arg_begin, arg_end, arg_size, '\0'))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate space for the argument pointer. */
|
||||
if((*end - *begin) >= *size)
|
||||
{
|
||||
int length = *end - *begin;
|
||||
char** newPointers = (char**)malloc(*size*2*sizeof(char*));
|
||||
if(!newPointers)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(newPointers, *begin, length*sizeof(char*));
|
||||
if(*begin != local)
|
||||
{
|
||||
free(*begin);
|
||||
}
|
||||
*begin = newPointers;
|
||||
*end = *begin + length;
|
||||
*size *= 2;
|
||||
}
|
||||
|
||||
/* Allocate space for the argument string. */
|
||||
**end = (char*)malloc(*arg_end - *arg_begin);
|
||||
if(!**end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Store the argument in the command array. */
|
||||
memcpy(**end, *arg_begin, *arg_end - *arg_begin);
|
||||
++(*end);
|
||||
|
||||
/* Reset the argument to be empty. */
|
||||
*arg_end = *arg_begin;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
#define KWSYSPE_LOCAL_BYTE_COUNT 1024
|
||||
#define KWSYSPE_LOCAL_ARGS_COUNT 32
|
||||
static char** kwsysProcessParseVerbatimCommand(const char* command)
|
||||
{
|
||||
/* Create a buffer for argument pointers during parsing. */
|
||||
char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT];
|
||||
int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT;
|
||||
char** pointer_begin = local_pointers;
|
||||
char** pointer_end = pointer_begin;
|
||||
|
||||
/* Create a buffer for argument strings during parsing. */
|
||||
char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT];
|
||||
int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT;
|
||||
char* buffer_begin = local_buffer;
|
||||
char* buffer_end = buffer_begin;
|
||||
|
||||
/* Parse the command string. Try to behave like a UNIX shell. */
|
||||
char** newCommand = 0;
|
||||
const char* c = command;
|
||||
int in_argument = 0;
|
||||
int in_escape = 0;
|
||||
int in_single = 0;
|
||||
int in_double = 0;
|
||||
int failed = 0;
|
||||
for(;*c; ++c)
|
||||
{
|
||||
if(in_escape)
|
||||
{
|
||||
/* This character is escaped so do no special handling. */
|
||||
if(!in_argument)
|
||||
{
|
||||
in_argument = 1;
|
||||
}
|
||||
if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
|
||||
&buffer_end, &buffer_size, *c))
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
in_escape = 0;
|
||||
}
|
||||
else if(*c == '\\' && !in_single)
|
||||
{
|
||||
/* The next character should be escaped. */
|
||||
in_escape = 1;
|
||||
}
|
||||
else if(*c == '\'' && !in_double)
|
||||
{
|
||||
/* Enter or exit single-quote state. */
|
||||
if(in_single)
|
||||
{
|
||||
in_single = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_single = 1;
|
||||
if(!in_argument)
|
||||
{
|
||||
in_argument = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*c == '"' && !in_single)
|
||||
{
|
||||
/* Enter or exit double-quote state. */
|
||||
if(in_double)
|
||||
{
|
||||
in_double = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_double = 1;
|
||||
if(!in_argument)
|
||||
{
|
||||
in_argument = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(isspace(*c))
|
||||
{
|
||||
if(in_argument)
|
||||
{
|
||||
if(in_single || in_double)
|
||||
{
|
||||
/* This space belongs to a quoted argument. */
|
||||
if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
|
||||
&buffer_end, &buffer_size, *c))
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This argument has been terminated by whitespace. */
|
||||
if(!kwsysProcessAppendArgument(local_pointers, &pointer_begin,
|
||||
&pointer_end, &pointers_size,
|
||||
local_buffer, &buffer_begin,
|
||||
&buffer_end, &buffer_size))
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
in_argument = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This character belong to an argument. */
|
||||
if(!in_argument)
|
||||
{
|
||||
in_argument = 1;
|
||||
}
|
||||
if(!kwsysProcessAppendByte(local_buffer, &buffer_begin,
|
||||
&buffer_end, &buffer_size, *c))
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish the last argument. */
|
||||
if(in_argument)
|
||||
{
|
||||
if(!kwsysProcessAppendArgument(local_pointers, &pointer_begin,
|
||||
&pointer_end, &pointers_size,
|
||||
local_buffer, &buffer_begin,
|
||||
&buffer_end, &buffer_size))
|
||||
{
|
||||
failed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we still have memory allocate space for the new command
|
||||
buffer. */
|
||||
if(!failed)
|
||||
{
|
||||
int n = pointer_end - pointer_begin;
|
||||
newCommand = (char**)malloc((n+1)*sizeof(char*));
|
||||
}
|
||||
|
||||
if(newCommand)
|
||||
{
|
||||
/* Copy the arguments into the new command buffer. */
|
||||
int n = pointer_end - pointer_begin;
|
||||
memcpy(newCommand, pointer_begin, sizeof(char*)*n);
|
||||
newCommand[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Free arguments already allocated. */
|
||||
while(pointer_end != pointer_begin)
|
||||
{
|
||||
free(*(--pointer_end));
|
||||
}
|
||||
}
|
||||
|
||||
/* Free temporary buffers. */
|
||||
if(pointer_begin != local_pointers)
|
||||
{
|
||||
free(pointer_begin);
|
||||
}
|
||||
if(buffer_begin != local_buffer)
|
||||
{
|
||||
free(buffer_begin);
|
||||
}
|
||||
|
||||
/* Return the final command buffer. */
|
||||
return newCommand;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,11 @@ 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,
|
||||
|
@ -206,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;
|
||||
|
||||
|
@ -646,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;
|
||||
}
|
||||
|
@ -669,77 +677,19 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
|
|||
}
|
||||
|
||||
/* We need to construct a single string representing the command
|
||||
and its arguments. We will surround each argument containing
|
||||
spaces with double-quotes. Inside a double-quoted argument, we
|
||||
need to escape double-quotes and all backslashes before them.
|
||||
We also need to escape backslashes at the end of an argument
|
||||
because they come before the closing double-quote for the
|
||||
argument. */
|
||||
and its arguments. We will surround each argument containing
|
||||
spaces with double-quotes. Inside a double-quoted argument, we
|
||||
need to escape double-quotes and all backslashes before them.
|
||||
We also need to escape backslashes at the end of an argument
|
||||
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
|
||||
the first argument that we will not use. */
|
||||
byte for the terminating null because we allocated a space for
|
||||
the first argument that we will not use. */
|
||||
newCommands[cp->NumberOfCommands] = (char*)malloc(length);
|
||||
if(!newCommands[cp->NumberOfCommands])
|
||||
{
|
||||
|
@ -749,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. */
|
||||
|
@ -968,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;
|
||||
}
|
||||
}
|
||||
|
@ -984,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;
|
||||
}
|
||||
}
|
||||
|
@ -2198,6 +2064,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 = 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. */
|
||||
|
|
Loading…
Reference in New Issue