summaryrefslogtreecommitdiffstats
path: root/Source/cmParseArgumentsCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmParseArgumentsCommand.cxx')
-rw-r--r--Source/cmParseArgumentsCommand.cxx204
1 files changed, 95 insertions, 109 deletions
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 796974c..5213432 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -8,13 +8,16 @@
#include <utility>
#include "cmAlgorithms.h"
+#include "cmArgumentParser.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cm_string_view.hxx"
class cmExecutionStatus;
-static std::string escape_arg(const std::string& arg)
+static std::string EscapeArg(const std::string& arg)
{
// replace ";" with "\;" so output argument lists will split correctly
std::string escapedArg;
@@ -27,6 +30,82 @@ static std::string escape_arg(const std::string& arg)
return escapedArg;
}
+static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+{
+ return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
+ : cmJoin(cmMakeRange(arg), ";");
+}
+
+namespace {
+
+typedef std::map<std::string, bool> options_map;
+typedef std::map<std::string, std::string> single_map;
+typedef std::map<std::string, std::vector<std::string>> multi_map;
+typedef std::set<std::string> options_set;
+
+struct UserArgumentParser : public cmArgumentParser<void>
+{
+ template <typename T, typename H>
+ void Bind(std::vector<std::string> const& names,
+ 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);
+ }
+ }
+ }
+};
+
+} // namespace
+
+static void PassParsedArguments(
+ const std::string& prefix, cmMakefile& makefile, const options_map& options,
+ const single_map& singleValArgs, const multi_map& multiValArgs,
+ const std::vector<std::string>& unparsed,
+ const options_set& keywordsMissingValues, bool parseFromArgV)
+{
+ for (auto const& iter : options) {
+ makefile.AddDefinition(prefix + iter.first,
+ iter.second ? "TRUE" : "FALSE");
+ }
+
+ for (auto const& iter : singleValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first, iter.second.c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ for (auto const& iter : multiValArgs) {
+ if (!iter.second.empty()) {
+ makefile.AddDefinition(prefix + iter.first,
+ JoinList(iter.second, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + iter.first);
+ }
+ }
+
+ if (!unparsed.empty()) {
+ makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
+ JoinList(unparsed, parseFromArgV).c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
+ }
+
+ if (!keywordsMissingValues.empty()) {
+ makefile.AddDefinition(
+ prefix + "KEYWORDS_MISSING_VALUES",
+ cmJoin(cmMakeRange(keywordsMissingValues), ";").c_str());
+ } else {
+ makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
+ }
+}
+
bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&)
{
@@ -65,11 +144,10 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// the first argument is the prefix
const std::string prefix = (*argIter++) + "_";
+ UserArgumentParser parser;
+
// define the result maps holding key/value pairs for
// options, single values and multi values
- typedef std::map<std::string, bool> options_map;
- typedef std::map<std::string, std::string> single_map;
- typedef std::map<std::string, std::vector<std::string>> multi_map;
options_map options;
single_map singleValArgs;
multi_map multiValArgs;
@@ -77,50 +155,25 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
// anything else is put into a vector of unparsed strings
std::vector<std::string> unparsed;
- // remember already defined keywords
- std::set<std::string> used_keywords;
- const std::string dup_warning = "keyword defined more than once: ";
+ auto const duplicateKey = [this](std::string const& key) {
+ this->GetMakefile()->IssueMessage(
+ MessageType::WARNING, "keyword defined more than once: " + key);
+ };
// the second argument is a (cmake) list of options without argument
std::vector<std::string> list;
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- options[iter]; // default initialize
- }
+ parser.Bind(list, options, duplicateKey);
// the third argument is a (cmake) list of single argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- singleValArgs[iter]; // default initialize
- }
+ parser.Bind(list, singleValArgs, duplicateKey);
// the fourth argument is a (cmake) list of multi argument options
list.clear();
cmSystemTools::ExpandListArgument(*argIter++, list);
- for (std::string const& iter : list) {
- if (!used_keywords.insert(iter).second) {
- this->GetMakefile()->IssueMessage(MessageType::WARNING,
- dup_warning + iter);
- }
- multiValArgs[iter]; // default initialize
- }
-
- enum insideValues
- {
- NONE,
- SINGLE,
- MULTI
- } insideValues = NONE;
- std::string currentArgName;
+ parser.Bind(list, multiValArgs, duplicateKey);
list.clear();
if (!parseFromArgV) {
@@ -155,81 +208,14 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args,
}
}
- // iterate over the arguments list and fill in the values where applicable
- for (std::string const& arg : list) {
- const options_map::iterator optIter = options.find(arg);
- if (optIter != options.end()) {
- insideValues = NONE;
- optIter->second = true;
- continue;
- }
-
- const single_map::iterator singleIter = singleValArgs.find(arg);
- if (singleIter != singleValArgs.end()) {
- insideValues = SINGLE;
- currentArgName = arg;
- continue;
- }
-
- const multi_map::iterator multiIter = multiValArgs.find(arg);
- if (multiIter != multiValArgs.end()) {
- insideValues = MULTI;
- currentArgName = arg;
- continue;
- }
-
- switch (insideValues) {
- case SINGLE:
- singleValArgs[currentArgName] = arg;
- insideValues = NONE;
- break;
- case MULTI:
- if (parseFromArgV) {
- multiValArgs[currentArgName].push_back(escape_arg(arg));
- } else {
- multiValArgs[currentArgName].push_back(arg);
- }
- break;
- default:
- if (parseFromArgV) {
- unparsed.push_back(escape_arg(arg));
- } else {
- unparsed.push_back(arg);
- }
- break;
- }
- }
+ std::vector<std::string> keywordsMissingValues;
- // now iterate over the collected values and update their definition
- // within the current scope. undefine if necessary.
+ parser.Parse(list, &unparsed, &keywordsMissingValues);
- for (auto const& iter : options) {
- this->Makefile->AddDefinition(prefix + iter.first,
- iter.second ? "TRUE" : "FALSE");
- }
- for (auto const& iter : singleValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(prefix + iter.first, iter.second.c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- for (auto const& iter : multiValArgs) {
- if (!iter.second.empty()) {
- this->Makefile->AddDefinition(
- prefix + iter.first, cmJoin(cmMakeRange(iter.second), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + iter.first);
- }
- }
-
- if (!unparsed.empty()) {
- this->Makefile->AddDefinition(prefix + "UNPARSED_ARGUMENTS",
- cmJoin(cmMakeRange(unparsed), ";").c_str());
- } else {
- this->Makefile->RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
- }
+ PassParsedArguments(
+ prefix, *this->Makefile, options, singleValArgs, multiValArgs, unparsed,
+ options_set(keywordsMissingValues.begin(), keywordsMissingValues.end()),
+ parseFromArgV);
return true;
}