ArgsParser.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Concepts.h>
  8. #include <AK/DeprecatedString.h>
  9. #include <AK/Function.h>
  10. #include <AK/Vector.h>
  11. #include <LibMain/Main.h>
  12. #include <stdio.h>
  13. namespace Core {
  14. class ArgsParser {
  15. public:
  16. ArgsParser();
  17. enum class Required {
  18. Yes,
  19. No
  20. };
  21. enum class FailureBehavior {
  22. PrintUsageAndExit,
  23. PrintUsage,
  24. Exit,
  25. Ignore,
  26. };
  27. enum class OptionArgumentMode {
  28. None,
  29. Optional,
  30. Required,
  31. };
  32. /// When an option is hidden.
  33. /// If the hide mode is not None, then it's always hidden from the usage/synopsis.
  34. enum class OptionHideMode {
  35. None,
  36. Markdown,
  37. CommandLineAndMarkdown,
  38. };
  39. struct Option {
  40. OptionArgumentMode argument_mode { OptionArgumentMode::Required };
  41. char const* help_string { nullptr };
  42. char const* long_name { nullptr };
  43. char short_name { 0 };
  44. char const* value_name { nullptr };
  45. Function<ErrorOr<bool>(StringView)> accept_value;
  46. OptionHideMode hide_mode { OptionHideMode::None };
  47. DeprecatedString name_for_display() const
  48. {
  49. if (long_name)
  50. return DeprecatedString::formatted("--{}", long_name);
  51. return DeprecatedString::formatted("-{:c}", short_name);
  52. }
  53. };
  54. struct Arg {
  55. char const* help_string { nullptr };
  56. char const* name { nullptr };
  57. int min_values { 0 };
  58. int max_values { 1 };
  59. Function<ErrorOr<bool>(StringView)> accept_value;
  60. };
  61. bool parse(Span<StringView> arguments, FailureBehavior failure_behavior = FailureBehavior::PrintUsageAndExit);
  62. bool parse(Main::Arguments const& arguments, FailureBehavior failure_behavior = FailureBehavior::PrintUsageAndExit)
  63. {
  64. return parse(arguments.strings, failure_behavior);
  65. }
  66. // *Without* trailing newline!
  67. void set_general_help(char const* help_string) { m_general_help = help_string; }
  68. void set_stop_on_first_non_option(bool stop_on_first_non_option) { m_stop_on_first_non_option = stop_on_first_non_option; }
  69. void print_usage(FILE*, StringView argv0);
  70. void print_usage_terminal(FILE*, StringView argv0);
  71. void print_usage_markdown(FILE*, StringView argv0);
  72. void print_version(FILE*);
  73. void add_option(Option&&);
  74. void add_ignored(char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None);
  75. void add_option(bool& value, char const* help_string, char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None);
  76. /// If the option is present, set the enum to have the given `new_value`.
  77. template<Enum T>
  78. void add_option(T& value, T new_value, char const* help_string, char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None)
  79. {
  80. add_option({ .argument_mode = Core::ArgsParser::OptionArgumentMode::None,
  81. .help_string = help_string,
  82. .long_name = long_name,
  83. .short_name = short_name,
  84. .accept_value = [&](StringView) {
  85. value = new_value;
  86. return true;
  87. },
  88. .hide_mode = hide_mode });
  89. }
  90. void add_option(DeprecatedString& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  91. void add_option(String& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  92. void add_option(StringView& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  93. template<Integral I>
  94. void add_option(I& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  95. void add_option(double& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  96. void add_option(Optional<double>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  97. void add_option(Optional<size_t>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  98. void add_option(Vector<size_t>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, char separator = ',', OptionHideMode hide_mode = OptionHideMode::None);
  99. // Note: This option is being used when we expect the user to use the same option
  100. // multiple times (e.g. "program --option=example --option=anotherexample ...").
  101. void add_option(Vector<DeprecatedString>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None);
  102. void add_positional_argument(Arg&&);
  103. void add_positional_argument(DeprecatedString& value, char const* help_string, char const* name, Required required = Required::Yes);
  104. void add_positional_argument(StringView& value, char const* help_string, char const* name, Required required = Required::Yes);
  105. void add_positional_argument(String& value, char const* help_string, char const* name, Required required = Required::Yes);
  106. template<Integral I>
  107. void add_positional_argument(I& value, char const* help_string, char const* name, Required required = Required::Yes);
  108. void add_positional_argument(double& value, char const* help_string, char const* name, Required required = Required::Yes);
  109. void add_positional_argument(Vector<DeprecatedString>& value, char const* help_string, char const* name, Required required = Required::Yes);
  110. void add_positional_argument(Vector<StringView>& value, char const* help_string, char const* name, Required required = Required::Yes);
  111. private:
  112. void autocomplete(FILE*, StringView program_name, ReadonlySpan<StringView> remaining_arguments);
  113. Vector<Option> m_options;
  114. Vector<Arg> m_positional_args;
  115. bool m_show_help { false };
  116. bool m_show_version { false };
  117. bool m_perform_autocomplete { false };
  118. char const* m_general_help { nullptr };
  119. bool m_stop_on_first_non_option { false };
  120. };
  121. }