1 //===-- Implementation of getopt ------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "src/unistd/getopt.h"
10 #include "src/__support/CPP/optional.h"
11 #include "src/__support/CPP/string_view.h"
12 #include "src/__support/File/file.h"
13 #include "src/__support/common.h"
14 #include "src/stdio/fprintf.h"
18 // This is POSIX compliant and does not support GNU extensions, mainly this is
19 // just the re-ordering of argv elements such that unknown arguments can be
20 // easily iterated over.
22 namespace LIBC_NAMESPACE
{
24 template <typename T
> struct RefWrapper
{
25 RefWrapper() = delete;
26 constexpr RefWrapper(T
*p
) : ptr
{p
} {}
27 constexpr RefWrapper(const RefWrapper
&) = default;
28 RefWrapper
&operator=(const RefWrapper
&) = default;
29 operator T
&() { return *ptr
; }
30 T
&get() { return *ptr
; }
34 struct GetoptContext
{
35 RefWrapper
<char *> optarg
;
36 RefWrapper
<int> optind
;
37 RefWrapper
<int> optopt
;
38 RefWrapper
<unsigned> optpos
;
40 RefWrapper
<int> opterr
;
44 GetoptContext
&operator=(const GetoptContext
&) = default;
46 template <typename
... Ts
> void report_error(const char *fmt
, Ts
... ts
) {
48 LIBC_NAMESPACE::fprintf(
50 : reinterpret_cast<FILE *>(LIBC_NAMESPACE::stderr
),
55 struct OptstringParser
{
56 using value_type
= struct {
61 cpp::string_view optstring
;
64 cpp::string_view curr
;
66 iterator
operator++() {
67 curr
= curr
.substr(1);
71 bool operator!=(iterator other
) { return curr
.data() != other
.curr
.data(); }
73 value_type
operator*() {
74 value_type r
{curr
.front(), false};
75 if (!curr
.substr(1).empty() && curr
.substr(1).front() == ':') {
84 bool skip
= optstring
.front() == '-' || optstring
.front() == '+' ||
85 optstring
.front() == ':';
86 return {optstring
.substr(!!skip
)};
89 iterator
end() { return {optstring
.substr(optstring
.size())}; }
92 int getopt_r(int argc
, char *const argv
[], const char *optstring
,
94 auto failure
= [&ctx
](int ret
= -1) {
99 if (ctx
.optind
>= argc
|| !argv
[ctx
.optind
])
102 cpp::string_view current
=
103 cpp::string_view
{argv
[ctx
.optind
]}.substr(ctx
.optpos
);
105 auto move_forward
= [¤t
, &ctx
] {
106 current
= current
.substr(1);
110 // If optpos is nonzero, then we are already parsing a valid flag and these
111 // need not be checked.
112 if (ctx
.optpos
== 0) {
113 if (current
[0] != '-')
116 if (current
== "--") {
128 [current
, optstring
]() -> cpp::optional
<OptstringParser::value_type
> {
129 for (auto i
: OptstringParser
{optstring
})
130 if (i
.c
== current
[0])
135 auto match
= find_match();
137 ctx
.report_error("%s: illegal option -- %c\n", argv
[0], current
[0]);
138 ctx
.optopt
.get() = current
[0];
142 // We've matched so eat that character.
145 // If we found an option that takes an argument and our current is not over,
146 // the rest of current is that argument. Ie, "-cabc" with opstring "c:",
147 // then optarg should point to "abc". Otherwise the argument to c will be in
148 // the next arg like "-c abc".
149 if (!current
.empty()) {
150 // This const cast is fine because current was already holding a mutable
151 // string, it just doesn't have the semantics to note that, we could use
152 // span but it doesn't have string_view string niceties.
153 ctx
.optarg
.get() = const_cast<char *>(current
.data());
155 // One char lookahead to see if we ran out of arguments. If so, return ':'
156 // if the first character of optstring is ':'. optind must stay at the
157 // current value so only increase it after we known there is another arg.
158 if (ctx
.optind
+ 1 >= argc
|| !argv
[ctx
.optind
+ 1]) {
159 ctx
.report_error("%s: option requires an argument -- %c\n", argv
[0],
161 return failure(optstring
[0] == ':' ? ':' : '?');
163 ctx
.optarg
.get() = argv
[++ctx
.optind
];
166 ctx
.optpos
.get() = 0;
167 } else if (current
.empty()) {
168 // If this argument is now empty we are safe to move onto the next one.
170 ctx
.optpos
.get() = 0;
179 char *optarg
= nullptr;
185 static unsigned optpos
;
187 static GetoptContext ctx
{&impl::optarg
, &impl::optind
, &impl::optopt
,
188 &optpos
, &impl::opterr
, /*errstream=*/nullptr};
190 #ifndef LIBC_COPT_PUBLIC_PACKAGING
191 // This is used exclusively in tests.
192 void set_getopt_state(char **optarg
, int *optind
, int *optopt
, unsigned *optpos
,
193 int *opterr
, FILE *errstream
) {
194 ctx
= {optarg
, optind
, optopt
, optpos
, opterr
, errstream
};
200 LLVM_LIBC_FUNCTION(int, getopt
,
201 (int argc
, char *const argv
[], const char *optstring
)) {
202 return getopt_r(argc
, argv
, optstring
, impl::ctx
);
205 } // namespace LIBC_NAMESPACE