summaryrefslogtreecommitdiff
path: root/Source/cmCommandLineArgument.h
diff options
context:
space:
mode:
authorRobert Maynard <robert.maynard@kitware.com>2020-12-28 16:41:18 -0500
committerBrad King <brad.king@kitware.com>2021-01-06 09:11:14 -0500
commit0fb78576b00aa9ca39112210d19ec53b0e6e975c (patch)
tree5df1efa060f264ed5833bada9197ab202169db47 /Source/cmCommandLineArgument.h
parent25a1cdef956e0c26067edbef3daa55ec6c65caae (diff)
downloadcmake-0fb78576b00aa9ca39112210d19ec53b0e6e975c.tar.gz
cmake: Use shared parsing code for all cmake argv parsing
Diffstat (limited to 'Source/cmCommandLineArgument.h')
-rw-r--r--Source/cmCommandLineArgument.h133
1 files changed, 133 insertions, 0 deletions
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
new file mode 100644
index 0000000000..aa96305f54
--- /dev/null
+++ b/Source/cmCommandLineArgument.h
@@ -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);
+ }
+};