diff options
author | Brad King <brad.king@kitware.com> | 2020-09-23 16:05:16 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2020-09-23 16:05:26 (GMT) |
commit | d827fdb6f99e58e4dfc6fdda3816ed2862e00a95 (patch) | |
tree | 4597f12193130eaa0311c2220a2d623ee71c36b0 /Source | |
parent | a41f375e65ad764f7512ebf9edd1370adaec24f7 (diff) | |
parent | d832c1cc7d717623b2eb07a940c85ca427a8084e (diff) | |
download | CMake-d827fdb6f99e58e4dfc6fdda3816ed2862e00a95.zip CMake-d827fdb6f99e58e4dfc6fdda3816ed2862e00a95.tar.gz CMake-d827fdb6f99e58e4dfc6fdda3816ed2862e00a95.tar.bz2 |
Merge topic 'separate_arguments-program'
d832c1cc7d separate_arguments: add option PROGRAM
f4c21d4953 separate_arguments: refactoring
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5253
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmSeparateArgumentsCommand.cxx | 190 |
1 files changed, 123 insertions, 67 deletions
diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx index e45f3b0..7e501a2 100644 --- a/Source/cmSeparateArgumentsCommand.cxx +++ b/Source/cmSeparateArgumentsCommand.cxx @@ -4,9 +4,13 @@ #include <algorithm> +#include <cmext/string_view> + +#include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmProperty.h" +#include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -19,86 +23,138 @@ bool cmSeparateArgumentsCommand(std::vector<std::string> const& args, return false; } - std::string var; - std::string command; - enum Mode - { - ModeOld, - ModeUnix, - ModeWindows - }; - Mode mode = ModeOld; - enum Doing - { - DoingNone, - DoingVariable, - DoingMode, - DoingCommand - }; - Doing doing = DoingVariable; - for (std::string const& arg : args) { - if (doing == DoingVariable) { - var = arg; - doing = DoingMode; - // This will always clone one of the other blocks. - // NOLINTNEXTLINE(bugprone-branch-clone) - } else if (doing == DoingMode && arg == "NATIVE_COMMAND") { -#ifdef _WIN32 - mode = ModeWindows; -#else - mode = ModeUnix; -#endif - doing = DoingCommand; - } else if (doing == DoingMode && arg == "UNIX_COMMAND") { - mode = ModeUnix; - doing = DoingCommand; - } else if (doing == DoingMode && arg == "WINDOWS_COMMAND") { - mode = ModeWindows; - doing = DoingCommand; - } else if (doing == DoingCommand) { - command = arg; - doing = DoingNone; - } else { - status.SetError(cmStrCat("given unknown argument ", arg)); - return false; - } - } + std::string const& var = args.front(); - if (mode == ModeOld) { + if (args.size() == 1) { // Original space-replacement version of command. if (cmProp def = status.GetMakefile().GetDefinition(var)) { std::string value = *def; std::replace(value.begin(), value.end(), ' ', ';'); status.GetMakefile().AddDefinition(var, value); } - } 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); + + return true; + } + + struct Arguments + { + bool UnixCommand = false; + bool WindowsCommand = false; + bool NativeCommand = false; + bool Program = false; + bool SeparateArgs = false; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("UNIX_COMMAND"_s, &Arguments::UnixCommand) + .Bind("WINDOWS_COMMAND"_s, &Arguments::WindowsCommand) + .Bind("NATIVE_COMMAND"_s, &Arguments::NativeCommand) + .Bind("PROGRAM"_s, &Arguments::Program) + .Bind("SEPARATE_ARGS"_s, &Arguments::SeparateArgs); + + std::vector<std::string> unparsedArguments; + Arguments arguments = + parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments); + + if (!arguments.UnixCommand && !arguments.WindowsCommand && + !arguments.NativeCommand) { + status.SetError("missing required option: 'UNIX_COMMAND' or " + "'WINDOWS_COMMAND' or 'NATIVE_COMMAND'"); + return false; + } + if ((arguments.UnixCommand && arguments.WindowsCommand) || + (arguments.UnixCommand && arguments.NativeCommand) || + (arguments.WindowsCommand && arguments.NativeCommand)) { + status.SetError("'UNIX_COMMAND', 'WINDOWS_COMMAND' and 'NATIVE_COMMAND' " + "are mutually exclusive"); + return false; + } + if (arguments.SeparateArgs && !arguments.Program) { + status.SetError("`SEPARATE_ARGS` option requires `PROGRAM' option"); + return false; + } + + if (unparsedArguments.size() > 1) { + status.SetError("given unexpected argument(s)"); + return false; + } + + std::string& command = unparsedArguments.front(); + + if (command.empty()) { + status.GetMakefile().AddDefinition(var, command); + return true; + } + + if (arguments.Program && !arguments.SeparateArgs) { + std::string program; + std::string 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 (!cmTrimWhitespace(command).empty()) { + program = cmSystemTools::FindProgram(command); } - // Construct the result list value. - std::string value; - const char* sep = ""; - for (std::string const& vi : vec) { - // Separate from the previous argument. - value += sep; - sep = ";"; - - // Preserve semicolons. - for (char si : vi) { - if (si == ';') { - value += '\\'; + // If that failed then assume a command-line string was given + // and split the program part from the rest of the arguments. + if (program.empty()) { + if (cmSystemTools::SplitProgramFromArgs(command, program, programArgs)) { + if (!cmSystemTools::FileExists(program)) { + program = cmSystemTools::FindProgram(program); } - value += si; } } - status.GetMakefile().AddDefinition(var, value); + + if (!program.empty()) { + program += cmStrCat(';', programArgs); + } + + status.GetMakefile().AddDefinition(var, program); + return true; + } + + // split command given + std::vector<std::string> values; + + if (arguments.NativeCommand) { +#if defined(_WIN32) + arguments.WindowsCommand = true; +#else + arguments.UnixCommand = true; +#endif + } + + if (arguments.UnixCommand) { + cmSystemTools::ParseUnixCommandLine(command.c_str(), values); + } else { + cmSystemTools::ParseWindowsCommandLine(command.c_str(), values); + } + + if (arguments.Program) { + // check program exist + if (!cmSystemTools::FileExists(values.front())) { + auto result = cmSystemTools::FindProgram(values.front()); + if (result.empty()) { + values.clear(); + } else { + values.front() = result; + } + } } + // preserve semicolons in arguments + std::for_each(values.begin(), values.end(), [](std::string& value) { + std::string::size_type pos = 0; + while ((pos = value.find_first_of(';', pos)) != std::string::npos) { + value.insert(pos, 1, '\\'); + pos += 2; + } + }); + auto value = cmJoin(values, ";"); + status.GetMakefile().AddDefinition(var, value); + return true; } |