cmParseArgumentsCommand: Port to cmArgumentParser

This commit is contained in:
Regina Pfeifer
2019-03-23 22:45:41 +01:00
committed by Kyle Edwards
parent 45edf1ad66
commit 9bddb03f31

View File

@@ -8,10 +8,12 @@
#include <utility> #include <utility>
#include "cmAlgorithms.h" #include "cmAlgorithms.h"
#include "cmArgumentParser.h"
#include "cmMakefile.h" #include "cmMakefile.h"
#include "cmMessageType.h" #include "cmMessageType.h"
#include "cmRange.h" #include "cmRange.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cm_string_view.hxx"
class cmExecutionStatus; class cmExecutionStatus;
@@ -28,42 +30,43 @@ static std::string EscapeArg(const std::string& arg)
return escapedArg; return escapedArg;
} }
namespace { static std::string JoinList(std::vector<std::string> const& arg, bool escape)
enum insideValues
{ {
NONE, return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
SINGLE, : cmJoin(cmMakeRange(arg), ";");
MULTI }
};
namespace {
typedef std::map<std::string, bool> options_map; typedef std::map<std::string, bool> options_map;
typedef std::map<std::string, std::string> single_map; typedef std::map<std::string, std::string> single_map;
typedef std::map<std::string, std::vector<std::string>> multi_map; typedef std::map<std::string, std::vector<std::string>> multi_map;
typedef std::set<std::string> options_set; typedef std::set<std::string> options_set;
}
// function to be called every time, a new key word was parsed or all struct UserArgumentParser : public cmArgumentParser<void>
// parameters where parsed.
static void DetectKeywordsMissingValues(insideValues currentState,
const std::string& currentArgName,
int& argumentsFound,
options_set& keywordsMissingValues)
{ {
if (currentState == SINGLE || template <typename T, typename H>
(currentState == MULTI && argumentsFound == 0)) { void Bind(std::vector<std::string> const& names,
keywordsMissingValues.insert(currentArgName); std::map<std::string, T>& ref, H duplicateKey)
{
for (std::string const& key : names) {
auto const it = ref.emplace(key, T{}).first;
bool const inserted = this->cmArgumentParser<void>::Bind(
cm::string_view(it->first), it->second);
if (!inserted) {
duplicateKey(key);
}
}
} }
};
argumentsFound = 0; } // namespace
}
static void PassParsedArguments(const std::string& prefix, static void PassParsedArguments(
cmMakefile& makefile, const std::string& prefix, cmMakefile& makefile, const options_map& options,
const options_map& options, const single_map& singleValArgs, const multi_map& multiValArgs,
const single_map& singleValArgs, const std::vector<std::string>& unparsed,
const multi_map& multiValArgs, const options_set& keywordsMissingValues, bool parseFromArgV)
const std::vector<std::string>& unparsed,
const options_set& keywordsMissingValues)
{ {
for (auto const& iter : options) { for (auto const& iter : options) {
makefile.AddDefinition(prefix + iter.first, makefile.AddDefinition(prefix + iter.first,
@@ -81,7 +84,7 @@ static void PassParsedArguments(const std::string& prefix,
for (auto const& iter : multiValArgs) { for (auto const& iter : multiValArgs) {
if (!iter.second.empty()) { if (!iter.second.empty()) {
makefile.AddDefinition(prefix + iter.first, makefile.AddDefinition(prefix + iter.first,
cmJoin(cmMakeRange(iter.second), ";").c_str()); JoinList(iter.second, parseFromArgV).c_str());
} else { } else {
makefile.RemoveDefinition(prefix + iter.first); makefile.RemoveDefinition(prefix + iter.first);
} }
@@ -89,7 +92,7 @@ static void PassParsedArguments(const std::string& prefix,
if (!unparsed.empty()) { if (!unparsed.empty()) {
makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS", makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
cmJoin(cmMakeRange(unparsed), ";").c_str()); JoinList(unparsed, parseFromArgV).c_str());
} else { } else {
makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS"); makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
} }
@@ -141,6 +144,8 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// the first argument is the prefix // the first argument is the prefix
const std::string prefix = (*argIter++) + "_"; const std::string prefix = (*argIter++) + "_";
UserArgumentParser parser;
// define the result maps holding key/value pairs for // define the result maps holding key/value pairs for
// options, single values and multi values // options, single values and multi values
options_map options; options_map options;
@@ -150,45 +155,25 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// anything else is put into a vector of unparsed strings // anything else is put into a vector of unparsed strings
std::vector<std::string> unparsed; std::vector<std::string> unparsed;
// remember already defined keywords auto const duplicateKey = [this](std::string const& key) {
std::set<std::string> used_keywords; this->GetMakefile()->IssueMessage(
const std::string dup_warning = "keyword defined more than once: "; MessageType::WARNING, "keyword defined more than once: " + key);
};
// the second argument is a (cmake) list of options without argument // the second argument is a (cmake) list of options without argument
std::vector<std::string> list; std::vector<std::string> list;
cmSystemTools::ExpandListArgument(*argIter++, list); cmSystemTools::ExpandListArgument(*argIter++, list);
for (std::string const& iter : list) { parser.Bind(list, options, duplicateKey);
if (!used_keywords.insert(iter).second) {
this->GetMakefile()->IssueMessage(MessageType::WARNING,
dup_warning + iter);
}
options[iter]; // default initialize
}
// the third argument is a (cmake) list of single argument options // the third argument is a (cmake) list of single argument options
list.clear(); list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list); cmSystemTools::ExpandListArgument(*argIter++, list);
for (std::string const& iter : list) { parser.Bind(list, singleValArgs, duplicateKey);
if (!used_keywords.insert(iter).second) {
this->GetMakefile()->IssueMessage(MessageType::WARNING,
dup_warning + iter);
}
singleValArgs[iter]; // default initialize
}
// the fourth argument is a (cmake) list of multi argument options // the fourth argument is a (cmake) list of multi argument options
list.clear(); list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list); cmSystemTools::ExpandListArgument(*argIter++, list);
for (std::string const& iter : list) { parser.Bind(list, multiValArgs, duplicateKey);
if (!used_keywords.insert(iter).second) {
this->GetMakefile()->IssueMessage(MessageType::WARNING,
dup_warning + iter);
}
multiValArgs[iter]; // default initialize
}
insideValues insideValues = NONE;
std::string currentArgName;
list.clear(); list.clear();
if (!parseFromArgV) { if (!parseFromArgV) {
@@ -223,68 +208,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
} }
} }
options_set keywordsMissingValues; std::vector<std::string> keywordsMissingValues;
int multiArgumentsFound = 0;
// iterate over the arguments list and fill in the values where applicable parser.Parse(list, &unparsed, &keywordsMissingValues);
for (std::string const& arg : list) {
const options_map::iterator optIter = options.find(arg);
if (optIter != options.end()) {
DetectKeywordsMissingValues(insideValues, currentArgName,
multiArgumentsFound, keywordsMissingValues);
insideValues = NONE;
optIter->second = true;
continue;
}
const single_map::iterator singleIter = singleValArgs.find(arg); PassParsedArguments(
if (singleIter != singleValArgs.end()) { prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed,
DetectKeywordsMissingValues(insideValues, currentArgName, options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
multiArgumentsFound, keywordsMissingValues); parseFromArgV);
insideValues = SINGLE;
currentArgName = arg;
continue;
}
const multi_map::iterator multiIter = multiValArgs.find(arg);
if (multiIter != multiValArgs.end()) {
DetectKeywordsMissingValues(insideValues, currentArgName,
multiArgumentsFound, keywordsMissingValues);
insideValues = MULTI;
currentArgName = arg;
continue;
}
switch (insideValues) {
case SINGLE:
singleValArgs[currentArgName] = arg;
insideValues = NONE;
break;
case MULTI:
++multiArgumentsFound;
if (parseFromArgV) {
multiValArgs[currentArgName].push_back(EscapeArg(arg));
} else {
multiValArgs[currentArgName].push_back(arg);
}
break;
default:
multiArgumentsFound = 0;
if (parseFromArgV) {
unparsed.push_back(EscapeArg(arg));
} else {
unparsed.push_back(arg);
}
break;
}
}
DetectKeywordsMissingValues(insideValues, currentArgName,
multiArgumentsFound, keywordsMissingValues);
PassParsedArguments(prefix, *this->Makefile, options, singleValArgs,
multiValArgs, unparsed, keywordsMissingValues);
return true; return true;
} }