1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmSeparateArgumentsCommand.h"
#include <algorithm>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmArgumentParser.h"
#include "cmExecutionStatus.h"
#include "cmList.h"
#include "cmMakefile.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmValue.h"
// cmSeparateArgumentsCommand
bool cmSeparateArgumentsCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
if (args.empty()) {
status.SetError("must be given at least one argument.");
return false;
}
std::string const& var = args.front();
if (args.size() == 1) {
// Original space-replacement version of command.
if (cmValue def = status.GetMakefile().GetDefinition(var)) {
std::string value = *def;
std::replace(value.begin(), value.end(), ' ', ';');
status.GetMakefile().AddDefinition(var, value);
}
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;
}
if (unparsedArguments.empty()) {
status.GetMakefile().AddDefinition(var, cm::string_view{});
return true;
}
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);
}
// 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);
}
}
}
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 = cmList::to_string(values);
status.GetMakefile().AddDefinition(var, value);
return true;
}
|