| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |  * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  | #include <AK/ByteString.h>
 | 
					
						
							| 
									
										
										
										
											2022-11-14 18:20:59 +00:00
										 |  |  | #include <AK/Concepts.h>
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  | #include <AK/Function.h>
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | #include <AK/Vector.h>
 | 
					
						
							| 
									
										
										
										
											2021-11-22 19:01:31 -05:00
										 |  |  | #include <LibMain/Main.h>
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | namespace Core { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ArgsParser { | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     ArgsParser(); | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     enum class Required { | 
					
						
							|  |  |  |         Yes, | 
					
						
							|  |  |  |         No | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 01:11:56 +02:00
										 |  |  |     enum class FailureBehavior { | 
					
						
							|  |  |  |         PrintUsageAndExit, | 
					
						
							|  |  |  |         PrintUsage, | 
					
						
							|  |  |  |         Exit, | 
					
						
							|  |  |  |         Ignore, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-12 22:13:38 +02:00
										 |  |  |     enum class OptionArgumentMode { | 
					
						
							|  |  |  |         None, | 
					
						
							| 
									
										
										
										
											2022-07-12 23:05:06 +02:00
										 |  |  |         Optional, | 
					
						
							| 
									
										
										
										
											2022-07-12 22:13:38 +02:00
										 |  |  |         Required, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-03 22:33:09 +00:00
										 |  |  |     /// When an option is hidden.
 | 
					
						
							|  |  |  |     /// If the hide mode is not None, then it's always hidden from the usage/synopsis.
 | 
					
						
							|  |  |  |     enum class OptionHideMode { | 
					
						
							|  |  |  |         None, | 
					
						
							|  |  |  |         Markdown, | 
					
						
							|  |  |  |         CommandLineAndMarkdown, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     struct Option { | 
					
						
							| 
									
										
										
										
											2022-07-12 22:13:38 +02:00
										 |  |  |         OptionArgumentMode argument_mode { OptionArgumentMode::Required }; | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  |         char const* help_string { nullptr }; | 
					
						
							|  |  |  |         char const* long_name { nullptr }; | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |         char short_name { 0 }; | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  |         char const* value_name { nullptr }; | 
					
						
							| 
									
										
										
										
											2023-07-01 16:01:30 +01:00
										 |  |  |         Function<ErrorOr<bool>(StringView)> accept_value; | 
					
						
							| 
									
										
										
										
											2022-04-03 22:33:09 +00:00
										 |  |  |         OptionHideMode hide_mode { OptionHideMode::None }; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |         ByteString name_for_display() const | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |         { | 
					
						
							|  |  |  |             if (long_name) | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |                 return ByteString::formatted("--{}", long_name); | 
					
						
							|  |  |  |             return ByteString::formatted("-{:c}", short_name); | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     struct Arg { | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  |         char const* help_string { nullptr }; | 
					
						
							|  |  |  |         char const* name { nullptr }; | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |         int min_values { 0 }; | 
					
						
							|  |  |  |         int max_values { 1 }; | 
					
						
							| 
									
										
										
										
											2023-07-01 16:08:46 +01:00
										 |  |  |         Function<ErrorOr<bool>(StringView)> accept_value; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-21 15:14:41 +03:30
										 |  |  |     bool parse(Span<StringView> arguments, FailureBehavior failure_behavior = FailureBehavior::PrintUsageAndExit); | 
					
						
							| 
									
										
										
										
											2021-11-22 19:01:31 -05:00
										 |  |  |     bool parse(Main::Arguments const& arguments, FailureBehavior failure_behavior = FailureBehavior::PrintUsageAndExit) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-02-21 15:14:41 +03:30
										 |  |  |         return parse(arguments.strings, failure_behavior); | 
					
						
							| 
									
										
										
										
											2021-11-22 19:01:31 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-05 15:54:27 +01:00
										 |  |  |     // *Without* trailing newline!
 | 
					
						
							| 
									
										
										
										
											2023-07-07 22:48:11 -04:00
										 |  |  |     void set_general_help(char const* help_string) { m_general_help = help_string; } | 
					
						
							| 
									
										
										
										
											2021-06-07 21:20:35 +02:00
										 |  |  |     void set_stop_on_first_non_option(bool stop_on_first_non_option) { m_stop_on_first_non_option = stop_on_first_non_option; } | 
					
						
							| 
									
										
										
										
											2023-02-21 15:14:41 +03:30
										 |  |  |     void print_usage(FILE*, StringView argv0); | 
					
						
							|  |  |  |     void print_usage_terminal(FILE*, StringView argv0); | 
					
						
							|  |  |  |     void print_usage_markdown(FILE*, StringView argv0); | 
					
						
							| 
									
										
										
										
											2021-08-14 18:50:52 -04:00
										 |  |  |     void print_version(FILE*); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     void add_option(Option&&); | 
					
						
							| 
									
										
										
										
											2022-04-03 22:33:09 +00:00
										 |  |  |     void add_ignored(char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None); | 
					
						
							|  |  |  |     void add_option(bool& value, char const* help_string, char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None); | 
					
						
							| 
									
										
										
										
											2023-09-24 16:13:00 +01:00
										 |  |  |     /// If the option is present, set the enum to have the given `new_value`.
 | 
					
						
							|  |  |  |     template<Enum T> | 
					
						
							|  |  |  |     void add_option(T& value, T new_value, char const* help_string, char const* long_name, char short_name, OptionHideMode hide_mode = OptionHideMode::None) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         add_option({ .argument_mode = Core::ArgsParser::OptionArgumentMode::None, | 
					
						
							|  |  |  |             .help_string = help_string, | 
					
						
							|  |  |  |             .long_name = long_name, | 
					
						
							|  |  |  |             .short_name = short_name, | 
					
						
							|  |  |  |             .accept_value = [&](StringView) { | 
					
						
							|  |  |  |                 value = new_value; | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             .hide_mode = hide_mode }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-01-15 11:56:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<Integral I> | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Option option { | 
					
						
							|  |  |  |             OptionArgumentMode::Required, | 
					
						
							|  |  |  |             help_string, | 
					
						
							|  |  |  |             long_name, | 
					
						
							|  |  |  |             short_name, | 
					
						
							|  |  |  |             value_name, | 
					
						
							|  |  |  |             [&value](StringView view) -> ErrorOr<bool> { | 
					
						
							|  |  |  |                 Optional<I> opt = view.to_number<I>(); | 
					
						
							|  |  |  |                 value = opt.value_or(0); | 
					
						
							|  |  |  |                 return opt.has_value(); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             hide_mode, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         add_option(move(option)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<Integral I> | 
					
						
							|  |  |  |     void add_option(Optional<I>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Option option { | 
					
						
							|  |  |  |             OptionArgumentMode::Required, | 
					
						
							|  |  |  |             help_string, | 
					
						
							|  |  |  |             long_name, | 
					
						
							|  |  |  |             short_name, | 
					
						
							|  |  |  |             value_name, | 
					
						
							|  |  |  |             [&value](StringView view) -> ErrorOr<bool> { | 
					
						
							|  |  |  |                 value = view.to_number<I>(); | 
					
						
							|  |  |  |                 return value.has_value(); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             hide_mode, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         add_option(move(option)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<Integral I> | 
					
						
							|  |  |  |     void add_option(Vector<I>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, char separator = ',', OptionHideMode hide_mode = OptionHideMode::None) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Option option { | 
					
						
							|  |  |  |             OptionArgumentMode::Required, | 
					
						
							|  |  |  |             help_string, | 
					
						
							|  |  |  |             long_name, | 
					
						
							|  |  |  |             short_name, | 
					
						
							|  |  |  |             value_name, | 
					
						
							|  |  |  |             [&values, separator](StringView s) -> ErrorOr<bool> { | 
					
						
							|  |  |  |                 bool parsed_all_values = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 s.for_each_split_view(separator, SplitBehavior::Nothing, [&](auto value) { | 
					
						
							|  |  |  |                     if (auto maybe_value = value.template to_number<I>(); maybe_value.has_value()) | 
					
						
							|  |  |  |                         values.append(*maybe_value); | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                         parsed_all_values = false; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return parsed_all_values; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             hide_mode | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         add_option(move(option)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |     void add_option(ByteString& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None); | 
					
						
							| 
									
										
										
										
											2023-06-13 16:03:03 +01:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2022-04-03 22:33:09 +00:00
										 |  |  |     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); | 
					
						
							| 
									
										
										
										
											2024-03-02 22:21:17 +13:00
										 |  |  |     void add_option(Optional<StringView>& value, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None); | 
					
						
							| 
									
										
										
										
											2022-04-03 22:33:09 +00:00
										 |  |  |     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); | 
					
						
							|  |  |  |     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); | 
					
						
							| 
									
										
										
										
											2022-11-04 20:47:36 +02:00
										 |  |  |     // Note: This option is being used when we expect the user to use the same option
 | 
					
						
							|  |  |  |     // multiple times (e.g. "program --option=example --option=anotherexample ...").
 | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |     void add_option(Vector<ByteString>& values, char const* help_string, char const* long_name, char short_name, char const* value_name, OptionHideMode hide_mode = OptionHideMode::None); | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     void add_positional_argument(Arg&&); | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |     void add_positional_argument(ByteString& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2021-06-01 09:01:31 +02:00
										 |  |  |     void add_positional_argument(StringView& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2023-06-13 16:03:03 +01:00
										 |  |  |     void add_positional_argument(String& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2023-04-27 12:58:52 +02:00
										 |  |  |     template<Integral I> | 
					
						
							| 
									
										
										
										
											2024-01-15 11:56:06 +01:00
										 |  |  |     void add_positional_argument(I& value, char const* help_string, char const* name, Required required = Required::Yes) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Arg arg { | 
					
						
							|  |  |  |             help_string, | 
					
						
							|  |  |  |             name, | 
					
						
							|  |  |  |             required == Required::Yes ? 1 : 0, | 
					
						
							|  |  |  |             1, | 
					
						
							|  |  |  |             [&value](StringView view) -> ErrorOr<bool> { | 
					
						
							|  |  |  |                 Optional<I> opt = view.to_number<I>(); | 
					
						
							|  |  |  |                 value = opt.value_or(0); | 
					
						
							|  |  |  |                 return opt.has_value(); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         add_positional_argument(move(arg)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  |     void add_positional_argument(double& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2023-12-16 17:49:34 +03:30
										 |  |  |     void add_positional_argument(Vector<ByteString>& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2021-11-26 22:09:09 +01:00
										 |  |  |     void add_positional_argument(Vector<StringView>& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2023-10-05 08:10:56 +05:30
										 |  |  |     void add_positional_argument(Vector<String>& value, char const* help_string, char const* name, Required required = Required::Yes); | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2023-02-21 15:14:41 +03:30
										 |  |  |     void autocomplete(FILE*, StringView program_name, ReadonlySpan<StringView> remaining_arguments); | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 20:19:39 +03:00
										 |  |  |     Vector<Option> m_options; | 
					
						
							|  |  |  |     Vector<Arg> m_positional_args; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool m_show_help { false }; | 
					
						
							| 
									
										
										
										
											2021-08-14 13:34:34 -04:00
										 |  |  |     bool m_show_version { false }; | 
					
						
							| 
									
										
										
										
											2022-03-23 13:16:43 +04:30
										 |  |  |     bool m_perform_autocomplete { false }; | 
					
						
							|  |  |  |     char const* m_general_help { nullptr }; | 
					
						
							| 
									
										
										
										
											2021-06-07 21:20:35 +02:00
										 |  |  |     bool m_stop_on_first_non_option { false }; | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |