last_getopt.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #pragma once
  2. #include "last_getopt_opts.h"
  3. #include "last_getopt_easy_setup.h"
  4. #include "last_getopt_parse_result.h"
  5. #include <util/generic/function.h>
  6. #include <util/string/split.h>
  7. /// see some documentation in
  8. /// https://wiki.yandex-team.ru/development/poisk/arcadia/util/lastgetopt/
  9. /// https://wiki.yandex-team.ru/development/poisk/arcadia/library/getopt/
  10. /// see examples in library/cpp/getopt/last_getopt_demo
  11. //TODO: in most cases this include is unnecessary, but needed THandlerFunctor1<TpFunc, TpArg>::HandleOpt
  12. #include "last_getopt_parser.h"
  13. namespace NLastGetopt {
  14. /// Handler to split option value by delimiter into a target container and allow ranges.
  15. template <class Container>
  16. struct TOptRangeSplitHandler: public IOptHandler {
  17. public:
  18. using TContainer = Container;
  19. using TValue = typename TContainer::value_type;
  20. explicit TOptRangeSplitHandler(TContainer* target, const char elementsDelim, const char rangesDelim)
  21. : Target(target)
  22. , ElementsDelim(elementsDelim)
  23. , RangesDelim(rangesDelim)
  24. {
  25. }
  26. void HandleOpt(const TOptsParser* parser) override {
  27. const TStringBuf curval(parser->CurValOrDef());
  28. if (curval.IsInited()) {
  29. StringSplitter(curval).Split(ElementsDelim).Consume([&](const TStringBuf& val) {
  30. TStringBuf mutableValue = val;
  31. TValue first = NPrivate::OptFromString<TValue>(mutableValue.NextTok(RangesDelim), parser->CurOpt());
  32. TValue last = mutableValue ? NPrivate::OptFromString<TValue>(mutableValue, parser->CurOpt()) : first;
  33. if (last < first) {
  34. throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(parser->CurOpt()) << " value " << TString(val).Quote() << ": the second argument is less than the first one";
  35. }
  36. for (++last; first < last; ++first) {
  37. Target->insert(Target->end(), first);
  38. }
  39. });
  40. }
  41. }
  42. private:
  43. TContainer* Target;
  44. char ElementsDelim;
  45. char RangesDelim;
  46. };
  47. template <class Container>
  48. struct TOptSplitHandler: public IOptHandler {
  49. public:
  50. using TContainer = Container;
  51. using TValue = typename TContainer::value_type;
  52. explicit TOptSplitHandler(TContainer* target, const char delim)
  53. : Target(target)
  54. , Delim(delim)
  55. {
  56. }
  57. void HandleOpt(const TOptsParser* parser) override {
  58. const TStringBuf curval(parser->CurValOrDef());
  59. if (curval.IsInited()) {
  60. StringSplitter(curval).Split(Delim).Consume([&](const TStringBuf& val) {
  61. Target->insert(Target->end(), NPrivate::OptFromString<TValue>(val, parser->CurOpt()));
  62. });
  63. }
  64. }
  65. private:
  66. TContainer* Target;
  67. char Delim;
  68. };
  69. template <class TpFunc>
  70. struct TOptKVHandler: public IOptHandler {
  71. public:
  72. using TKey = typename TFunctionArgs<TpFunc>::template TGet<0>;
  73. using TValue = typename TFunctionArgs<TpFunc>::template TGet<1>;
  74. explicit TOptKVHandler(TpFunc func, const char kvdelim = '=')
  75. : Func(func)
  76. , KVDelim(kvdelim)
  77. {
  78. }
  79. void HandleOpt(const TOptsParser* parser) override {
  80. const TStringBuf curval(parser->CurValOrDef());
  81. const TOpt* curOpt(parser->CurOpt());
  82. if (curval.IsInited()) {
  83. TStringBuf key, value;
  84. if (!curval.TrySplit(KVDelim, key, value)) {
  85. throw TUsageException() << "failed to parse opt " << NPrivate::OptToString(curOpt)
  86. << " value " << TString(curval).Quote() << ": expected key" << KVDelim << "value format";
  87. }
  88. Func(NPrivate::OptFromString<TKey>(key, curOpt), NPrivate::OptFromString<TValue>(value, curOpt));
  89. }
  90. }
  91. private:
  92. TpFunc Func;
  93. char KVDelim;
  94. };
  95. namespace NPrivate {
  96. template <typename TpFunc, typename TpArg>
  97. void THandlerFunctor1<TpFunc, TpArg>::HandleOpt(const TOptsParser* parser) {
  98. const TStringBuf curval = parser->CurValOrDef(!HasDef_);
  99. const TpArg& arg = curval.IsInited() ? OptFromString<TpArg>(curval, parser->CurOpt()) : Def_;
  100. try {
  101. Func_(arg);
  102. } catch (const TUsageException&) {
  103. throw;
  104. } catch (...) {
  105. throw TUsageException() << "failed to handle opt " << OptToString(parser->CurOpt())
  106. << " value " << TString(curval).Quote() << ": " << CurrentExceptionMessage();
  107. }
  108. }
  109. }
  110. }