Serenity Operating System
1/*
2 * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
3 * Copyright (c) 2023, Ali Mohammad Pur <mpfard@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <AK/Format.h>
11#include <AK/StringView.h>
12#include <AK/Vector.h>
13
14namespace AK {
15
16class OptionParser {
17public:
18 enum class ArgumentRequirement {
19 NoArgument,
20 HasOptionalArgument,
21 HasRequiredArgument,
22 };
23 // Note: This is weird, but this class is used as a backend for getopt, so we're mirroring getopt here.
24 struct Option {
25 StringView name;
26 ArgumentRequirement requirement;
27 int* flag;
28 int val;
29 };
30
31 struct GetOptResult {
32 int result; // Whatever getopt is supposed to return.
33 Optional<int> optopt_value; // The new contents of `optopt' after this call
34 Optional<StringView> optarg_value; // The new contents of `optarg' after this call
35 size_t consumed_args;
36 };
37
38 GetOptResult getopt(Span<StringView> args, StringView short_options, Span<Option const> long_options, Optional<int&> out_long_option_index);
39 void reset_state();
40
41private:
42 Optional<ArgumentRequirement> lookup_short_option_requirement(char option) const;
43 int handle_short_option();
44
45 Optional<Option const&> lookup_long_option(StringView raw) const;
46 int handle_long_option();
47
48 void shift_argv();
49 bool find_next_option();
50
51 StringView current_arg() const
52 {
53 if (m_arg_index >= m_args.size())
54 return {};
55
56 return m_args[m_arg_index];
57 }
58
59 template<typename... Args>
60 static void reportln(CheckedFormatString<Args...> format_string, Args&&... args)
61 {
62 warnln(format_string.view(), forward<Args>(args)...);
63 }
64
65 // NOTE: These are ephemeral, and effectively only last for one call of `getopt()'.
66 Span<StringView> m_args {};
67 StringView m_short_options {};
68 Span<Option const> m_long_options {};
69 mutable Optional<int&> m_out_long_option_index {};
70 mutable Optional<int> m_optopt_value {};
71 mutable Optional<StringView> m_optarg_value {};
72
73 size_t m_arg_index { 0 };
74 size_t m_skipped_arguments { 0 };
75 size_t m_consumed_args { 0 };
76 size_t m_index_into_multioption_argument { 0 };
77 bool m_stop_on_first_non_option { false };
78};
79
80}
81
82#if USING_AK_GLOBALLY
83using AK::OptionParser;
84#endif