From: David Bozier Date: Thu, 2 Mar 2017 16:50:48 +0000 (+0000) Subject: Allow use of spaces in Bugpoint ‘--compile-command’ argument X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=05f3b7323d4b360869204bd0643ed97fae750ac0;p=llvm Allow use of spaces in Bugpoint ‘--compile-command’ argument Bug-Point functionality needs extending due to the patch D29185 by bd1976llvm (Allow llvm's build and test systems to support paths with spaces ). It requires Bugpoint to accept the use of spaces within ‘--compile-command’ tokens. Details Bugpoint uses the argument ‘--compile-command’ to pass in a command line argument as a string, the string is tokenized by the ‘lexCommand’ function using spaces as a delimiter. Patch D29185 will cause the unit test compile-custom.ll to fail as spaces are now required within tokens and as a delimiter. This patch allows the use of escape characters as below: Two consecutive '\' evaluate to a single '\'. A space after a '\' evaluates to a space that is not interpreted as a delimiter. Any other instances of the '\' character are removed. Committed on behalf of Owen Reynolds Differential revision: https://reviews.llvm.org/D29940 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296763 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 4633d643733..10532ef8395 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -355,37 +355,62 @@ Expected CustomExecutor::ExecuteProgram( // Tokenize the CommandLine to the command and the args to allow // defining a full command line as the command instead of just the // executed program. We cannot just pass the whole string after the command -// as a single argument because then program sees only a single +// as a single argument because then the program sees only a single // command line argument (with spaces in it: "foo bar" instead // of "foo" and "bar"). // -// code borrowed from: -// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html +// Spaces are used as a delimiter; however repeated, leading, and trailing +// whitespace are ignored. Simple escaping is allowed via the '\' +// character, as seen below: +// +// Two consecutive '\' evaluate to a single '\'. +// A space after a '\' evaluates to a space that is not interpreted as a +// delimiter. +// Any other instances of the '\' character are removed. +// +// Example: +// '\\' -> '\' +// '\ ' -> ' ' +// 'exa\mple' -> 'example' +// static void lexCommand(std::string &Message, const std::string &CommandLine, std::string &CmdPath, std::vector &Args) { - std::string Command = ""; - std::string delimiters = " "; - - std::string::size_type lastPos = CommandLine.find_first_not_of(delimiters, 0); - std::string::size_type pos = CommandLine.find_first_of(delimiters, lastPos); - - while (std::string::npos != pos || std::string::npos != lastPos) { - std::string token = CommandLine.substr(lastPos, pos - lastPos); - if (Command == "") - Command = token; - else - Args.push_back(token); - // Skip delimiters. Note the "not_of" - lastPos = CommandLine.find_first_not_of(delimiters, pos); - // Find next "non-delimiter" - pos = CommandLine.find_first_of(delimiters, lastPos); + std::string Token; + std::string Command; + bool FoundPath = false; + + // first argument is the PATH. + // Skip repeated whitespace, leading whitespace and trailing whitespace. + for (std::size_t Pos = 0u; Pos <= CommandLine.size(); ++Pos) { + if ('\\' == CommandLine[Pos]) { + if (Pos + 1 < CommandLine.size()) + Token.push_back(CommandLine[++Pos]); + + continue; + } + if (' ' == CommandLine[Pos] || CommandLine.size() == Pos) { + if (Token.empty()) + continue; + + if (!FoundPath) { + Command = Token; + FoundPath = true; + Token.clear(); + continue; + } + + Args.push_back(Token); + Token.clear(); + continue; + } + Token.push_back(CommandLine[Pos]); } auto Path = sys::findProgramByName(Command); if (!Path) { - Message = std::string("Cannot find '") + Command + "' in PATH: " + - Path.getError().message() + "\n"; + Message = std::string("Cannot find '") + Command + + "' in PATH: " + Path.getError().message() + "\n"; return; } CmdPath = *Path;