aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/getopt/small/last_getopt_opts.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/getopt/small/last_getopt_opts.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/getopt/small/last_getopt_opts.h')
-rw-r--r--library/cpp/getopt/small/last_getopt_opts.h643
1 files changed, 643 insertions, 0 deletions
diff --git a/library/cpp/getopt/small/last_getopt_opts.h b/library/cpp/getopt/small/last_getopt_opts.h
new file mode 100644
index 0000000000..825b99c871
--- /dev/null
+++ b/library/cpp/getopt/small/last_getopt_opts.h
@@ -0,0 +1,643 @@
+#pragma once
+
+#include "last_getopt_opt.h"
+
+#include <library/cpp/colorizer/fwd.h>
+
+#include <util/generic/map.h>
+
+namespace NLastGetopt {
+ enum EArgPermutation {
+ REQUIRE_ORDER,
+ PERMUTE,
+ RETURN_IN_ORDER,
+ DEFAULT_ARG_PERMUTATION = PERMUTE
+ };
+
+ /**
+ * NLastGetopt::TOpts is a storage of program options' parse rules.
+ * It contains information about all options, free args, some parsing options
+ * and rules about interaction between options.
+ *
+ * The main point for defining program options.
+ *
+ * The parsing rules determined by the following parts:
+ * - Arguments permutation. It is expected free args be after named args.
+ * This point adjusts how to treat breaking this expectation.
+ * if REQUIRE_ORDER is choosen, the exception during parsing will be raised,
+ * the special string " -- " will be treated as end of named
+ * options: all options after it will be parsed as free args
+ * if PERMUTE is choosen, arguments will be rearranged in correct order,
+ * if RETURN_IN_ORDER is choosen, all free args will be ommited (TODO: looks very strange)
+ * - Using '+' as a prefix instead '--' for long names
+ * - Using "-" as a prefix for both short and long names
+ * - Allowing unknown options
+ *
+ */
+ class TOpts {
+ friend class TOptsParseResult;
+ friend class TOptsParser;
+
+ public:
+ static constexpr const ui32 UNLIMITED_ARGS = Max<ui32>();
+
+ typedef TVector<TSimpleSharedPtr<TOpt>> TOptsVector;
+ TOptsVector Opts_; // infomation about named (short and long) options
+ TVector<std::function<void(TStringBuf)>> ArgBindings_;
+
+ EArgPermutation ArgPermutation_ = DEFAULT_ARG_PERMUTATION; // determines how to parse positions of named and free options. See information below.
+ bool AllowSingleDashForLong_ = false; //
+ bool AllowPlusForLong_ = false; // using '+' instead '--' for long options
+
+ //Allows unknwon options:
+ bool AllowUnknownCharOptions_ = false;
+ bool AllowUnknownLongOptions_ = false;
+
+ ui32 Wrap_ = 80;
+
+ private:
+ ui32 FreeArgsMin_; // minimal number of free args
+ ui32 FreeArgsMax_; // maximal number of free args
+
+ TMap<ui32, TFreeArgSpec> FreeArgSpecs_; // mapping [free arg position] -> [free arg specification]
+ TFreeArgSpec TrailingArgSpec_; // spec for the trailing argument (when arguments are unlimited)
+ TString DefaultFreeArgTitle_ = "ARG"; // title that's used for free args without a title
+
+ TString Title; // title of the help string
+ TString CustomCmdLineDescr; // user defined help string
+ TString CustomUsage; // user defined usage string
+
+ TVector<std::pair<TString, TString>> Sections; // additional help entries to print after usage
+
+ public:
+ /**
+ * Constructs TOpts from string as in getopt(3)
+ */
+ TOpts(const TStringBuf& optstring = TStringBuf());
+
+ /**
+ * Constructs TOpts from string as in getopt(3) and
+ * additionally adds help option (for '?') and svn-verstion option (for 'V')
+ */
+ static TOpts Default(const TStringBuf& optstring = TStringBuf()) {
+ TOpts opts(optstring);
+ opts.AddHelpOption();
+ opts.AddVersionOption();
+ return opts;
+ }
+
+ /**
+ * Checks correctness of options' descriptions.
+ * Throws TConfException if validation failed.
+ * Check consist of:
+ * -not intersecting of names
+ * -compability of settings, that responsable for freeArgs parsing
+ */
+ void Validate() const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ const TOpt* FindLongOption(const TStringBuf& name) const;
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ const TOpt* FindCharOption(char c) const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ TOpt* FindLongOption(const TStringBuf& name);
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ TOpt* FindCharOption(char c);
+
+ /**
+ * Search for the option with given name
+ * @param name name for search
+ * @return ptr on result (nullptr if not found)
+ */
+ /// @{
+
+ const TOpt* FindOption(const TStringBuf& name) const {
+ return FindLongOption(name);
+ }
+
+ TOpt* FindOption(const TStringBuf& name) {
+ return FindLongOption(name);
+ }
+
+ const TOpt* FindOption(char c) const {
+ return FindCharOption(c);
+ }
+
+ TOpt* FindOption(char c) {
+ return FindCharOption(c);
+ }
+
+ /// @}
+
+ /**
+ * Sets title of the help string
+ * @param title title to set
+ */
+ void SetTitle(const TString& title) {
+ Title = title;
+ }
+
+ /**
+ * @return true if there is an option with given long name
+ *
+ * @param name long name for search
+ */
+ bool HasLongOption(const TString& name) const {
+ return FindLongOption(name) != nullptr;
+ }
+
+ /**
+ * @return true if there is an option with given short name
+ *
+ * @param char short name for search
+ */
+ bool HasCharOption(char c) const {
+ return FindCharOption(c) != nullptr;
+ }
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ref on result (throw exception if not found)
+ */
+ const TOpt& GetLongOption(const TStringBuf& name) const;
+
+ /**
+ * Search for the option with given long name
+ * @param name long name for search
+ * @return ref on result (throw exception if not found)
+ */
+ TOpt& GetLongOption(const TStringBuf& name);
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ref on result (throw exception if not found)
+ */
+ const TOpt& GetCharOption(char c) const;
+
+ /**
+ * Search for the option with given short name
+ * @param c short name for search
+ * @return ref on result (throw exception if not found)
+ */
+ TOpt& GetCharOption(char c);
+
+ /**
+ * Search for the option with given name
+ * @param name name for search
+ * @return ref on result (throw exception if not found)
+ */
+ /// @{
+
+ const TOpt& GetOption(const TStringBuf& name) const {
+ return GetLongOption(name);
+ }
+
+ TOpt& GetOption(const TStringBuf& name) {
+ return GetLongOption(name);
+ }
+
+ const TOpt& GetOption(char c) const {
+ return GetCharOption(c);
+ }
+
+ TOpt& GetOption(char c) {
+ return GetCharOption(c);
+ }
+
+ /// @}
+
+ /**
+ * @return true if short options exist
+ */
+ bool HasAnyShortOption() const;
+
+ /**
+ * @return true if long options exist
+ */
+ bool HasAnyLongOption() const;
+
+ /**
+ * Creates new [option description (TOpt)] as a copy of given one
+ * @param option source
+ * @return reference for created option
+ */
+ TOpt& AddOption(const TOpt& option);
+
+ /**
+ * Creates new free argument handling
+ * @param name name of free arg to show in help
+ * @param target variable address to store parsing result into
+ * @param help help string to show in help
+ */
+ template <typename T>
+ void AddFreeArgBinding(const TString& name, T& target, const TString& help = "") {
+ ArgBindings_.emplace_back([&target](TStringBuf value) {
+ target = FromString<T>(value);
+ });
+
+ FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
+ SetFreeArgTitle(ArgBindings_.size() - 1, name, help);
+ }
+
+ /**
+ * Creates options list from string as in getopt(3)
+ *
+ * @param optstring source
+ */
+ void AddCharOptions(const TStringBuf& optstring);
+
+ /**
+ * Creates new [option description (TOpt)] with given short name and given help string
+ *
+ * @param c short name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddCharOption(char c, const TString& help = "") {
+ return AddCharOption(c, DEFAULT_HAS_ARG, help);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given short name and given help string
+ *
+ * @param c short name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddCharOption(char c, EHasArg hasArg, const TString& help = "") {
+ TOpt option;
+ option.AddShortName(c);
+ option.Help(help);
+ option.HasArg(hasArg);
+ return AddOption(option);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given long name and given help string
+ *
+ * @param name long name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddLongOption(const TString& name, const TString& help = "") {
+ return AddLongOption(0, name, help);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] with given long and short names and given help string
+ *
+ * @param c short name
+ * @param name long name
+ * @param help help string
+ * @return reference for created option
+ */
+ TOpt& AddLongOption(char c, const TString& name, const TString& help = "") {
+ TOpt option;
+ if (c != 0)
+ option.AddShortName(c);
+ option.AddLongName(name);
+ option.Help(help);
+ return AddOption(option);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] for help printing,
+ * adds appropriate handler for it
+ * If "help" option already exist, will add given short name to it.
+ *
+ * @param c new short name for help option
+ */
+ TOpt& AddHelpOption(char c = '?') {
+ if (TOpt* o = FindLongOption("help")) {
+ if (!o->CharIs(c))
+ o->AddShortName(c);
+ return *o;
+ }
+ return AddLongOption(c, "help", "print usage")
+ .HasArg(NO_ARGUMENT)
+ .IfPresentDisableCompletion()
+ .Handler(&PrintUsageAndExit);
+ }
+
+ /**
+ * Creates new [option description (TOpt)] for svn-revision printing,
+ * adds appropriate handler for it.
+ * If "svnversion" option already exist, will add given short name to it.
+ *
+ * @param c new short name for "svnversion" option
+ */
+ TOpt& AddVersionOption(char c = 'V') {
+ if (TOpt* o = FindLongOption("svnrevision")) {
+ if (!o->CharIs(c))
+ o->AddShortName(c);
+ return *o;
+ }
+ return AddLongOption(c, "svnrevision", "print svn version")
+ .HasArg(NO_ARGUMENT)
+ .IfPresentDisableCompletion()
+ .Handler(&PrintVersionAndExit);
+ }
+
+ /**
+ * Creates new option for generating completion shell scripts.
+ *
+ * @param command name of command that should be completed (typically corresponds to the executable name).
+ */
+ TOpt& AddCompletionOption(TString command, TString longName = "completion");
+
+ /**
+ * Creates or finds option with given short name
+ *
+ * @param c new short name for search/create
+ */
+ TOpt& CharOption(char c) {
+ const TOpt* opt = FindCharOption(c);
+ if (opt != nullptr) {
+ return const_cast<TOpt&>(*opt);
+ } else {
+ AddCharOption(c);
+ return const_cast<TOpt&>(GetCharOption(c));
+ }
+ }
+
+ /**
+ * Indicate that some options can't appear together.
+ *
+ * Note: this is not transitive.
+ *
+ * Note: don't use this on options with default values. If option with default value wasn't specified,
+ * parser will run handlers for default value, thus triggering a false-positive exclusivity check.
+ */
+ template <typename T1, typename T2>
+ void MutuallyExclusive(T1&& opt1, T2&& opt2) {
+ MutuallyExclusiveOpt(GetOption(std::forward<T1>(opt1)), GetOption(std::forward<T2>(opt2)));
+ }
+
+ /**
+ * Like `MutuallyExclusive`, but accepts `TOpt`s instead of option names.
+ */
+ void MutuallyExclusiveOpt(TOpt& opt1, TOpt& opt2);
+
+ /**
+ * @return index of option
+ *
+ * @param opt pointer of option to search
+ */
+ size_t IndexOf(const TOpt* opt) const;
+
+ /**
+ * Replace help string with given
+ *
+ * @param decr new help string
+ */
+ void SetCmdLineDescr(const TString& descr) {
+ CustomCmdLineDescr = descr;
+ }
+
+ /**
+ * Replace usage string with given
+ *
+ * @param usage new usage string
+ */
+ void SetCustomUsage(const TString& usage) {
+ CustomUsage = usage;
+ }
+
+ /**
+ * Add a section to print after the main usage spec.
+ */
+ void AddSection(TString title, TString text) {
+ Sections.emplace_back(std::move(title), std::move(text));
+ }
+
+ /**
+ * Add section with examples.
+ *
+ * @param examples text of this section
+ */
+ void SetExamples(TString examples) {
+ AddSection("Examples", std::move(examples));
+ }
+
+ /**
+ * Set minimal number of free args
+ *
+ * @param min new value
+ */
+ void SetFreeArgsMin(size_t min) {
+ FreeArgsMin_ = ui32(min);
+ }
+
+
+ /**
+ * Get current minimal number of free args
+ */
+ ui32 GetFreeArgsMin() const {
+ return FreeArgsMin_;
+ }
+
+ /**
+ * Set maximal number of free args
+ *
+ * @param max new value
+ */
+ void SetFreeArgsMax(size_t max) {
+ FreeArgsMax_ = ui32(max);
+ FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
+ }
+
+ /**
+ * Get current maximal number of free args
+ */
+ ui32 GetFreeArgsMax() const {
+ return FreeArgsMax_;
+ }
+
+ /**
+ * Get mapping for free args
+ */
+ const TMap<ui32, TFreeArgSpec>& GetFreeArgSpecs() const {
+ return FreeArgSpecs_;
+ }
+
+ /**
+ * Set exact expected number of free args
+ *
+ * @param count new value
+ */
+ void SetFreeArgsNum(size_t count) {
+ FreeArgsMin_ = ui32(count);
+ FreeArgsMax_ = ui32(count);
+ }
+
+ /**
+ * Set minimal and maximal number of free args
+ *
+ * @param min new value for minimal
+ * @param max new value for maximal
+ */
+ void SetFreeArgsNum(size_t min, size_t max) {
+ FreeArgsMin_ = ui32(min);
+ FreeArgsMax_ = ui32(max);
+ }
+
+ /**
+ * Set title and help string of free argument
+ *
+ * @param pos index of argument
+ * @param title new value for argument title
+ * @param help new value for help string
+ * @param optional indicates that the flag's help string should be rendered as for optional flag;
+ * does not affect actual flags parsing
+ */
+ void SetFreeArgTitle(size_t pos, const TString& title, const TString& help = TString(), bool optional = false);
+
+ /**
+ * Get free argument's spec for further modification.
+ */
+ TFreeArgSpec& GetFreeArgSpec(size_t pos);
+
+ /**
+ * Legacy, don't use. Same as `SetTrailingArgTitle`.
+ * Older versions of lastgetopt didn't have destinction between default title and title
+ * for the trailing argument.
+ */
+ void SetFreeArgDefaultTitle(const TString& title, const TString& help = TString()) {
+ SetTrailingArgTitle(title, help);
+ }
+
+ /**
+ * Set default title that will be used for all arguments that have no title.
+ */
+ void SetDefaultFreeArgTitle(TString title) {
+ DefaultFreeArgTitle_ = std::move(title);
+ }
+
+ /**
+ * Set default title that will be used for all arguments that have no title.
+ */
+ const TString& GetDefaultFreeArgTitle() const {
+ return DefaultFreeArgTitle_;
+ }
+
+ /**
+ * Set title and help for the trailing argument.
+ *
+ * This title and help are used to render the last repeated argument when max number of arguments is unlimited.
+ */
+ /// @{
+ void SetTrailingArgTitle(TString title) {
+ TrailingArgSpec_.Title(std::move(title));
+ }
+ void SetTrailingArgTitle(TString title, TString help) {
+ TrailingArgSpec_.Title(std::move(title));
+ TrailingArgSpec_.Help(std::move(help));
+ }
+ /// @}
+
+ /**
+ * Get spec for the trailing argument.
+ *
+ * This spec is used to render the last repeated argument when max number of arguments is unlimited.
+ */
+ /// @{
+ TFreeArgSpec& GetTrailingArgSpec() {
+ return TrailingArgSpec_;
+ }
+ const TFreeArgSpec& GetTrailingArgSpec() const {
+ return TrailingArgSpec_;
+ }
+ /// @}
+
+ /**
+ * Set the rule of parsing single dash as prefix of long names
+ *
+ * @param value new value of the option
+ */
+ void SetAllowSingleDashForLong(bool value) {
+ AllowSingleDashForLong_ = value;
+ }
+
+ /**
+ * Wrap help text at this number of characters. 0 to disable wrapping.
+ */
+ void SetWrap(ui32 wrap = 80) {
+ Wrap_ = wrap;
+ }
+
+ /**
+ * Print usage string
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintUsage(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
+
+ /**
+ * Print usage string
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ */
+ void PrintUsage(const TStringBuf& program, IOutputStream& os = Cout) const;
+
+ /**
+ * Get list of options in order of definition.
+ */
+ TVector<const TOpt*> GetOpts() const {
+ auto ret = TVector<const TOpt*>(Reserve(Opts_.size()));
+ for (auto& opt : Opts_) {
+ ret.push_back(opt.Get());
+ }
+ return ret;
+ }
+
+ private:
+ /**
+ * @return argument title of a free argument
+ *
+ * @param pos position of the argument
+ */
+ TStringBuf GetFreeArgTitle(size_t pos) const;
+
+ /**
+ * Print usage helper
+ *
+ * @param program prefix of result (path to the program)
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintCmdLine(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
+
+ /**
+ * Print usage helper
+ *
+ * @param os destination stream
+ * @param colors colorizer
+ */
+ void PrintFreeArgsDesc(IOutputStream& os, const NColorizer::TColors& colors) const;
+ };
+
+}