cmake: Use shared parsing code for all cmake argv parsing
This commit is contained in:
parent
25a1cdef95
commit
0fb78576b0
133
Source/cmCommandLineArgument.h
Normal file
133
Source/cmCommandLineArgument.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
template <typename FunctionSignature>
|
||||
struct cmCommandLineArgument
|
||||
{
|
||||
enum class Values
|
||||
{
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
};
|
||||
|
||||
std::string InvalidSyntaxMessage;
|
||||
std::string InvalidValueMessage;
|
||||
std::string Name;
|
||||
Values Type;
|
||||
std::function<FunctionSignature> StoreCall;
|
||||
|
||||
template <typename FunctionType>
|
||||
cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
|
||||
, InvalidValueMessage(cmStrCat("Invalid value used with ", n))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
|
||||
FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
|
||||
, InvalidValueMessage(std::move(failedMsg))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
bool matches(std::string const& input) const
|
||||
{
|
||||
return (this->Type == Values::Zero) ? (input == this->Name)
|
||||
: cmHasPrefix(input, this->Name);
|
||||
}
|
||||
|
||||
template <typename T, typename... CallState>
|
||||
bool parse(std::string const& input, T& index,
|
||||
std::vector<std::string> const& allArgs,
|
||||
CallState&&... state) const
|
||||
{
|
||||
enum class ParseMode
|
||||
{
|
||||
Valid,
|
||||
Invalid,
|
||||
SyntaxError,
|
||||
ValueError
|
||||
};
|
||||
ParseMode parseState = ParseMode::Valid;
|
||||
|
||||
if (this->Type == Values::Zero) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
parseState =
|
||||
this->StoreCall(std::string{}, std::forward<CallState>(state)...)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
} else {
|
||||
parseState = ParseMode::SyntaxError;
|
||||
}
|
||||
|
||||
} else if (this->Type == Values::One) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
++index;
|
||||
if (index >= allArgs.size() || allArgs[index][0] == '-') {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
parseState =
|
||||
this->StoreCall(allArgs[index], std::forward<CallState>(state)...)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
} else {
|
||||
// parse the string to get the value
|
||||
auto possible_value = cm::string_view(input).substr(this->Name.size());
|
||||
if (possible_value.empty()) {
|
||||
parseState = ParseMode::SyntaxError;
|
||||
parseState = ParseMode::ValueError;
|
||||
} else if (possible_value[0] == '=') {
|
||||
possible_value.remove_prefix(1);
|
||||
if (possible_value.empty()) {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
parseState = this->StoreCall(std::string(possible_value),
|
||||
std::forward<CallState>(state)...)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
if (parseState == ParseMode::Valid) {
|
||||
parseState = this->StoreCall(std::string(possible_value),
|
||||
std::forward<CallState>(state)...)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
} else if (this->Type == Values::Two) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
|
||||
allArgs[index + 2][0] == '-') {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
index += 2;
|
||||
parseState =
|
||||
this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
|
||||
std::forward<CallState>(state)...)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parseState == ParseMode::SyntaxError) {
|
||||
cmSystemTools::Error(this->InvalidSyntaxMessage);
|
||||
} else if (parseState == ParseMode::ValueError) {
|
||||
cmSystemTools::Error(this->InvalidValueMessage);
|
||||
}
|
||||
return (parseState == ParseMode::Valid);
|
||||
}
|
||||
};
|
125
Source/cmake.cxx
125
Source/cmake.cxx
@ -29,6 +29,7 @@
|
||||
#include "cm_sys_stat.h"
|
||||
|
||||
#include "cmCMakePresetsFile.h"
|
||||
#include "cmCommandLineArgument.h"
|
||||
#include "cmCommands.h"
|
||||
#include "cmDocumentation.h"
|
||||
#include "cmDocumentationEntry.h"
|
||||
@ -132,131 +133,13 @@ namespace {
|
||||
using JsonValueMapType = std::unordered_map<std::string, Json::Value>;
|
||||
#endif
|
||||
|
||||
struct CommandArgument
|
||||
{
|
||||
enum struct Values
|
||||
{
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
};
|
||||
|
||||
std::string InvalidSyntaxMessage;
|
||||
std::string InvalidValueMessage;
|
||||
std::string Name;
|
||||
CommandArgument::Values Type;
|
||||
std::function<bool(std::string const& value, cmake* state)> StoreCall;
|
||||
|
||||
template <typename FunctionType>
|
||||
CommandArgument(std::string n, CommandArgument::Values t,
|
||||
FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
|
||||
, InvalidValueMessage(cmStrCat("Invalid value used with ", n))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename FunctionType>
|
||||
CommandArgument(std::string n, std::string failedMsg,
|
||||
CommandArgument::Values t, FunctionType&& func)
|
||||
: InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
|
||||
, InvalidValueMessage(std::move(failedMsg))
|
||||
, Name(std::move(n))
|
||||
, Type(t)
|
||||
, StoreCall(std::forward<FunctionType>(func))
|
||||
{
|
||||
}
|
||||
|
||||
bool matches(std::string const& input) const
|
||||
{
|
||||
return cmHasPrefix(input, this->Name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool parse(std::string const& input, T& index,
|
||||
std::vector<std::string> const& allArgs, cmake* state) const
|
||||
{
|
||||
enum struct ParseMode
|
||||
{
|
||||
Valid,
|
||||
Invalid,
|
||||
SyntaxError,
|
||||
ValueError
|
||||
};
|
||||
ParseMode parseState = ParseMode::Valid;
|
||||
|
||||
// argument is the next parameter
|
||||
if (this->Type == CommandArgument::Values::Zero) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
parseState = this->StoreCall(input, state) ? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
} else {
|
||||
parseState = ParseMode::SyntaxError;
|
||||
}
|
||||
|
||||
} else if (this->Type == CommandArgument::Values::One) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
++index;
|
||||
if (index >= allArgs.size() || allArgs[index][0] == '-') {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
parseState = this->StoreCall(allArgs[index], state)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
} else {
|
||||
// parse the string to get the value
|
||||
auto possible_value = cm::string_view(input).substr(this->Name.size());
|
||||
if (possible_value.empty()) {
|
||||
parseState = ParseMode::SyntaxError;
|
||||
parseState = ParseMode::ValueError;
|
||||
} else if (possible_value[0] == '=') {
|
||||
possible_value.remove_prefix(1);
|
||||
if (possible_value.empty()) {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
parseState = this->StoreCall(std::string(possible_value), state)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
if (parseState == ParseMode::Valid) {
|
||||
parseState = this->StoreCall(std::string(possible_value), state)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
} else if (this->Type == CommandArgument::Values::Two) {
|
||||
if (input.size() == this->Name.size()) {
|
||||
if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
|
||||
allArgs[index + 2][0] == '-') {
|
||||
parseState = ParseMode::ValueError;
|
||||
} else {
|
||||
index += 2;
|
||||
parseState =
|
||||
this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
|
||||
state)
|
||||
? ParseMode::Valid
|
||||
: ParseMode::Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parseState == ParseMode::SyntaxError) {
|
||||
cmSystemTools::Error(this->InvalidSyntaxMessage);
|
||||
} else if (parseState == ParseMode::ValueError) {
|
||||
cmSystemTools::Error(this->InvalidValueMessage);
|
||||
}
|
||||
return (parseState == ParseMode::Valid);
|
||||
}
|
||||
};
|
||||
|
||||
auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool {
|
||||
return true;
|
||||
};
|
||||
|
||||
using CommandArgument =
|
||||
cmCommandLineArgument<bool(std::string const& value, cmake* state)>;
|
||||
|
||||
} // namespace
|
||||
|
||||
static bool cmakeCheckStampFile(const std::string& stampName);
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <cm3p/uv.h>
|
||||
|
||||
#include "cmCommandLineArgument.h"
|
||||
#include "cmConsoleBuf.h"
|
||||
#include "cmDocumentationEntry.h" // IWYU pragma: keep
|
||||
#include "cmGlobalGenerator.h"
|
||||
@ -213,61 +214,115 @@ int do_cmake(int ac, char const* const* av)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool wizard_mode = false;
|
||||
bool sysinfo = false;
|
||||
bool list_cached = false;
|
||||
bool list_all_cached = false;
|
||||
bool list_help = false;
|
||||
bool view_only = false;
|
||||
cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
|
||||
std::vector<std::string> args;
|
||||
for (int i = 0; i < ac; ++i) {
|
||||
if (strcmp(av[i], "-i") == 0) {
|
||||
/* clang-format off */
|
||||
std::cerr <<
|
||||
"The \"cmake -i\" wizard mode is no longer supported.\n"
|
||||
"Use the -D option to set cache values on the command line.\n"
|
||||
"Use cmake-gui or ccmake for an interactive dialog.\n";
|
||||
/* clang-format on */
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(av[i], "--system-information") == 0) {
|
||||
sysinfo = true;
|
||||
} else if (strcmp(av[i], "-N") == 0) {
|
||||
view_only = true;
|
||||
} else if (strcmp(av[i], "-L") == 0) {
|
||||
list_cached = true;
|
||||
} else if (strcmp(av[i], "-LA") == 0) {
|
||||
list_all_cached = true;
|
||||
} else if (strcmp(av[i], "-LH") == 0) {
|
||||
list_cached = true;
|
||||
list_help = true;
|
||||
} else if (strcmp(av[i], "-LAH") == 0) {
|
||||
list_all_cached = true;
|
||||
list_help = true;
|
||||
} else if (cmHasLiteralPrefix(av[i], "-P")) {
|
||||
if (i == ac - 1) {
|
||||
cmSystemTools::Error("No script specified for argument -P");
|
||||
return 1;
|
||||
std::vector<std::string> parsedArgs;
|
||||
|
||||
using CommandArgument =
|
||||
cmCommandLineArgument<bool(std::string const& value)>;
|
||||
std::vector<CommandArgument> arguments = {
|
||||
CommandArgument{
|
||||
"-i", CommandArgument::Values::Zero,
|
||||
[&wizard_mode](std::string const&) -> bool {
|
||||
/* clang-format off */
|
||||
std::cerr <<
|
||||
"The \"cmake -i\" wizard mode is no longer supported.\n"
|
||||
"Use the -D option to set cache values on the command line.\n"
|
||||
"Use cmake-gui or ccmake for an interactive dialog.\n";
|
||||
/* clang-format on */
|
||||
wizard_mode = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "--system-information", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
sysinfo = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-N", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
view_only = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-LAH", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
list_all_cached = true;
|
||||
list_help = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-LA", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
list_all_cached = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-LH", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
list_cached = true;
|
||||
list_help = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-L", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
list_cached = true;
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "-P", "No script specified for argument -P",
|
||||
CommandArgument::Values::One,
|
||||
[&](std::string const& value) -> bool {
|
||||
workingMode = cmake::SCRIPT_MODE;
|
||||
parsedArgs.emplace_back("-P");
|
||||
parsedArgs.push_back(std::move(value));
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "--find-package", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
workingMode = cmake::FIND_PACKAGE_MODE;
|
||||
parsedArgs.emplace_back("--find-package");
|
||||
return true;
|
||||
} },
|
||||
CommandArgument{ "--list-presets", CommandArgument::Values::Zero,
|
||||
[&](std::string const&) -> bool {
|
||||
workingMode = cmake::HELP_MODE;
|
||||
parsedArgs.emplace_back("--list-presets");
|
||||
return true;
|
||||
} },
|
||||
};
|
||||
|
||||
std::vector<std::string> inputArgs;
|
||||
inputArgs.reserve(ac);
|
||||
cm::append(inputArgs, av, av + ac);
|
||||
|
||||
for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) {
|
||||
std::string const& arg = inputArgs[i];
|
||||
bool matched = false;
|
||||
for (auto const& m : arguments) {
|
||||
if (m.matches(arg)) {
|
||||
matched = true;
|
||||
if (m.parse(arg, i, inputArgs)) {
|
||||
break;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
workingMode = cmake::SCRIPT_MODE;
|
||||
args.emplace_back(av[i]);
|
||||
i++;
|
||||
args.emplace_back(av[i]);
|
||||
} else if (cmHasLiteralPrefix(av[i], "--find-package")) {
|
||||
workingMode = cmake::FIND_PACKAGE_MODE;
|
||||
args.emplace_back(av[i]);
|
||||
} else if (strcmp(av[i], "--list-presets") == 0) {
|
||||
workingMode = cmake::HELP_MODE;
|
||||
args.emplace_back(av[i]);
|
||||
} else {
|
||||
args.emplace_back(av[i]);
|
||||
}
|
||||
if (!matched) {
|
||||
parsedArgs.emplace_back(av[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (wizard_mode) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sysinfo) {
|
||||
cmake cm(cmake::RoleProject, cmState::Project);
|
||||
cm.SetHomeDirectory("");
|
||||
cm.SetHomeOutputDirectory("");
|
||||
int ret = cm.GetSystemInformation(args);
|
||||
int ret = cm.GetSystemInformation(parsedArgs);
|
||||
return ret;
|
||||
}
|
||||
cmake::Role const role =
|
||||
@ -297,7 +352,7 @@ int do_cmake(int ac, char const* const* av)
|
||||
});
|
||||
cm.SetWorkingMode(workingMode);
|
||||
|
||||
int res = cm.Run(args, view_only);
|
||||
int res = cm.Run(parsedArgs, view_only);
|
||||
if (list_cached || list_all_cached) {
|
||||
std::cout << "-- Cache values" << std::endl;
|
||||
std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys();
|
||||
|
Loading…
Reference in New Issue
Block a user