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:
parent
7a907f87f8
commit
b23b1800a5
|
@ -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;
|
||||
}
|
||||
std::string value = cacheValue;
|
||||
cmSystemTools::ReplaceString(value," ", ";");
|
||||
this->Makefile->AddDefinition(args[0].c_str(), value.c_str());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -18,6 +18,7 @@ AddCMakeTest(GetFilenameComponentRealpath "")
|
|||
AddCMakeTest(Version "")
|
||||
AddCMakeTest(Message "")
|
||||
AddCMakeTest(File "")
|
||||
AddCMakeTest(SeparateArguments "")
|
||||
|
||||
SET(GetPrerequisites_PreArgs
|
||||
"-DCTEST_CONFIGURATION_TYPE:STRING=\\\${CTEST_CONFIGURATION_TYPE}"
|
||||
|
|
|
@ -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()
|
Loading…
Reference in New Issue