/* 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 struct cmCommandLineArgument { enum class Values { Zero, One, Two, ZeroOrOne, OneOrMore }; std::string InvalidSyntaxMessage; std::string InvalidValueMessage; std::string Name; Values Type; std::function StoreCall; template 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(func)) { } template 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(func)) { } bool matches(std::string const& input) const { return (this->Type == Values::Zero) ? (input == this->Name) : cmHasPrefix(input, this->Name); } template bool parse(std::string const& input, T& index, std::vector 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(state)...) ? ParseMode::Valid : ParseMode::Invalid; } else { parseState = ParseMode::SyntaxError; } } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) { if (input.size() == this->Name.size()) { auto nextValueIndex = index + 1; if (nextValueIndex >= allArgs.size() || allArgs[nextValueIndex][0] == '-') { if (this->Type == Values::ZeroOrOne) { parseState = this->StoreCall(std::string{}, std::forward(state)...) ? ParseMode::Valid : ParseMode::Invalid; } else { parseState = ParseMode::ValueError; } } else { parseState = this->StoreCall(allArgs[nextValueIndex], std::forward(state)...) ? ParseMode::Valid : ParseMode::Invalid; index = nextValueIndex; } } 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(state)...) ? ParseMode::Valid : ParseMode::Invalid; } } if (parseState == ParseMode::Valid) { if (possible_value[0] == ' ') { possible_value.remove_prefix(1); } parseState = this->StoreCall(std::string(possible_value), std::forward(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(state)...) ? ParseMode::Valid : ParseMode::Invalid; } } } else if (this->Type == Values::OneOrMore) { if (input.size() == this->Name.size()) { auto nextValueIndex = index + 1; if (nextValueIndex >= allArgs.size() || allArgs[nextValueIndex][0] == '-') { parseState = ParseMode::ValueError; } else { std::string buffer = allArgs[nextValueIndex++]; while (nextValueIndex < allArgs.size() && allArgs[nextValueIndex][0] != '-') { buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]); } parseState = this->StoreCall(buffer, std::forward(state)...) ? ParseMode::Valid : ParseMode::Invalid; index = (nextValueIndex - 1); } } } if (parseState == ParseMode::SyntaxError) { cmSystemTools::Error(this->InvalidSyntaxMessage); } else if (parseState == ParseMode::ValueError) { cmSystemTools::Error(this->InvalidValueMessage); } return (parseState == ParseMode::Valid); } };