summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/cmGetFilenameComponentCommand.cxx25
-rw-r--r--Source/cmSystemTools.cxx50
-rw-r--r--Source/cmSystemTools.h5
3 files changed, 79 insertions, 1 deletions
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
index c23684c..1b358ab 100644
--- a/Source/cmGetFilenameComponentCommand.cxx
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -60,7 +60,30 @@ bool cmGetFilenameComponentCommand::InitialPass(
}
}
}
- cmSystemTools::SplitProgramFromArgs(filename, result, programArgs);
+
+ // First assume the path to the program was specified with no
+ // arguments and with no quoting or escaping for spaces.
+ // Only bother doing this if there is non-whitespace.
+ if (!cmSystemTools::TrimWhitespace(filename).empty()) {
+ result = cmSystemTools::FindProgram(filename);
+ }
+
+ // If that failed then assume a command-line string was given
+ // and split the program part from the rest of the arguments.
+ if (result.empty()) {
+ std::string program;
+ if (cmSystemTools::SplitProgramFromArgs(filename, program,
+ programArgs)) {
+ if (cmSystemTools::FileExists(program)) {
+ result = program;
+ } else {
+ result = cmSystemTools::FindProgram(program);
+ }
+ }
+ if (result.empty()) {
+ programArgs.clear();
+ }
+ }
} else if (args[2] == "EXT") {
result = cmSystemTools::GetFilenameExtension(filename);
} else if (args[2] == "NAME_WE") {
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 5c63d98..2635d6d 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -603,6 +603,56 @@ std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
return args;
}
+bool cmSystemTools::SplitProgramFromArgs(std::string const& command,
+ std::string& program,
+ std::string& args)
+{
+ const char* c = command.c_str();
+
+ // Skip leading whitespace.
+ while (isspace(static_cast<unsigned char>(*c))) {
+ ++c;
+ }
+
+ // Parse one command-line element up to an unquoted space.
+ bool in_escape = false;
+ bool in_double = false;
+ bool in_single = false;
+ for (; *c; ++c) {
+ if (in_single) {
+ if (*c == '\'') {
+ in_single = false;
+ } else {
+ program += *c;
+ }
+ } else if (in_escape) {
+ in_escape = false;
+ program += *c;
+ } else if (*c == '\\') {
+ in_escape = true;
+ } else if (in_double) {
+ if (*c == '"') {
+ in_double = false;
+ } else {
+ program += *c;
+ }
+ } else if (*c == '"') {
+ in_double = true;
+ } else if (*c == '\'') {
+ in_single = true;
+ } else if (isspace(static_cast<unsigned char>(*c))) {
+ break;
+ } else {
+ program += *c;
+ }
+ }
+
+ // The remainder of the command line holds unparsed arguments.
+ args = c;
+
+ return !in_single && !in_escape && !in_double;
+}
+
size_t cmSystemTools::CalculateCommandLineLengthLimit()
{
size_t sz =
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 9bec361..e7082e6 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -255,6 +255,11 @@ public:
static void ParseUnixCommandLine(const char* command,
std::vector<std::string>& args);
+ /** Split a command-line string into the parsed command and the unparsed
+ arguments. Returns false on unfinished quoting or escaping. */
+ static bool SplitProgramFromArgs(std::string const& command,
+ std::string& program, std::string& args);
+
/**
* Handle response file in an argument list and return a new argument list
* **/