diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/getopt/small/last_getopt_opts.h | |
download | ydb-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.h | 643 |
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; + }; + +} |