summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2006-09-27 17:43:46 (GMT)
committerBrad King <brad.king@kitware.com>2006-09-27 17:43:46 (GMT)
commitdd332a00cc0169221243a231cd2474b6521aa11a (patch)
tree85d4722d4ac0dcbf665182a4dd2fe6f48f900fc0
parent5d22d36c5da1e0838d50c90250c06ba6852fb7b4 (diff)
downloadCMake-dd332a00cc0169221243a231cd2474b6521aa11a.zip
CMake-dd332a00cc0169221243a231cd2474b6521aa11a.tar.gz
CMake-dd332a00cc0169221243a231cd2474b6521aa11a.tar.bz2
ENH: Re-implemented command line argument shell quoting to support several platforms with one code base.
-rw-r--r--Source/cmCustomCommand.cxx30
-rw-r--r--Source/cmCustomCommand.h11
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx16
-rw-r--r--Source/cmLocalGenerator.cxx52
-rw-r--r--Source/cmLocalGenerator.h9
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx12
-rw-r--r--Source/cmLocalVisualStudio6Generator.cxx8
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx25
-rw-r--r--Source/cmLocalVisualStudioGenerator.cxx13
-rw-r--r--Source/cmLocalVisualStudioGenerator.h2
-rw-r--r--Source/kwsys/ProcessWin32.c4
-rw-r--r--Source/kwsys/System.c427
-rw-r--r--Source/kwsys/System.h.in70
13 files changed, 556 insertions, 123 deletions
diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx
index 162f10f..debc805 100644
--- a/Source/cmCustomCommand.cxx
+++ b/Source/cmCustomCommand.cxx
@@ -19,6 +19,8 @@
//----------------------------------------------------------------------------
cmCustomCommand::cmCustomCommand()
{
+ this->EscapeOldStyle = true;
+ this->EscapeAllowMakeVars = false;
this->Used = false;
}
@@ -30,6 +32,8 @@ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r):
Comment(r.Comment),
WorkingDirectory(r.WorkingDirectory)
{
+ this->EscapeOldStyle = true;
+ this->EscapeAllowMakeVars = false;
this->Used = false;
}
@@ -45,6 +49,8 @@ cmCustomCommand::cmCustomCommand(const std::vector<std::string>& outputs,
Comment(comment?comment:""),
WorkingDirectory(workingDirectory?workingDirectory:"")
{
+ this->EscapeOldStyle = true;
+ this->EscapeAllowMakeVars = false;
this->Used = false;
}
@@ -81,3 +87,27 @@ const char* cmCustomCommand::GetComment() const
{
return this->Comment.c_str();
}
+
+//----------------------------------------------------------------------------
+bool cmCustomCommand::GetEscapeOldStyle() const
+{
+ return this->EscapeOldStyle;
+}
+
+//----------------------------------------------------------------------------
+void cmCustomCommand::SetEscapeOldStyle(bool b)
+{
+ this->EscapeOldStyle = b;
+}
+
+//----------------------------------------------------------------------------
+bool cmCustomCommand::GetEscapeAllowMakeVars() const
+{
+ return this->EscapeAllowMakeVars;
+}
+
+//----------------------------------------------------------------------------
+void cmCustomCommand::SetEscapeAllowMakeVars(bool b)
+{
+ this->EscapeAllowMakeVars = b;
+}
diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h
index 4fc300c..e493c5d 100644
--- a/Source/cmCustomCommand.h
+++ b/Source/cmCustomCommand.h
@@ -53,6 +53,15 @@ public:
/** Get the comment string for the command. */
const char* GetComment() const;
+ /** Set/Get whether old-style escaping should be used. */
+ bool GetEscapeOldStyle() const;
+ void SetEscapeOldStyle(bool b);
+
+ /** Set/Get whether the build tool can replace variables in
+ arguments to the command. */
+ bool GetEscapeAllowMakeVars() const;
+ void SetEscapeAllowMakeVars(bool b);
+
/** set get the used status of the command */
void SetUsed() { this->Used = true;};
bool IsUsed() { return this->Used;};
@@ -63,6 +72,8 @@ private:
cmCustomCommandLines CommandLines;
std::string Comment;
std::string WorkingDirectory;
+ bool EscapeAllowMakeVars;
+ bool EscapeOldStyle;
bool Used;
};
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index bfc8c8e..728e37e 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -962,7 +962,8 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
cmCustomCommand const& cc = *i;
if(!cc.GetCommandLines().empty())
{
-
+ bool escapeOldStyle = cc.GetEscapeOldStyle();
+ bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
makefileStream << "\n#" << "Custom command rule: " <<
cc.GetComment() << "\n";
const std::vector<std::string>& outputs = cc.GetOutputs();
@@ -1037,8 +1038,17 @@ cmGlobalXCodeGenerator::AddCommandsToBuildPhase(cmXCodeObject* buildphase,
for(unsigned int j=1; j < commandLine.size(); ++j)
{
cmd += " ";
- cmd += (this->CurrentLocalGenerator
- ->EscapeForShell(commandLine[j].c_str()));
+ if(escapeOldStyle)
+ {
+ cmd += (this->CurrentLocalGenerator
+ ->EscapeForShellOldStyle(commandLine[j].c_str()));
+ }
+ else
+ {
+ cmd += (this->CurrentLocalGenerator->
+ EscapeForShell(commandLine[j].c_str(),
+ escapeAllowMakeVars));
+ }
}
makefileStream << "\t" << cmd.c_str() << "\n";
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 34295ae..a3b48b3 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -39,6 +39,7 @@ cmLocalGenerator::cmLocalGenerator()
this->ExcludeFromAll = false;
this->Parent = 0;
this->WindowsShell = false;
+ this->WindowsVSIDE = false;
this->IgnoreLibPrefix = false;
this->UseRelativePaths = false;
this->Configured = false;
@@ -2243,12 +2244,9 @@ cmLocalGenerator
}
//----------------------------------------------------------------------------
-std::string cmLocalGenerator::EscapeForShell(const char* str)
+std::string cmLocalGenerator::EscapeForShellOldStyle(const char* str)
{
std::string result;
- // Temporarily use old shell escaping code until a means of backward
- // compatibility can be established in the new implementation.
-#if 1
bool forceOn = cmSystemTools::GetForceUnixPaths();
if(forceOn && this->WindowsShell)
{
@@ -2259,25 +2257,41 @@ std::string cmLocalGenerator::EscapeForShell(const char* str)
{
cmSystemTools::SetForceUnixPaths(true);
}
-#else
+ return result;
+}
+
+//----------------------------------------------------------------------------
+std::string cmLocalGenerator::EscapeForShell(const char* str, bool makeVars)
+{
+ // Compute the flags for the target shell environment.
+ int flags = 0;
+ if(this->WindowsVSIDE)
+ {
+ flags |= cmsysSystem_Shell_Flag_VSIDE;
+ }
+ else
+ {
+ flags |= cmsysSystem_Shell_Flag_Make;
+ }
+ if(makeVars)
+ {
+ flags |= cmsysSystem_Shell_Flag_AllowMakeVariables;
+ }
+
+ // Compute the buffer size needed.
+ int size = (this->WindowsShell ?
+ cmsysSystem_Shell_GetArgumentSizeForWindows(str, flags) :
+ cmsysSystem_Shell_GetArgumentSizeForUnix(str, flags));
+
+ // Compute the shell argument itself.
+ std::vector<char> arg(size);
if(this->WindowsShell)
{
- int size = cmsysSystem_Windows_ShellArgumentSize(str);
- std::vector<char> arg(size);
- cmsysSystem_Windows_ShellArgument(str, &arg[0]);
- result = &arg[0];
+ cmsysSystem_Shell_GetArgumentForWindows(str, &arg[0], flags);
}
else
{
- for(const char* c = str; *c; ++c)
- {
- if(*c == '\\' || *c == '\'' || *c == '"' || *c == ';' || *c == ' ')
- {
- result += "\\";
- }
- result += *c;
- }
+ cmsysSystem_Shell_GetArgumentForUnix(str, &arg[0], flags);
}
-#endif
- return result;
+ return std::string(&arg[0]);
}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 44aa79a..1f273b9 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -202,8 +202,12 @@ public:
};
/** Escape the given string to be used as a command line argument in
- the native build system shell. */
- std::string EscapeForShell(const char* str);
+ the native build system shell. Optionally allow the build
+ system to replace make variable references. */
+ std::string EscapeForShell(const char* str, bool makeVars = false);
+
+ /** Backwards-compatibility version of EscapeForShell. */
+ std::string EscapeForShellOldStyle(const char* str);
protected:
@@ -267,6 +271,7 @@ protected:
std::map<cmStdString, cmStdString> LanguageToIncludeFlags;
std::map<cmStdString, cmStdString> UniqueObjectNamesMap;
bool WindowsShell;
+ bool WindowsVSIDE;
bool ForceUnixPath;
bool UseRelativePaths;
bool IgnoreLibPrefix;
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 0898daf..2eac5ab 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -899,6 +899,8 @@ cmLocalUnixMakefileGenerator3
{
dir = workingDir;
}
+ bool escapeOldStyle = cc.GetEscapeOldStyle();
+ bool escapeAllowMakeVars = cc.GetEscapeAllowMakeVars();
// Add each command line to the set of commands.
std::vector<std::string> commands1;
@@ -927,7 +929,15 @@ cmLocalUnixMakefileGenerator3
for(unsigned int j=1; j < commandLine.size(); ++j)
{
cmd += " ";
- cmd += this->EscapeForShell(commandLine[j].c_str());
+ if(escapeOldStyle)
+ {
+ cmd += this->EscapeForShellOldStyle(commandLine[j].c_str());
+ }
+ else
+ {
+ cmd += this->EscapeForShell(commandLine[j].c_str(),
+ escapeAllowMakeVars);
+ }
}
commands1.push_back(cmd);
}
diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx
index 7a07d45..4295ce8 100644
--- a/Source/cmLocalVisualStudio6Generator.cxx
+++ b/Source/cmLocalVisualStudio6Generator.cxx
@@ -461,6 +461,8 @@ void cmLocalVisualStudio6Generator
std::string script =
this->ConstructScript(command->GetCommandLines(),
command->GetWorkingDirectory(),
+ command->GetEscapeOldStyle(),
+ command->GetEscapeAllowMakeVars(),
"\\\n\t");
std::string comment =
this->ConstructComment(*command,
@@ -775,6 +777,8 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars(),
prelink_newline);
}
for (std::vector<cmCustomCommand>::const_iterator cr =
@@ -787,6 +791,8 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars(),
prelink_newline);
}
if(prelink_total > 0)
@@ -814,6 +820,8 @@ cmLocalVisualStudio6Generator::CreateTargetRules(cmTarget &target,
}
customRuleCode += this->ConstructScript(cr->GetCommandLines(),
cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars(),
postbuild_newline);
}
if(postbuild_total > 0)
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 08d5158..2cdca06 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -1184,7 +1184,9 @@ void cmLocalVisualStudio7Generator
// Construct the entire set of commands in one string.
std::string script =
this->ConstructScript(command->GetCommandLines(),
- command->GetWorkingDirectory());
+ command->GetWorkingDirectory(),
+ command->GetEscapeOldStyle(),
+ command->GetEscapeAllowMakeVars());
std::string comment = this->ConstructComment(*command);
const char* flags = compileFlags.size() ? compileFlags.c_str(): 0;
this->WriteCustomRule(fout, source.c_str(), script.c_str(),
@@ -1391,8 +1393,11 @@ void cmLocalVisualStudio7Generator
fout << "\nCommandLine=\"";
init = true;
}
- std::string script =
- this->ConstructScript(cr->GetCommandLines(), cr->GetWorkingDirectory());
+ std::string script =
+ this->ConstructScript(cr->GetCommandLines(),
+ cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();
}
if (init)
@@ -1413,8 +1418,11 @@ void cmLocalVisualStudio7Generator
fout << "\nCommandLine=\"";
init = true;
}
- std::string script = this->ConstructScript(cr->GetCommandLines(),
- cr->GetWorkingDirectory());
+ std::string script =
+ this->ConstructScript(cr->GetCommandLines(),
+ cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();
}
if (init)
@@ -1435,8 +1443,11 @@ void cmLocalVisualStudio7Generator
fout << "\nCommandLine=\"";
init = true;
}
- std::string script =
- this->ConstructScript(cr->GetCommandLines(), cr->GetWorkingDirectory());
+ std::string script =
+ this->ConstructScript(cr->GetCommandLines(),
+ cr->GetWorkingDirectory(),
+ cr->GetEscapeOldStyle(),
+ cr->GetEscapeAllowMakeVars());
fout << this->EscapeForXML(script.c_str()).c_str();
}
if (init)
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index f874987..c342e28 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -24,6 +24,7 @@
cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator()
{
this->WindowsShell = true;
+ this->WindowsVSIDE = true;
}
//----------------------------------------------------------------------------
@@ -110,6 +111,8 @@ std::string
cmLocalVisualStudioGenerator
::ConstructScript(const cmCustomCommandLines& commandLines,
const char* workingDirectory,
+ bool escapeOldStyle,
+ bool escapeAllowMakeVars,
const char* newline)
{
// Store the script in a string.
@@ -146,7 +149,15 @@ cmLocalVisualStudioGenerator
for(unsigned int j=1;j < commandLine.size(); ++j)
{
script += " ";
- script += this->EscapeForShell(commandLine[j].c_str());
+ if(escapeOldStyle)
+ {
+ script += this->EscapeForShellOldStyle(commandLine[j].c_str());
+ }
+ else
+ {
+ script += this->EscapeForShell(commandLine[j].c_str(),
+ escapeAllowMakeVars);
+ }
}
// End the line.
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
index 38ca491..ca9cb6c 100644
--- a/Source/cmLocalVisualStudioGenerator.h
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -39,6 +39,8 @@ protected:
/** Construct a script from the given list of command lines. */
std::string ConstructScript(const cmCustomCommandLines& commandLines,
const char* workingDirectory,
+ bool escapeOldStyle,
+ bool escapeAllowMakeVars,
const char* newline = "\n");
// Safe object file name generation.
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 1fe6cb0..4f50d36 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -2089,7 +2089,7 @@ int kwsysProcessComputeCommandLength(kwsysProcess* cp,
{
/* Add the length of this argument. It already includes room
for a separating space or terminating null. */
- length += kwsysSystem_Windows_ShellArgumentSize(*arg);
+ length += kwsysSystem_Shell_GetArgumentSizeForWindows(*arg, 0);
}
}
@@ -2119,7 +2119,7 @@ void kwsysProcessComputeCommandLine(kwsysProcess* cp,
}
/* Add the current argument. */
- cmd = kwsysSystem_Windows_ShellArgument(*arg, cmd);
+ cmd = kwsysSystem_Shell_GetArgumentForWindows(*arg, cmd, 0);
}
/* Add the terminating null character to the command line. */
diff --git a/Source/kwsys/System.c b/Source/kwsys/System.c
index 3b8e5a5..414e69c 100644
--- a/Source/kwsys/System.c
+++ b/Source/kwsys/System.c
@@ -21,19 +21,164 @@
#endif
#include <string.h> /* strlen */
+#include <ctype.h> /* isalpha */
+
+#include <stdio.h>
+
+/*
+
+Notes:
+
+Make variable replacements open a can of worms. Sometimes they should
+be quoted and sometimes not. Sometimes their replacement values are
+already quoted.
+
+VS variables cause problems. In order to pass the referenced value
+with spaces the reference must be quoted. If the variable value ends
+in a backslash then it will escape the ending quote! In order to make
+the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+Make variable references are platform specific so we should probably
+just NOT quote them and let the listfile author deal with it.
+
+*/
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem_Shell__CharIsWhitespace(char c)
+{
+ return ((c == ' ') || (c == '\t'));
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem_Shell__CharNeedsQuotesOnUnix(char c)
+{
+ return ((c == '\'') || (c == '`') || (c == ';') ||
+ (c == '&') || (c == '$') || (c == '(') || (c == ')'));
+}
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem_Shell__CharNeedsQuotes(char c, int isUnix, int flags)
+{
+ /* On all platforms quotes are needed to preserve whitespace. */
+ if(kwsysSystem_Shell__CharIsWhitespace(c))
+ {
+ return 1;
+ }
+
+ if(isUnix)
+ {
+ /* On UNIX several special characters need quotes to preserve them. */
+ if(kwsysSystem_Shell__CharNeedsQuotesOnUnix(c))
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ /* On Windows single-quotes must be escaped in some make
+ environments, such as in mingw32-make. */
+ if(flags & kwsysSystem_Shell_Flag_Make)
+ {
+ if(c == '\'')
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
/*--------------------------------------------------------------------------*/
-static int kwsysSystemWindowsShellArgumentNeedsEscape(const char* in)
+static int kwsysSystem_Shell__CharIsMakeVariableName(char c)
{
- /* Scan the string for characters that need escaping. Note that
- single quotes seem to need escaping for some windows shell
- environments (mingw32-make shell for example). Single quotes do
- not actually need backslash escapes but must be in a
- double-quoted argument. */
+ return c && (c == '_' || isalpha(((int)c)));
+}
+
+/*--------------------------------------------------------------------------*/
+static const char* kwsysSystem_Shell__SkipMakeVariables(const char* c)
+{
+ while(*c == '$' && *(c+1) == '(')
+ {
+ const char* skip = c+2;
+ while(kwsysSystem_Shell__CharIsMakeVariableName(*skip))
+ {
+ ++skip;
+ }
+ if(*skip == ')')
+ {
+ c = skip+1;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return c;
+}
+
+/*
+Allowing make variable replacements opens a can of worms. Sometimes
+they should be quoted and sometimes not. Sometimes their replacement
+values are already quoted or contain escapes.
+
+Some Visual Studio variables cause problems. In order to pass the
+referenced value with spaces the reference must be quoted. If the
+variable value ends in a backslash then it will escape the ending
+quote! In order to make the ending backslash appear we need this:
+
+ "$(InputDir)\"
+
+However if there is not a trailing backslash then this will put a
+quote in the value so we need:
+
+ "$(InputDir)"
+
+This macro decides whether we quote an argument just because it
+contains a make variable reference. This should be replaced with a
+flag later when we understand applications of this better.
+*/
+#define KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES 0
+
+/*--------------------------------------------------------------------------*/
+static int kwsysSystem_Shell__ArgumentNeedsQuotes(const char* in, int isUnix,
+ int flags)
+{
+ /* Scan the string for characters that require quoting. */
const char* c;
for(c=in; *c; ++c)
{
- if(*c == ' ' || *c == '\t' || *c == '"' || *c == '\'')
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables)
+ {
+#if KWSYS_SYSTEM_SHELL_QUOTE_MAKE_VARIABLES
+ const char* skip = kwsysSystem_Shell__SkipMakeVariables(c);
+ if(skip != c)
+ {
+ /* We need to quote make variable references to preserve the
+ string with contents substituted in its place. */
+ return 1;
+ }
+#else
+ /* Skip over the make variable references if any are present. */
+ c = kwsysSystem_Shell__SkipMakeVariables(c);
+
+ /* Stop if we have reached the end of the string. */
+ if(!*c)
+ {
+ break;
+ }
+#endif
+ }
+
+ /* Check whether this character needs quotes. */
+ if(kwsysSystem_Shell__CharNeedsQuotes(*c, isUnix, flags))
{
return 1;
}
@@ -42,130 +187,260 @@ static int kwsysSystemWindowsShellArgumentNeedsEscape(const char* in)
}
/*--------------------------------------------------------------------------*/
-int kwsysSystem_Windows_ShellArgumentSize(const char* in)
+static int kwsysSystem_Shell__GetArgumentSize(const char* in,
+ int isUnix, int flags)
{
/* Start with the length of the original argument, plus one for
either a terminating null or a separating space. */
- int length = (int)strlen(in) + 1;
+ int size = (int)strlen(in) + 1;
/* String iterator. */
const char* c;
/* Keep track of how many backslashes have been encountered in a row. */
- int backslashes = 0;
-
- /* If nothing needs escaping, we do not need any extra length. */
- if(!kwsysSystemWindowsShellArgumentNeedsEscape(in))
- {
- return length;
- }
-
- /* Add 2 for double quotes since spaces are present. */
- length += 2;
+ int windows_backslashes = 0;
- /* Scan the string to find characters that need escaping. */
+ /* Scan the string for characters that require escaping or quoting. */
for(c=in; *c; ++c)
{
- if(*c == '\\')
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables)
{
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
+ /* Skip over the make variable references if any are present. */
+ c = kwsysSystem_Shell__SkipMakeVariables(c);
+
+ /* Stop if we have reached the end of the string. */
+ if(!*c)
+ {
+ break;
+ }
}
- else if(*c == '"')
+
+ /* Check whether this character needs escaping. */
+ if(isUnix)
{
- /* Found a double-quote. We need to escape it and all
- immediately preceding backslashes. */
- length += backslashes + 1;
- backslashes = 0;
+ /* On Unix a few special characters need escaping even inside a
+ quoted argument. */
+ if(*c == '\\' || *c == '"' || *c == '`' || *c == '$')
+ {
+ /* This character needs a backslash to escape it. */
+ ++size;
+ }
}
else
{
- /* Found another character. This eliminates the possibility
- that any immediately preceding backslashes will be
- escaped. */
- backslashes = 0;
+ /* 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. */
+ 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;
+ }
+ }
+
+ /* The dollar sign needs special handling in some environments. */
+ if(*c == '$')
+ {
+ if(flags & kwsysSystem_Shell_Flag_Make)
+ {
+ /* In Makefiles a dollar is written $$ so we need one extra
+ character. */
+ ++size;
+ }
+ else if(flags & kwsysSystem_Shell_Flag_VSIDE)
+ {
+ /* In a VS IDE a dollar is written "$" so we need two extra
+ characters. */
+ size += 2;
+ }
}
}
- /* We need to escape all ending backslashes. */
- length += backslashes;
+ /* Check whether the argument needs surrounding quotes. */
+ if(kwsysSystem_Shell__ArgumentNeedsQuotes(in, isUnix, flags))
+ {
+ /* Surrounding quotes are needed. Allocate space for them. */
+ size += 2;
- return length;
+ /* We must escape all ending backslashes when quoting on windows. */
+ size += windows_backslashes;
+ }
+
+ return size;
}
/*--------------------------------------------------------------------------*/
-char* kwsysSystem_Windows_ShellArgument(const char* in, char* out)
+static char* kwsysSystem_Shell__GetArgument(const char* in, char* out,
+ int isUnix, int flags)
{
/* String iterator. */
const char* c;
/* Keep track of how many backslashes have been encountered in a row. */
- int backslashes = 0;
+ int windows_backslashes = 0;
- /* If nothing needs escaping, we can pass the argument verbatim. */
- if(!kwsysSystemWindowsShellArgumentNeedsEscape(in))
+ /* Whether the argument must be quoted. */
+ int needQuotes = kwsysSystem_Shell__ArgumentNeedsQuotes(in, isUnix, flags);
+ if(needQuotes)
{
- /* Just copy the string. */
- for(c=in; *c; ++c)
- {
- *out++ = *c;
- }
-
- /* Store a terminating null without incrementing. */
- *out = 0;
- return out;
+ /* Add the opening quote for this argument. */
+ *out++ = '"';
}
- /* Add the opening double-quote for this argument. */
- *out++ = '"';
-
- /* Add the characters of the argument, possibly escaping them. */
+ /* Scan the string for characters that require escaping or quoting. */
for(c=in; *c; ++c)
{
- if(*c == '\\')
+ /* Look for $(MAKEVAR) syntax if requested. */
+ if(flags & kwsysSystem_Shell_Flag_AllowMakeVariables)
{
- /* Found a backslash. It may need to be escaped later. */
- ++backslashes;
- *out++ = '\\';
+ const char* skip = kwsysSystem_Shell__SkipMakeVariables(c);
+ if(skip != c)
+ {
+ /* Copy to the end of the make variable references. */
+ while(c != skip)
+ {
+ *out++ = *c++;
+ }
+
+ /* Stop if we have reached the end of the string. */
+ if(!*c)
+ {
+ break;
+ }
+ }
}
- else if(*c == '"')
+
+ /* Check whether this character needs escaping. */
+ if(isUnix)
{
- /* Add enough backslashes to escape any that preceded the
- double-quote. */
- while(backslashes > 0)
+ /* On Unix a few special characters need escaping even inside a
+ quoted argument. */
+ if(*c == '\\' || *c == '"' || *c == '`' || *c == '$')
{
- --backslashes;
+ /* This character needs a backslash to escape it. */
*out++ = '\\';
}
+ }
+ else
+ {
+ /* 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++ = '\\';
+ /* 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;
+ }
+ }
- /* Add the double-quote itself. */
- *out++ = '"';
+ /* The dollar sign needs special handling in some environments. */
+ if(*c == '$')
+ {
+ if(flags & kwsysSystem_Shell_Flag_Make)
+ {
+ /* In Makefiles a dollar is written $$. The make tool will
+ replace it with just $ before passing it to the shell. */
+ *out++ = '$';
+ *out++ = '$';
+ }
+ else if(flags & kwsysSystem_Shell_Flag_VSIDE)
+ {
+ /* In a VS IDE a dollar is written "$". If this is written in
+ an un-quoted argument it starts a quoted segment, inserts
+ the $ and ends the segment. If it is written in a quoted
+ argument it ends quoting, inserts the $ and restarts
+ quoting. Either way the $ is isolated from surrounding
+ text to avoid looking like a variable reference. */
+ *out++ = '"';
+ *out++ = '$';
+ *out++ = '"';
+ }
+ else
+ {
+ /* Otherwise a dollar is written just $. */
+ *out++ = '$';
+ }
}
else
{
- /* We encountered a normal character. This eliminates any
- escaping needed for preceding backslashes. Add the
- character. */
- backslashes = 0;
+ /* Store this character. */
*out++ = *c;
}
}
- /* Add enough backslashes to escape any trailing ones. */
- while(backslashes > 0)
+ if(needQuotes)
{
- --backslashes;
- *out++ = '\\';
- }
+ /* Add enough backslashes to escape any trailing ones. */
+ while(windows_backslashes > 0)
+ {
+ --windows_backslashes;
+ *out++ = '\\';
+ }
- /* Add the closing double-quote for this argument. */
- *out++ = '"';
+ /* Add the closing quote for this argument. */
+ *out++ = '"';
+ }
/* Store a terminating null without incrementing. */
*out = 0;
return out;
}
+
+/*--------------------------------------------------------------------------*/
+char* kwsysSystem_Shell_GetArgumentForWindows(const char* in,
+ char* out,
+ int flags)
+{
+ return kwsysSystem_Shell__GetArgument(in, out, 0, flags);
+}
+
+/*--------------------------------------------------------------------------*/
+char* kwsysSystem_Shell_GetArgumentForUnix(const char* in,
+ char* out,
+ int flags)
+{
+ return kwsysSystem_Shell__GetArgument(in, out, 1, flags);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysSystem_Shell_GetArgumentSizeForWindows(const char* in, int flags)
+{
+ return kwsysSystem_Shell__GetArgumentSize(in, 0, flags);
+}
+
+/*--------------------------------------------------------------------------*/
+int kwsysSystem_Shell_GetArgumentSizeForUnix(const char* in, int flags)
+{
+ return kwsysSystem_Shell__GetArgumentSize(in, 1, flags);
+}
diff --git a/Source/kwsys/System.h.in b/Source/kwsys/System.h.in
index db4859e..b125473 100644
--- a/Source/kwsys/System.h.in
+++ b/Source/kwsys/System.h.in
@@ -24,8 +24,14 @@
# define kwsys_ns(x) @KWSYS_NAMESPACE@##x
# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
#endif
-#define kwsysSystem_Windows_ShellArgument kwsys_ns(System_Windows_ShellArgument)
-#define kwsysSystem_Windows_ShellArgumentSize kwsys_ns(System_Windows_ShellArgumentSize)
+#define kwsysSystem_Shell_GetArgumentForWindows kwsys_ns(System_Shell_GetArgumentForWindows)
+#define kwsysSystem_Shell_GetArgumentForUnix kwsys_ns(System_Shell_GetArgumentForUnix)
+#define kwsysSystem_Shell_GetArgumentSizeForWindows kwsys_ns(System_Shell_GetArgumentSizeForWindows)
+#define kwsysSystem_Shell_GetArgumentSizeForUnix kwsys_ns(System_Shell_GetArgumentSizeForUnix)
+#define kwsysSystem_Shell_Flag_e kwsys_ns(System_Shell_Flag_e)
+#define kwsysSystem_Shell_Flag_Make kwsys_ns(System_Shell_Flag_Make)
+#define kwsysSystem_Shell_Flag_VSIDE kwsys_ns(System_Shell_Flag_VSIDE)
+#define kwsysSystem_Shell_Flag_AllowMakeVariables kwsys_ns(System_Shell_Flag_AllowMakeVariables)
#if defined(__cplusplus)
extern "C"
@@ -33,18 +39,52 @@ extern "C"
#endif
/**
- * Escape the given command line argument for use in a windows shell.
- * Returns a pointer to the end of the command line argument in the
- * given buffer.
+ * Transform the given command line argument for use in a Windows or
+ * Unix shell. Returns a pointer to the end of the command line
+ * argument in the provided output buffer. Flags may be passed to
+ * modify the generated quoting and escape sequences to work under
+ * alternative environments.
*/
-kwsysEXPORT char* kwsysSystem_Windows_ShellArgument(const char* in, char* out);
+kwsysEXPORT char* kwsysSystem_Shell_GetArgumentForWindows(const char* in,
+ char* out,
+ int flags);
+kwsysEXPORT char* kwsysSystem_Shell_GetArgumentForUnix(const char* in,
+ char* out,
+ int flags);
/**
- * Compute the size of the buffer needed to store the result of
- * kwsysSystem_Windows_ShellArgument. The return value includes space
- * for a null-terminator.
+ * Compute the size of the buffer required to store the output from
+ * kwsysSystem_Shell_GetArgumentForWindows or
+ * kwsysSystem_Shell_GetArgumentForUnix. The flags passed must be
+ * identical between the two calls.
*/
-kwsysEXPORT int kwsysSystem_Windows_ShellArgumentSize(const char* in);
+kwsysEXPORT int kwsysSystem_Shell_GetArgumentSizeForWindows(const char* in,
+ int flags);
+kwsysEXPORT int kwsysSystem_Shell_GetArgumentSizeForUnix(const char* in,
+ int flags);
+
+/**
+ * Flags to pass to kwsysSystem_Shell_GetArgumentForWindows or
+ * kwsysSystem_Shell_GetArgumentForUnix. These modify the generated
+ * quoting and escape sequences to work under alternative
+ * environments.
+ */
+enum kwsysSystem_Shell_Flag_e
+{
+ /** The target shell is in a makefile. */
+ kwsysSystem_Shell_Flag_Make = (1<<0),
+
+ /** The target shell is in a VS project file. Do not use with
+ Shell_Flag_Make. */
+ kwsysSystem_Shell_Flag_VSIDE = (1<<1),
+
+ /** Make variable reference syntax $(MAKEVAR) should not be escaped
+ to allow a build tool to replace it. Replacement values
+ containing spaces, quotes, backslashes, or other
+ non-alphanumeric characters that have significance to some makes
+ or shells produce undefined behavior. */
+ kwsysSystem_Shell_Flag_AllowMakeVariables = (1<<2)
+};
#if defined(__cplusplus)
} /* extern "C" */
@@ -55,8 +95,14 @@ kwsysEXPORT int kwsysSystem_Windows_ShellArgumentSize(const char* in);
#if !defined(KWSYS_NAMESPACE)
# undef kwsys_ns
# undef kwsysEXPORT
-# undef kwsysSystem_Windows_ShellArgument
-# undef kwsysSystem_Windows_ShellArgumentSize
+# undef kwsysSystem_Shell_GetArgumentForWindows
+# undef kwsysSystem_Shell_GetArgumentForUnix
+# undef kwsysSystem_Shell_GetArgumentSizeForWindows
+# undef kwsysSystem_Shell_GetArgumentSizeForUnix
+# undef kwsysSystem_Shell_Flag_e
+# undef kwsysSystem_Shell_Flag_Make
+# undef kwsysSystem_Shell_Flag_VSIDE
+# undef kwsysSystem_Shell_Flag_AllowMakeVariables
#endif
#endif