diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarOptionParser.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarOptionParser.cpp')
-rw-r--r-- | source/core/StarOptionParser.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/source/core/StarOptionParser.cpp b/source/core/StarOptionParser.cpp new file mode 100644 index 0000000..f9d51ff --- /dev/null +++ b/source/core/StarOptionParser.cpp @@ -0,0 +1,162 @@ +#include "StarOptionParser.hpp" +#include "StarIterator.hpp" + +namespace Star { + +void OptionParser::setCommandName(String commandName) { + m_commandName = move(commandName); +} + +void OptionParser::setSummary(String summary) { + m_summary = move(summary); +} + +void OptionParser::setAdditionalHelp(String help) { + m_additionalHelp = move(help); +} + +void OptionParser::addSwitch(String const& flag, String description) { + if (!m_options.insert(flag, Switch{flag, move(description)}).second) + throw OptionParserException::format("Duplicate switch '-%s' added", flag); +} + +void OptionParser::addParameter(String const& flag, String argument, RequirementMode requirementMode, String description) { + if (!m_options.insert(flag, Parameter{flag, move(argument), requirementMode, move(description)}).second) + throw OptionParserException::format("Duplicate flag '-%s' added", flag); +} + +void OptionParser::addArgument(String argument, RequirementMode requirementMode, String description) { + m_arguments.append(Argument{move(argument), requirementMode, move(description)}); +} + +pair<OptionParser::Options, StringList> OptionParser::parseOptions(StringList const& arguments) const { + Options result; + StringList errors; + bool endOfFlags = false; + + auto it = makeSIterator(arguments); + while (it.hasNext()) { + auto const& arg = it.next(); + if (arg == "--") { + endOfFlags = true; + continue; + } + + if (!endOfFlags && arg.beginsWith("-")) { + String flag = arg.substr(1); + auto option = m_options.maybe(flag); + if (!option) { + errors.append(strf("No such option '-%s'", flag)); + continue; + } + + if (option->is<Switch>()) { + result.switches.add(move(flag)); + } else { + auto const& parameter = option->get<Parameter>(); + if (!it.hasNext()) { + errors.append(strf("Option '-%s' must be followed by an argument", flag)); + continue; + } + String val = it.next(); + if (parameter.requirementMode != Multiple && result.parameters.contains(flag)) { + errors.append(strf("Option with argument '-%s' specified multiple times", flag)); + continue; + } + result.parameters[move(flag)].append(move(val)); + } + + } else { + result.arguments.append(move(arg)); + } + } + + for (auto const& pair : m_options) { + if (pair.second.is<Parameter>()) { + auto const& na = pair.second.get<Parameter>(); + if (na.requirementMode == Required && !result.parameters.contains(pair.first)) + errors.append(strf("Missing required flag with argument '-%s'", pair.first)); + } + } + + size_t minimumArguments = 0; + size_t maximumArguments = 0; + for (auto const& argument : m_arguments) { + if ((argument.requirementMode == Optional || argument.requirementMode == Required) && maximumArguments != NPos) + ++maximumArguments; + if (argument.requirementMode == Required) + ++minimumArguments; + if (argument.requirementMode == Multiple) + maximumArguments = NPos; + } + if (result.arguments.size() < minimumArguments) + errors.append(strf( + "Too few positional arguments given, expected at least %s got %s", minimumArguments, result.arguments.size())); + if (result.arguments.size() > maximumArguments) + errors.append(strf( + "Too many positional arguments given, expected at most %s got %s", maximumArguments, result.arguments.size())); + + return {move(result), move(errors)}; +} + +void OptionParser::printHelp(std::ostream& os) const { + if (!m_commandName.empty() && !m_summary.empty()) + format(os, "%s: %s\n\n", m_commandName, m_summary); + else if (!m_commandName.empty()) + format(os, "%s:\n\n", m_commandName); + else if (!m_summary.empty()) + format(os, "%s\n\n", m_summary); + + String cmdLineText; + + for (auto const& p : m_options) { + if (p.second.is<Switch>()) { + cmdLineText += strf(" [-%s]", p.first); + } else { + auto const& parameter = p.second.get<Parameter>(); + if (parameter.requirementMode == Optional) + cmdLineText += strf(" [-%s <%s>]", parameter.flag, parameter.argument); + else if (parameter.requirementMode == Required) + cmdLineText += strf(" -%s <%s>", parameter.flag, parameter.argument); + else if (parameter.requirementMode == Multiple) + cmdLineText += strf(" [-%s <%s>]...", parameter.flag, parameter.argument); + } + } + + for (auto const& p : m_arguments) { + if (p.requirementMode == Optional) + cmdLineText += strf(" [<%s>]", p.argumentName); + else if (p.requirementMode == Required) + cmdLineText += strf(" <%s>", p.argumentName); + else + cmdLineText += strf(" [<%s>...]", p.argumentName); + } + + if (m_commandName.empty()) + format(os, "Command Line Usage:%s\n", cmdLineText); + else + format(os, "Command Line Usage: %s%s\n", m_commandName, cmdLineText); + + for (auto const& p : m_options) { + if (p.second.is<Switch>()) { + auto const& sw = p.second.get<Switch>(); + if (!sw.description.empty()) + format(os, " -%s\t- %s\n", sw.flag, sw.description); + } + if (p.second.is<Parameter>()) { + auto const& parameter = p.second.get<Parameter>(); + if (!parameter.description.empty()) + format(os, " -%s <%s>\t- %s\n", parameter.flag, parameter.argument, parameter.description); + } + } + + for (auto const& p : m_arguments) { + if (!p.description.empty()) + format(os, " <%s>\t- %s\n", p.argumentName, p.description); + } + + if (!m_additionalHelp.empty()) + format(os, "\n%s\n", m_additionalHelp); +} + +} |