From 3e2e0d062b3e296d3e25897114c8646c9f664f52 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 17 Jan 2018 11:14:57 +0100 Subject: [PATCH] util/OptionParser: support option values --- src/util/OptionDef.hxx | 14 +++++++++++ src/util/OptionParser.cxx | 49 ++++++++++++++++++++++++++++++++------- src/util/OptionParser.hxx | 4 +++- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/util/OptionDef.hxx b/src/util/OptionDef.hxx index aa83045f4..ab8b255bf 100644 --- a/src/util/OptionDef.hxx +++ b/src/util/OptionDef.hxx @@ -29,6 +29,7 @@ class OptionDef { const char *long_option; char short_option; + bool has_value = false; const char *desc; public: constexpr OptionDef(const char *_long_option, const char *_desc) @@ -42,8 +43,21 @@ public: short_option(_short_option), desc(_desc) { } + constexpr OptionDef(const char *_long_option, + char _short_option, bool _has_value, + const char *_desc) noexcept + :long_option(_long_option), + short_option(_short_option), + has_value(_has_value), + desc(_desc) {} + constexpr bool HasLongOption() const { return long_option != nullptr; } constexpr bool HasShortOption() const { return short_option != 0; } + + constexpr bool HasValue() const noexcept { + return has_value; + } + constexpr bool HasDescription() const { return desc != nullptr; } const char *GetLongOption() const { diff --git a/src/util/OptionParser.cxx b/src/util/OptionParser.cxx index b48873777..72fb05f7f 100644 --- a/src/util/OptionParser.cxx +++ b/src/util/OptionParser.cxx @@ -20,25 +20,56 @@ #include "OptionParser.hxx" #include "OptionDef.hxx" #include "util/RuntimeError.hxx" +#include "util/StringCompare.hxx" #include +inline const char * +OptionParser::CheckShiftValue(const char *s, const OptionDef &option) +{ + if (!option.HasValue()) + return nullptr; + + if (args.empty()) + throw FormatRuntimeError("Value expected after %s", s); + + return args.shift(); +} + inline OptionParser::Result -OptionParser::IdentifyOption(const char *s) const +OptionParser::IdentifyOption(const char *s) { assert(s != nullptr); assert(*s == '-'); if (s[1] == '-') { - for (const auto &i : options) - if (i.HasLongOption() && - strcmp(s + 2, i.GetLongOption()) == 0) - return {int(&i - options.data)}; + for (const auto &i : options) { + if (!i.HasLongOption()) + continue; + + const char *t = StringAfterPrefix(s + 2, i.GetLongOption()); + if (t == nullptr) + continue; + + const char *value; + + if (*t == 0) + value = CheckShiftValue(s, i); + else if (*t == '=') + value = t + 1; + else + continue; + + return {int(&i - options.data), value}; + } } else if (s[1] != 0 && s[2] == 0) { const char ch = s[1]; - for (const auto &i : options) - if (i.HasShortOption() && ch == i.GetShortOption()) - return {int(&i - options.data)}; + for (const auto &i : options) { + if (i.HasShortOption() && ch == i.GetShortOption()) { + const char *value = CheckShiftValue(s, i); + return {int(&i - options.data), value}; + } + } } throw FormatRuntimeError("Unknown option: %s", s); @@ -55,5 +86,5 @@ OptionParser::Next() *remaining_tail++ = arg; } - return {-1}; + return {-1, nullptr}; } diff --git a/src/util/OptionParser.hxx b/src/util/OptionParser.hxx index a7176a4c3..a6a95a325 100644 --- a/src/util/OptionParser.hxx +++ b/src/util/OptionParser.hxx @@ -47,6 +47,7 @@ public: struct Result { int index; + const char *value; constexpr operator bool() noexcept { return index >= 0; @@ -70,7 +71,8 @@ public: } private: - Result IdentifyOption(const char *s) const; + const char *CheckShiftValue(const char *s, const OptionDef &option); + Result IdentifyOption(const char *s); }; #endif