diff options
author | Brad King <brad.king@kitware.com> | 2008-09-26 12:24:25 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-09-26 12:24:25 (GMT) |
commit | d6643ebba469d2ac7da20a7aed5da88b11daabd2 (patch) | |
tree | 2c1befc9f226d54da1852c90a596d37ff7e03451 /Source | |
parent | 014f684317ec67cabc4ee70a6f9e576c0d395834 (diff) | |
download | CMake-d6643ebba469d2ac7da20a7aed5da88b11daabd2.zip CMake-d6643ebba469d2ac7da20a7aed5da88b11daabd2.tar.gz CMake-d6643ebba469d2ac7da20a7aed5da88b11daabd2.tar.bz2 |
BUG: Fix SharedForward with spaces on windows
The windows execvp function does not re-escape arguments correctly.
Instead we generate the escape sequences before calling it.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/kwsys/SharedForward.h.in | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index e2be6c9..87f53dc 100644 --- a/Source/kwsys/SharedForward.h.in +++ b/Source/kwsys/SharedForward.h.in @@ -157,6 +157,7 @@ # include <io.h> # include <windows.h> # include <process.h> +# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ #else # include <unistd.h> # include <sys/stat.h> @@ -269,6 +270,146 @@ static const char kwsys_shared_forward_path_slash[2] = {KWSYS_SHARED_FORWARD_PAT # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" #endif +#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV +/*--------------------------------------------------------------------------*/ +typedef struct kwsys_sf_arg_info_s +{ + const char* arg; + int size; + int quote; +} kwsys_sf_arg_info; + +/*--------------------------------------------------------------------------*/ +static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) +{ + /* Initialize information. */ + kwsys_sf_arg_info info; + + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Start with the length of the original argument, plus one for + either a terminating null or a separating space. */ + info.arg = in; + info.size = (int)strlen(in) + 1; + info.quote = 0; + + /* Scan the string for characters that require escaping or quoting. */ + for(c=in; *c; ++c) + { + /* Check whether this character needs quotes. */ + if(strchr(" \t?'#&<>|^", *c)) + { + info.quote = 1; + } + + /* On Windows only backslashes and double-quotes need escaping. */ + if(*c == '\\') + { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } + else if(*c == '"') + { + /* Found a double-quote. We need to escape it and all + immediately preceding backslashes. */ + info.size += windows_backslashes + 1; + windows_backslashes = 0; + } + else + { + /* Found another character. This eliminates the possibility + that any immediately preceding backslashes will be + escaped. */ + windows_backslashes = 0; + } + } + + /* Check whether the argument needs surrounding quotes. */ + if(info.quote) + { + /* Surrounding quotes are needed. Allocate space for them. */ + info.size += 2; + + /* We must escape all ending backslashes when quoting on windows. */ + info.size += windows_backslashes; + } + + return info; +} + +/*--------------------------------------------------------------------------*/ +static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) +{ + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Whether the argument must be quoted. */ + if(info.quote) + { + /* Add the opening quote for this argument. */ + *out++ = '"'; + } + + /* Scan the string for characters that require escaping or quoting. */ + for(c=info.arg; *c; ++c) + { + /* On Windows only backslashes and double-quotes need escaping. */ + if(*c == '\\') + { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } + else if(*c == '"') + { + /* Found a double-quote. Escape all immediately preceding + backslashes. */ + while(windows_backslashes > 0) + { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the backslash to escape the double-quote. */ + *out++ = '\\'; + } + else + { + /* We encountered a normal character. This eliminates any + escaping needed for preceding backslashes. */ + windows_backslashes = 0; + } + + /* Store this character. */ + *out++ = *c; + } + + if(info.quote) + { + /* Add enough backslashes to escape any trailing ones. */ + while(windows_backslashes > 0) + { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the closing quote for this argument. */ + *out++ = '"'; + } + + /* Store a terminating null without incrementing. */ + *out = 0; + + return out; +} +#endif + /*--------------------------------------------------------------------------*/ /* Function to convert a logical or relative path to a physical full path. */ static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) @@ -341,8 +482,34 @@ static void kwsys_shared_forward_strerror(char* message) /*--------------------------------------------------------------------------*/ /* Functions to execute a child process. */ -static void kwsys_shared_forward_execvp(const char* cmd, char* const argv[]) +static void kwsys_shared_forward_execvp(const char* cmd, char* const* argv) { +#ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV + /* Count the number of arguments. */ + int argc = 0; + { + char* const* argvc; + for(argvc = argv; *argvc; ++argvc,++argc) {} + } + + /* Create the escaped arguments. */ + { + char** nargv = (char**)malloc((argc+1) * sizeof(char*)); + int i; + for(i=0; i < argc; ++i) + { + kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); + nargv[i] = (char*)malloc(info.size); + kwsys_sf_get_arg(info, nargv[i]); + } + nargv[argc] = 0; + + /* Replace the command line to be used. */ + argv = nargv; + } +#endif + + /* Invoke the child process. */ #if defined(_MSC_VER) _execvp(cmd, argv); #else |