last_getopt_opts.h 21 KB

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