ENH: Teach separate_arguments() to parse commands

This adds UNIX_COMMAND and WINDOWS_COMMAND modes to the command.
These modes parse unix- and windows-style command lines.
This commit is contained in:
Brad King 2009-07-14 10:15:47 -04:00
parent 7a907f87f8
commit b23b1800a5
4 changed files with 128 additions and 10 deletions

View File

@ -20,19 +20,95 @@
bool cmSeparateArgumentsCommand
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
{
if(args.size() != 1 )
if(args.empty())
{
this->SetError("called with incorrect number of arguments");
this->SetError("must be given at least one argument.");
return false;
}
const char* cacheValue = this->Makefile->GetDefinition(args[0].c_str());
if(!cacheValue)
std::string var;
std::string command;
enum Mode { ModeOld, ModeUnix, ModeWindows };
Mode mode = ModeOld;
enum Doing { DoingNone, DoingVariable, DoingMode, DoingCommand };
Doing doing = DoingVariable;
for(unsigned int i=0; i < args.size(); ++i)
{
return true;
if(doing == DoingVariable)
{
var = args[i];
doing = DoingMode;
}
else if(doing == DoingMode && args[i] == "UNIX_COMMAND")
{
mode = ModeUnix;
doing = DoingCommand;
}
else if(doing == DoingMode && args[i] == "WINDOWS_COMMAND")
{
mode = ModeWindows;
doing = DoingCommand;
}
else if(doing == DoingCommand)
{
command = args[i];
doing = DoingNone;
}
else
{
cmOStringStream e;
e << "given unknown argument " << args[i];
this->SetError(e.str().c_str());
return false;
}
}
std::string value = cacheValue;
cmSystemTools::ReplaceString(value," ", ";");
this->Makefile->AddDefinition(args[0].c_str(), value.c_str());
if(mode == ModeOld)
{
// Original space-replacement version of command.
if(const char* def = this->Makefile->GetDefinition(var.c_str()))
{
std::string value = def;
cmSystemTools::ReplaceString(value, " ", ";");
this->Makefile->AddDefinition(var.c_str(), value.c_str());
}
}
else
{
// Parse the command line.
std::vector<std::string> vec;
if(mode == ModeUnix)
{
cmSystemTools::ParseUnixCommandLine(command.c_str(), vec);
}
else // if(mode == ModeWindows)
{
cmSystemTools::ParseWindowsCommandLine(command.c_str(), vec);
}
// Construct the result list value.
std::string value;
const char* sep = "";
for(std::vector<std::string>::const_iterator vi = vec.begin();
vi != vec.end(); ++vi)
{
// Separate from the previous argument.
value += sep;
sep = ";";
// Preserve semicolons.
for(std::string::const_iterator si = vi->begin();
si != vi->end(); ++si)
{
if(*si == ';')
{
value += '\\';
}
value += *si;
}
}
this->Makefile->AddDefinition(var.c_str(), value.c_str());
}
return true;
}

View File

@ -58,7 +58,7 @@ public:
virtual const char* GetTerseDocumentation()
{
return
"Split space separated arguments into a semi-colon separated list.";
"Parse space-separated arguments into a semicolon-separated list.";
}
/**
@ -67,6 +67,22 @@ public:
virtual const char* GetFullDocumentation()
{
return
" separate_arguments(<var> <UNIX|WINDOWS>_COMMAND \"<args>\")\n"
"Parses a unix- or windows-style command-line string \"<args>\" and "
"stores a semicolon-separated list of the arguments in <var>. "
"The entire command line must be given in one \"<args>\" argument."
"\n"
"The UNIX_COMMAND mode separates arguments by unquoted whitespace. "
"It recognizes both single-quote and double-quote pairs. "
"A backslash escapes the next literal character (\\\" is \"); "
"there are no special escapes (\\n is just n)."
"\n"
"The WINDOWS_COMMAND mode parses a windows command-line using the "
"same syntax the runtime library uses to construct argv at startup. "
"It separates arguments by whitespace that is not double-quoted. "
"Backslashes are literal unless they precede double-quotes. "
"See the MSDN article \"Parsing C Command-Line Arguments\" for details."
"\n"
" separate_arguments(VARIABLE)\n"
"Convert the value of VARIABLE to a semi-colon separated list. "
"All spaces are replaced with ';'. This helps with generating "

View File

@ -18,6 +18,7 @@ AddCMakeTest(GetFilenameComponentRealpath "")
AddCMakeTest(Version "")
AddCMakeTest(Message "")
AddCMakeTest(File "")
AddCMakeTest(SeparateArguments "")
SET(GetPrerequisites_PreArgs
"-DCTEST_CONFIGURATION_TYPE:STRING=\\\${CTEST_CONFIGURATION_TYPE}"

View File

@ -0,0 +1,25 @@
set(old_out "a b c")
separate_arguments(old_out)
set(old_exp "a;b;;c")
set(unix_cmd "a \"b c\" 'd e' \";\" \\ \\'\\\" '\\'' \"\\\"\"")
set(unix_exp "a;b c;d e;\;; '\";';\"")
separate_arguments(unix_out UNIX_COMMAND "${unix_cmd}")
set(windows_cmd "a \"b c\" 'd e' \";\" \\ \"c:\\windows\\path\\\\\" \\\"")
set(windows_exp "a;b c;'d;e';\;;\\;c:\\windows\\path\\;\"")
separate_arguments(windows_out WINDOWS_COMMAND "${windows_cmd}")
foreach(mode old unix windows)
if(NOT "${${mode}_out}" STREQUAL "${${mode}_exp}")
message(FATAL_ERROR "separate_arguments ${mode}-style failed. "
"Expected\n [${${mode}_exp}]\nbut got\n [${${mode}_out}]\n")
endif()
endforeach()
set(nothing)
separate_arguments(nothing)
if(DEFINED nothing)
message(FATAL_ERROR "separate_arguments null-case failed: "
"nothing=[${nothing}]")
endif()