last_getopt_opts.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #pragma once
  2. #include "last_getopt_opt.h"
  3. #include <library/cpp/colorizer/fwd.h>
  4. #include <util/generic/map.h>
  5. namespace NLastGetopt {
  6. enum EArgPermutation {
  7. REQUIRE_ORDER,
  8. PERMUTE,
  9. RETURN_IN_ORDER,
  10. DEFAULT_ARG_PERMUTATION = PERMUTE
  11. };
  12. /**
  13. * NLastGetopt::TOpts is a storage of program options' parse rules.
  14. * It contains information about all options, free args, some parsing options
  15. * and rules about interaction between options.
  16. *
  17. * The main point for defining program options.
  18. *
  19. * The parsing rules determined by the following parts:
  20. * - Arguments permutation. It is expected free args be after named args.
  21. * This point adjusts how to treat breaking this expectation.
  22. * if REQUIRE_ORDER is choosen, the exception during parsing will be raised,
  23. * the special string " -- " will be treated as end of named
  24. * options: all options after it will be parsed as free args
  25. * if PERMUTE is choosen, arguments will be rearranged in correct order,
  26. * if RETURN_IN_ORDER is choosen, all free args will be ommited (TODO: looks very strange)
  27. * - Using '+' as a prefix instead '--' for long names
  28. * - Using "-" as a prefix for both short and long names
  29. * - Allowing unknown options
  30. *
  31. */
  32. class TOpts {
  33. friend class TOptsParseResult;
  34. friend class TOptsParser;
  35. public:
  36. static constexpr const ui32 UNLIMITED_ARGS = Max<ui32>();
  37. typedef TVector<TSimpleSharedPtr<TOpt>> TOptsVector;
  38. TOptsVector Opts_; // infomation about named (short and long) options
  39. TVector<std::function<void(TStringBuf)>> ArgBindings_;
  40. EArgPermutation ArgPermutation_ = DEFAULT_ARG_PERMUTATION; // determines how to parse positions of named and free options. See information below.
  41. bool AllowSingleDashForLong_ = false; //
  42. bool AllowPlusForLong_ = false; // using '+' instead '--' for long options
  43. //Allows unknwon options:
  44. bool AllowUnknownCharOptions_ = false;
  45. bool AllowUnknownLongOptions_ = false;
  46. ui32 Wrap_ = 80;
  47. private:
  48. ui32 FreeArgsMin_; // minimal number of free args
  49. ui32 FreeArgsMax_; // maximal number of free args
  50. TMap<ui32, TFreeArgSpec> FreeArgSpecs_; // mapping [free arg position] -> [free arg specification]
  51. TFreeArgSpec TrailingArgSpec_; // spec for the trailing argument (when arguments are unlimited)
  52. TString DefaultFreeArgTitle_ = "ARG"; // title that's used for free args without a title
  53. TString Title; // title of the help string
  54. TString CustomCmdLineDescr; // user defined help string
  55. TString CustomUsage; // user defined usage string
  56. TVector<std::pair<TString, TString>> Sections; // additional help entries to print after usage
  57. public:
  58. /**
  59. * Constructs TOpts from string as in getopt(3)
  60. */
  61. TOpts(const TStringBuf& optstring = TStringBuf());
  62. /**
  63. * Constructs TOpts from string as in getopt(3) and
  64. * additionally adds help option (for '?') and svn-verstion option (for 'V')
  65. */
  66. static TOpts Default(const TStringBuf& optstring = TStringBuf()) {
  67. TOpts opts(optstring);
  68. opts.AddHelpOption();
  69. opts.AddVersionOption();
  70. return opts;
  71. }
  72. /**
  73. * Checks correctness of options' descriptions.
  74. * Throws TConfException if validation failed.
  75. * Check consist of:
  76. * -not intersecting of names
  77. * -compability of settings, that responsable for freeArgs parsing
  78. */
  79. void Validate() const;
  80. /**
  81. * Search for the option with given long name
  82. * @param name long name for search
  83. * @return ptr on result (nullptr if not found)
  84. */
  85. const TOpt* FindLongOption(const TStringBuf& name) const;
  86. /**
  87. * Search for the option with given short name
  88. * @param c short name for search
  89. * @return ptr on result (nullptr if not found)
  90. */
  91. const TOpt* FindCharOption(char c) const;
  92. /**
  93. * Search for the option with given long name
  94. * @param name long name for search
  95. * @return ptr on result (nullptr if not found)
  96. */
  97. TOpt* FindLongOption(const TStringBuf& name);
  98. /**
  99. * Search for the option with given short name
  100. * @param c short name for search
  101. * @return ptr on result (nullptr if not found)
  102. */
  103. TOpt* FindCharOption(char c);
  104. /**
  105. * Search for the option with given name
  106. * @param name name for search
  107. * @return ptr on result (nullptr if not found)
  108. */
  109. /// @{
  110. const TOpt* FindOption(const TStringBuf& name) const {
  111. return FindLongOption(name);
  112. }
  113. TOpt* FindOption(const TStringBuf& name) {
  114. return FindLongOption(name);
  115. }
  116. const TOpt* FindOption(char c) const {
  117. return FindCharOption(c);
  118. }
  119. TOpt* FindOption(char c) {
  120. return FindCharOption(c);
  121. }
  122. /// @}
  123. /**
  124. * Sets title of the help string
  125. * @param title title to set
  126. */
  127. void SetTitle(const TString& title) {
  128. Title = title;
  129. }
  130. /**
  131. * @return true if there is an option with given long name
  132. *
  133. * @param name long name for search
  134. */
  135. bool HasLongOption(const TString& name) const {
  136. return FindLongOption(name) != nullptr;
  137. }
  138. /**
  139. * @return true if there is an option with given short name
  140. *
  141. * @param char short name for search
  142. */
  143. bool HasCharOption(char c) const {
  144. return FindCharOption(c) != nullptr;
  145. }
  146. /**
  147. * Search for the option with given long name
  148. * @param name long name for search
  149. * @return ref on result (throw exception if not found)
  150. */
  151. const TOpt& GetLongOption(const TStringBuf& name) const;
  152. /**
  153. * Search for the option with given long name
  154. * @param name long name for search
  155. * @return ref on result (throw exception if not found)
  156. */
  157. TOpt& GetLongOption(const TStringBuf& name);
  158. /**
  159. * Search for the option with given short name
  160. * @param c short name for search
  161. * @return ref on result (throw exception if not found)
  162. */
  163. const TOpt& GetCharOption(char c) const;
  164. /**
  165. * Search for the option with given short name
  166. * @param c short name for search
  167. * @return ref on result (throw exception if not found)
  168. */
  169. TOpt& GetCharOption(char c);
  170. /**
  171. * Search for the option with given name
  172. * @param name name for search
  173. * @return ref on result (throw exception if not found)
  174. */
  175. /// @{
  176. const TOpt& GetOption(const TStringBuf& name) const {
  177. return GetLongOption(name);
  178. }
  179. TOpt& GetOption(const TStringBuf& name) {
  180. return GetLongOption(name);
  181. }
  182. const TOpt& GetOption(char c) const {
  183. return GetCharOption(c);
  184. }
  185. TOpt& GetOption(char c) {
  186. return GetCharOption(c);
  187. }
  188. /// @}
  189. /**
  190. * @return true if short options exist
  191. */
  192. bool HasAnyShortOption() const;
  193. /**
  194. * @return true if long options exist
  195. */
  196. bool HasAnyLongOption() const;
  197. /**
  198. * Creates new [option description (TOpt)] as a copy of given one
  199. * @param option source
  200. * @return reference for created option
  201. */
  202. TOpt& AddOption(const TOpt& option);
  203. /**
  204. * Creates new free argument handling
  205. * @param name name of free arg to show in help
  206. * @param target variable address to store parsing result into
  207. * @param help help string to show in help
  208. */
  209. template <typename T>
  210. void AddFreeArgBinding(const TString& name, T& target, const TString& help = "") {
  211. ArgBindings_.emplace_back([&target](TStringBuf value) {
  212. target = FromString<T>(value);
  213. });
  214. FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
  215. SetFreeArgTitle(ArgBindings_.size() - 1, name, help);
  216. }
  217. /**
  218. * Creates options list from string as in getopt(3)
  219. *
  220. * @param optstring source
  221. */
  222. void AddCharOptions(const TStringBuf& optstring);
  223. /**
  224. * Creates new [option description (TOpt)] with given short name and given help string
  225. *
  226. * @param c short name
  227. * @param help help string
  228. * @return reference for created option
  229. */
  230. TOpt& AddCharOption(char c, const TString& help = "") {
  231. return AddCharOption(c, DEFAULT_HAS_ARG, help);
  232. }
  233. /**
  234. * Creates new [option description (TOpt)] with given short name and given help string
  235. *
  236. * @param c short name
  237. * @param help help string
  238. * @return reference for created option
  239. */
  240. TOpt& AddCharOption(char c, EHasArg hasArg, const TString& help = "") {
  241. TOpt option;
  242. option.AddShortName(c);
  243. option.Help(help);
  244. option.HasArg(hasArg);
  245. return AddOption(option);
  246. }
  247. /**
  248. * Creates new [option description (TOpt)] with given long name and given help string
  249. *
  250. * @param name long name
  251. * @param help help string
  252. * @return reference for created option
  253. */
  254. TOpt& AddLongOption(const TString& name, const TString& help = "") {
  255. return AddLongOption(0, name, help);
  256. }
  257. /**
  258. * Creates new [option description (TOpt)] with given long and short names and given help string
  259. *
  260. * @param c short name
  261. * @param name long name
  262. * @param help help string
  263. * @return reference for created option
  264. */
  265. TOpt& AddLongOption(char c, const TString& name, const TString& help = "") {
  266. TOpt option;
  267. if (c != 0)
  268. option.AddShortName(c);
  269. option.AddLongName(name);
  270. option.Help(help);
  271. return AddOption(option);
  272. }
  273. /**
  274. * Creates new [option description (TOpt)] for help printing,
  275. * adds appropriate handler for it
  276. * If "help" option already exist, will add given short name to it.
  277. *
  278. * @param c new short name for help option
  279. */
  280. TOpt& AddHelpOption(char c = '?') {
  281. if (TOpt* o = FindLongOption("help")) {
  282. if (!o->CharIs(c))
  283. o->AddShortName(c);
  284. return *o;
  285. }
  286. return AddLongOption(c, "help", "print usage")
  287. .HasArg(NO_ARGUMENT)
  288. .IfPresentDisableCompletion()
  289. .Handler(&PrintUsageAndExit);
  290. }
  291. /**
  292. * Creates new [option description (TOpt)] for svn-revision printing,
  293. * adds appropriate handler for it.
  294. * If "svnversion" option already exist, will add given short name to it.
  295. *
  296. * @param c new short name for "svnversion" option
  297. */
  298. TOpt& AddVersionOption(char c = 'V') {
  299. if (TOpt* o = FindLongOption("svnrevision")) {
  300. if (!o->CharIs(c))
  301. o->AddShortName(c);
  302. return *o;
  303. }
  304. return AddLongOption(c, "svnrevision", "print svn version")
  305. .HasArg(NO_ARGUMENT)
  306. .IfPresentDisableCompletion()
  307. .Handler(&PrintVersionAndExit);
  308. }
  309. /**
  310. * Creates new option for generating completion shell scripts.
  311. *
  312. * @param command name of command that should be completed (typically corresponds to the executable name).
  313. */
  314. TOpt& AddCompletionOption(TString command, TString longName = "completion");
  315. /**
  316. * Creates or finds option with given short name
  317. *
  318. * @param c new short name for search/create
  319. */
  320. TOpt& CharOption(char c) {
  321. const TOpt* opt = FindCharOption(c);
  322. if (opt != nullptr) {
  323. return const_cast<TOpt&>(*opt);
  324. } else {
  325. AddCharOption(c);
  326. return const_cast<TOpt&>(GetCharOption(c));
  327. }
  328. }
  329. /**
  330. * Indicate that some options can't appear together.
  331. *
  332. * Note: this is not transitive.
  333. *
  334. * Note: don't use this on options with default values. If option with default value wasn't specified,
  335. * parser will run handlers for default value, thus triggering a false-positive exclusivity check.
  336. */
  337. template <typename T1, typename T2>
  338. void MutuallyExclusive(T1&& opt1, T2&& opt2) {
  339. MutuallyExclusiveOpt(GetOption(std::forward<T1>(opt1)), GetOption(std::forward<T2>(opt2)));
  340. }
  341. /**
  342. * Like `MutuallyExclusive`, but accepts `TOpt`s instead of option names.
  343. */
  344. void MutuallyExclusiveOpt(TOpt& opt1, TOpt& opt2);
  345. /**
  346. * @return index of option
  347. *
  348. * @param opt pointer of option to search
  349. */
  350. size_t IndexOf(const TOpt* opt) const;
  351. /**
  352. * Replace help string with given
  353. *
  354. * @param decr new help string
  355. */
  356. void SetCmdLineDescr(const TString& descr) {
  357. CustomCmdLineDescr = descr;
  358. }
  359. /**
  360. * Replace usage string with given
  361. *
  362. * @param usage new usage string
  363. */
  364. void SetCustomUsage(const TString& usage) {
  365. CustomUsage = usage;
  366. }
  367. /**
  368. * Add a section to print after the main usage spec.
  369. */
  370. void AddSection(TString title, TString text) {
  371. Sections.emplace_back(std::move(title), std::move(text));
  372. }
  373. /**
  374. * Add section with examples.
  375. *
  376. * @param examples text of this section
  377. */
  378. void SetExamples(TString examples) {
  379. AddSection("Examples", std::move(examples));
  380. }
  381. /**
  382. * Set minimal number of free args
  383. *
  384. * @param min new value
  385. */
  386. void SetFreeArgsMin(size_t min) {
  387. FreeArgsMin_ = ui32(min);
  388. }
  389. /**
  390. * Get current minimal number of free args
  391. */
  392. ui32 GetFreeArgsMin() const {
  393. return FreeArgsMin_;
  394. }
  395. /**
  396. * Set maximal number of free args
  397. *
  398. * @param max new value
  399. */
  400. void SetFreeArgsMax(size_t max) {
  401. FreeArgsMax_ = ui32(max);
  402. FreeArgsMax_ = Max<ui32>(FreeArgsMax_, ArgBindings_.size());
  403. }
  404. /**
  405. * Get current maximal number of free args
  406. */
  407. ui32 GetFreeArgsMax() const {
  408. return FreeArgsMax_;
  409. }
  410. /**
  411. * Get mapping for free args
  412. */
  413. const TMap<ui32, TFreeArgSpec>& GetFreeArgSpecs() const {
  414. return FreeArgSpecs_;
  415. }
  416. /**
  417. * Set exact expected number of free args
  418. *
  419. * @param count new value
  420. */
  421. void SetFreeArgsNum(size_t count) {
  422. FreeArgsMin_ = ui32(count);
  423. FreeArgsMax_ = ui32(count);
  424. }
  425. /**
  426. * Set minimal and maximal number of free args
  427. *
  428. * @param min new value for minimal
  429. * @param max new value for maximal
  430. */
  431. void SetFreeArgsNum(size_t min, size_t max) {
  432. FreeArgsMin_ = ui32(min);
  433. FreeArgsMax_ = ui32(max);
  434. }
  435. /**
  436. * Set title and help string of free argument
  437. *
  438. * @param pos index of argument
  439. * @param title new value for argument title
  440. * @param help new value for help string
  441. * @param optional indicates that the flag's help string should be rendered as for optional flag;
  442. * does not affect actual flags parsing
  443. */
  444. void SetFreeArgTitle(size_t pos, const TString& title, const TString& help = TString(), bool optional = false);
  445. /**
  446. * Get free argument's spec for further modification.
  447. */
  448. TFreeArgSpec& GetFreeArgSpec(size_t pos);
  449. /**
  450. * Legacy, don't use. Same as `SetTrailingArgTitle`.
  451. * Older versions of lastgetopt didn't have destinction between default title and title
  452. * for the trailing argument.
  453. */
  454. void SetFreeArgDefaultTitle(const TString& title, const TString& help = TString()) {
  455. SetTrailingArgTitle(title, help);
  456. }
  457. /**
  458. * Set default title that will be used for all arguments that have no title.
  459. */
  460. void SetDefaultFreeArgTitle(TString title) {
  461. DefaultFreeArgTitle_ = std::move(title);
  462. }
  463. /**
  464. * Set default title that will be used for all arguments that have no title.
  465. */
  466. const TString& GetDefaultFreeArgTitle() const {
  467. return DefaultFreeArgTitle_;
  468. }
  469. /**
  470. * Set title and help for the trailing argument.
  471. *
  472. * This title and help are used to render the last repeated argument when max number of arguments is unlimited.
  473. */
  474. /// @{
  475. void SetTrailingArgTitle(TString title) {
  476. TrailingArgSpec_.Title(std::move(title));
  477. }
  478. void SetTrailingArgTitle(TString title, TString help) {
  479. TrailingArgSpec_.Title(std::move(title));
  480. TrailingArgSpec_.Help(std::move(help));
  481. }
  482. /// @}
  483. /**
  484. * Get spec for the trailing argument.
  485. *
  486. * This spec is used to render the last repeated argument when max number of arguments is unlimited.
  487. */
  488. /// @{
  489. TFreeArgSpec& GetTrailingArgSpec() {
  490. return TrailingArgSpec_;
  491. }
  492. const TFreeArgSpec& GetTrailingArgSpec() const {
  493. return TrailingArgSpec_;
  494. }
  495. /// @}
  496. /**
  497. * Set the rule of parsing single dash as prefix of long names
  498. *
  499. * @param value new value of the option
  500. */
  501. void SetAllowSingleDashForLong(bool value) {
  502. AllowSingleDashForLong_ = value;
  503. }
  504. /**
  505. * Wrap help text at this number of characters. 0 to disable wrapping.
  506. */
  507. void SetWrap(ui32 wrap = 80) {
  508. Wrap_ = wrap;
  509. }
  510. /**
  511. * Print usage string
  512. *
  513. * @param program prefix of result (path to the program)
  514. * @param os destination stream
  515. * @param colors colorizer
  516. */
  517. void PrintUsage(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
  518. /**
  519. * Print usage string
  520. *
  521. * @param program prefix of result (path to the program)
  522. * @param os destination stream
  523. */
  524. void PrintUsage(const TStringBuf& program, IOutputStream& os = Cout) const;
  525. /**
  526. * Get list of options in order of definition.
  527. */
  528. TVector<const TOpt*> GetOpts() const {
  529. auto ret = TVector<const TOpt*>(Reserve(Opts_.size()));
  530. for (auto& opt : Opts_) {
  531. ret.push_back(opt.Get());
  532. }
  533. return ret;
  534. }
  535. private:
  536. /**
  537. * @return argument title of a free argument
  538. *
  539. * @param pos position of the argument
  540. */
  541. TStringBuf GetFreeArgTitle(size_t pos) const;
  542. /**
  543. * Print usage helper
  544. *
  545. * @param program prefix of result (path to the program)
  546. * @param os destination stream
  547. * @param colors colorizer
  548. */
  549. void PrintCmdLine(const TStringBuf& program, IOutputStream& os, const NColorizer::TColors& colors) const;
  550. /**
  551. * Print usage helper
  552. *
  553. * @param os destination stream
  554. * @param colors colorizer
  555. */
  556. void PrintFreeArgsDesc(IOutputStream& os, const NColorizer::TColors& colors) const;
  557. };
  558. }