/src/gdal/apps/argparse/argparse.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | __ _ _ __ __ _ _ __ __ _ _ __ ___ ___ |
3 | | / _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++ |
4 | | | (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse |
5 | | \__,_|_| \__, | .__/ \__,_|_| |___/\___| |
6 | | |___/|_| |
7 | | |
8 | | Licensed under the MIT License <http://opensource.org/licenses/MIT>. |
9 | | SPDX-License-Identifier: MIT |
10 | | Copyright (c) 2019-2022 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com> |
11 | | and other contributors. |
12 | | |
13 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
14 | | of this software and associated documentation files (the "Software"), to deal |
15 | | in the Software without restriction, including without limitation the rights |
16 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
17 | | copies of the Software, and to permit persons to whom the Software is |
18 | | furnished to do so, subject to the following conditions: |
19 | | |
20 | | The above copyright notice and this permission notice shall be included in all |
21 | | copies or substantial portions of the Software. |
22 | | |
23 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
24 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
25 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
26 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
27 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
28 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
29 | | SOFTWARE. |
30 | | */ |
31 | | #pragma once |
32 | | |
33 | | #include <cerrno> |
34 | | |
35 | | #ifndef ARGPARSE_MODULE_USE_STD_MODULE |
36 | | #include <algorithm> |
37 | | #include <any> |
38 | | #include <array> |
39 | | #include <set> |
40 | | #include <charconv> |
41 | | #include <cstdlib> |
42 | | #include <functional> |
43 | | #include <iomanip> |
44 | | #include <iostream> |
45 | | #include <iterator> |
46 | | #include <limits> |
47 | | #include <list> |
48 | | #include <map> |
49 | | #include <numeric> |
50 | | #include <optional> |
51 | | #include <sstream> |
52 | | #include <stdexcept> |
53 | | #include <string> |
54 | | #include <string_view> |
55 | | #include <tuple> |
56 | | #include <type_traits> |
57 | | #include <utility> |
58 | | #include <variant> |
59 | | #include <vector> |
60 | | #endif |
61 | | |
62 | | #ifndef ARGPARSE_CUSTOM_STRTOF |
63 | | #define ARGPARSE_CUSTOM_STRTOF strtof |
64 | | #endif |
65 | | |
66 | | #ifndef ARGPARSE_CUSTOM_STRTOD |
67 | | #define ARGPARSE_CUSTOM_STRTOD strtod |
68 | | #endif |
69 | | |
70 | | #ifndef ARGPARSE_CUSTOM_STRTOLD |
71 | | #define ARGPARSE_CUSTOM_STRTOLD strtold |
72 | | #endif |
73 | | |
74 | | namespace argparse { |
75 | | |
76 | | namespace details { // namespace for helper methods |
77 | | |
78 | | template <typename T, typename = void> |
79 | | struct HasContainerTraits : std::false_type {}; |
80 | | |
81 | | template <> struct HasContainerTraits<std::string> : std::false_type {}; |
82 | | |
83 | | template <> struct HasContainerTraits<std::string_view> : std::false_type {}; |
84 | | |
85 | | template <typename T> |
86 | | struct HasContainerTraits< |
87 | | T, std::void_t<typename T::value_type, decltype(std::declval<T>().begin()), |
88 | | decltype(std::declval<T>().end()), |
89 | | decltype(std::declval<T>().size())>> : std::true_type {}; |
90 | | |
91 | | template <typename T> |
92 | | inline constexpr bool IsContainer = HasContainerTraits<T>::value; |
93 | | |
94 | | template <typename T, typename = void> |
95 | | struct HasStreamableTraits : std::false_type {}; |
96 | | |
97 | | template <typename T> |
98 | | struct HasStreamableTraits< |
99 | | T, |
100 | | std::void_t<decltype(std::declval<std::ostream &>() << std::declval<T>())>> |
101 | | : std::true_type {}; |
102 | | |
103 | | template <typename T> |
104 | | inline constexpr bool IsStreamable = HasStreamableTraits<T>::value; |
105 | | |
106 | | constexpr std::size_t repr_max_container_size = 5; |
107 | | |
108 | 0 | template <typename T> std::string repr(T const &val) { |
109 | 0 | if constexpr (std::is_same_v<T, bool>) { |
110 | 0 | return val ? "true" : "false"; |
111 | 0 | } else if constexpr (std::is_convertible_v<T, std::string_view>) { |
112 | 0 | return '"' + std::string{std::string_view{val}} + '"'; |
113 | | } else if constexpr (IsContainer<T>) { |
114 | | std::stringstream out; |
115 | | out << "{"; |
116 | | const auto size = val.size(); |
117 | | if (size > 1) { |
118 | | out << repr(*val.begin()); |
119 | | std::for_each( |
120 | | std::next(val.begin()), |
121 | | std::next( |
122 | | val.begin(), |
123 | | static_cast<typename T::iterator::difference_type>( |
124 | | std::min<std::size_t>(size, repr_max_container_size) - 1)), |
125 | | [&out](const auto &v) { out << " " << repr(v); }); |
126 | | if (size <= repr_max_container_size) { |
127 | | out << " "; |
128 | | } else { |
129 | | out << "..."; |
130 | | } |
131 | | } |
132 | | if (size > 0) { |
133 | | out << repr(*std::prev(val.end())); |
134 | | } |
135 | | out << "}"; |
136 | | return out.str(); |
137 | 0 | } else if constexpr (IsStreamable<T>) { |
138 | 0 | std::stringstream out; |
139 | 0 | out << val; |
140 | 0 | return out.str(); |
141 | | } else { |
142 | | return "<not representable>"; |
143 | | } |
144 | 0 | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > gdal_argparse::details::repr<bool>(bool const&) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > gdal_argparse::details::repr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > gdal_argparse::details::repr<double>(double const&) |
145 | | |
146 | | namespace { |
147 | | |
148 | | template <typename T> constexpr bool standard_signed_integer = false; |
149 | | template <> constexpr bool standard_signed_integer<signed char> = true; |
150 | | template <> constexpr bool standard_signed_integer<short int> = true; |
151 | | template <> constexpr bool standard_signed_integer<int> = true; |
152 | | template <> constexpr bool standard_signed_integer<long int> = true; |
153 | | template <> constexpr bool standard_signed_integer<long long int> = true; |
154 | | |
155 | | template <typename T> constexpr bool standard_unsigned_integer = false; |
156 | | template <> constexpr bool standard_unsigned_integer<unsigned char> = true; |
157 | | template <> constexpr bool standard_unsigned_integer<unsigned short int> = true; |
158 | | template <> constexpr bool standard_unsigned_integer<unsigned int> = true; |
159 | | template <> constexpr bool standard_unsigned_integer<unsigned long int> = true; |
160 | | template <> |
161 | | constexpr bool standard_unsigned_integer<unsigned long long int> = true; |
162 | | |
163 | | } // namespace |
164 | | |
165 | | constexpr int radix_2 = 2; |
166 | | constexpr int radix_8 = 8; |
167 | | constexpr int radix_10 = 10; |
168 | | constexpr int radix_16 = 16; |
169 | | |
170 | | template <typename T> |
171 | | constexpr bool standard_integer = |
172 | | standard_signed_integer<T> || standard_unsigned_integer<T>; |
173 | | |
174 | | template <class F, class Tuple, class Extra, std::size_t... I> |
175 | | constexpr decltype(auto) |
176 | | apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, |
177 | | std::index_sequence<I...> /*unused*/) { |
178 | | return std::invoke(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))..., |
179 | | std::forward<Extra>(x)); |
180 | | } |
181 | | |
182 | | template <class F, class Tuple, class Extra> |
183 | | constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) { |
184 | | return details::apply_plus_one_impl( |
185 | | std::forward<F>(f), std::forward<Tuple>(t), std::forward<Extra>(x), |
186 | | std::make_index_sequence< |
187 | | std::tuple_size_v<std::remove_reference_t<Tuple>>>{}); |
188 | | } |
189 | | |
190 | 0 | constexpr auto pointer_range(std::string_view s) noexcept { |
191 | 0 | return std::tuple(s.data(), s.data() + s.size()); |
192 | 0 | } |
193 | | |
194 | | template <class CharT, class Traits> |
195 | | constexpr bool starts_with(std::basic_string_view<CharT, Traits> prefix, |
196 | 0 | std::basic_string_view<CharT, Traits> s) noexcept { |
197 | 0 | return s.substr(0, prefix.size()) == prefix; |
198 | 0 | } |
199 | | |
200 | | enum class chars_format { |
201 | | scientific = 0xf1, |
202 | | fixed = 0xf2, |
203 | | hex = 0xf4, |
204 | | binary = 0xf8, |
205 | | general = fixed | scientific |
206 | | }; |
207 | | |
208 | | struct ConsumeBinaryPrefixResult { |
209 | | bool is_binary; |
210 | | std::string_view rest; |
211 | | }; |
212 | | |
213 | | constexpr auto consume_binary_prefix(std::string_view s) |
214 | 0 | -> ConsumeBinaryPrefixResult { |
215 | 0 | if (starts_with(std::string_view{"0b"}, s) || |
216 | 0 | starts_with(std::string_view{"0B"}, s)) { |
217 | 0 | s.remove_prefix(2); |
218 | 0 | return {true, s}; |
219 | 0 | } |
220 | 0 | return {false, s}; |
221 | 0 | } |
222 | | |
223 | | struct ConsumeHexPrefixResult { |
224 | | bool is_hexadecimal; |
225 | | std::string_view rest; |
226 | | }; |
227 | | |
228 | | using namespace std::literals; |
229 | | |
230 | | constexpr auto consume_hex_prefix(std::string_view s) |
231 | 0 | -> ConsumeHexPrefixResult { |
232 | 0 | if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { |
233 | 0 | s.remove_prefix(2); |
234 | 0 | return {true, s}; |
235 | 0 | } |
236 | 0 | return {false, s}; |
237 | 0 | } |
238 | | |
239 | | template <class T, auto Param> |
240 | 0 | inline auto do_from_chars(std::string_view s) -> T { |
241 | 0 | T x{0}; |
242 | 0 | auto [first, last] = pointer_range(s); |
243 | 0 | auto [ptr, ec] = std::from_chars(first, last, x, Param); |
244 | 0 | if (ec == std::errc()) { |
245 | 0 | if (ptr == last) { |
246 | 0 | return x; |
247 | 0 | } |
248 | 0 | throw std::invalid_argument{"pattern '" + std::string(s) + |
249 | 0 | "' does not match to the end"}; |
250 | 0 | } |
251 | 0 | if (ec == std::errc::invalid_argument) { |
252 | 0 | throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"}; |
253 | 0 | } |
254 | 0 | if (ec == std::errc::result_out_of_range) { |
255 | 0 | throw std::range_error{"'" + std::string(s) + "' not representable"}; |
256 | 0 | } |
257 | 0 | return x; // unreachable |
258 | 0 | } Unexecuted instantiation: _ZN13gdal_argparse7details13do_from_charsIiTnDaLi10EEET_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE Unexecuted instantiation: _ZN13gdal_argparse7details13do_from_charsIiTnDaLi16EEET_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE Unexecuted instantiation: _ZN13gdal_argparse7details13do_from_charsIiTnDaLi2EEET_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE Unexecuted instantiation: _ZN13gdal_argparse7details13do_from_charsIiTnDaLi8EEET_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE Unexecuted instantiation: _ZN13gdal_argparse7details13do_from_charsIxTnDaLi10EEET_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE |
259 | | |
260 | | template <class T, auto Param = 0> struct parse_number { |
261 | 0 | auto operator()(std::string_view s) -> T { |
262 | 0 | return do_from_chars<T, Param>(s); |
263 | 0 | } Unexecuted instantiation: gdal_argparse::details::parse_number<int, 10>::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Unexecuted instantiation: gdal_argparse::details::parse_number<long long, 10>::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >) |
264 | | }; |
265 | | |
266 | | template <class T> struct parse_number<T, radix_2> { |
267 | | auto operator()(std::string_view s) -> T { |
268 | | if (auto [ok, rest] = consume_binary_prefix(s); ok) { |
269 | | return do_from_chars<T, radix_2>(rest); |
270 | | } |
271 | | throw std::invalid_argument{"pattern not found"}; |
272 | | } |
273 | | }; |
274 | | |
275 | | template <class T> struct parse_number<T, radix_16> { |
276 | | auto operator()(std::string_view s) -> T { |
277 | | if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { |
278 | | if (auto [ok, rest] = consume_hex_prefix(s); ok) { |
279 | | try { |
280 | | return do_from_chars<T, radix_16>(rest); |
281 | | } catch (const std::invalid_argument &err) { |
282 | | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
283 | | "' as hexadecimal: " + err.what()); |
284 | | } catch (const std::range_error &err) { |
285 | | throw std::range_error("Failed to parse '" + std::string(s) + |
286 | | "' as hexadecimal: " + err.what()); |
287 | | } |
288 | | } |
289 | | } else { |
290 | | // Allow passing hex numbers without prefix |
291 | | // Shape 'x' already has to be specified |
292 | | try { |
293 | | return do_from_chars<T, radix_16>(s); |
294 | | } catch (const std::invalid_argument &err) { |
295 | | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
296 | | "' as hexadecimal: " + err.what()); |
297 | | } catch (const std::range_error &err) { |
298 | | throw std::range_error("Failed to parse '" + std::string(s) + |
299 | | "' as hexadecimal: " + err.what()); |
300 | | } |
301 | | } |
302 | | |
303 | | throw std::invalid_argument{"pattern '" + std::string(s) + |
304 | | "' not identified as hexadecimal"}; |
305 | | } |
306 | | }; |
307 | | |
308 | | template <class T> struct parse_number<T> { |
309 | 0 | auto operator()(std::string_view s) -> T { |
310 | 0 | auto [ok, rest] = consume_hex_prefix(s); |
311 | 0 | if (ok) { |
312 | 0 | try { |
313 | 0 | return do_from_chars<T, radix_16>(rest); |
314 | 0 | } catch (const std::invalid_argument &err) { |
315 | 0 | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
316 | 0 | "' as hexadecimal: " + err.what()); |
317 | 0 | } catch (const std::range_error &err) { |
318 | 0 | throw std::range_error("Failed to parse '" + std::string(s) + |
319 | 0 | "' as hexadecimal: " + err.what()); |
320 | 0 | } |
321 | 0 | } |
322 | | |
323 | 0 | auto [ok_binary, rest_binary] = consume_binary_prefix(s); |
324 | 0 | if (ok_binary) { |
325 | 0 | try { |
326 | 0 | return do_from_chars<T, radix_2>(rest_binary); |
327 | 0 | } catch (const std::invalid_argument &err) { |
328 | 0 | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
329 | 0 | "' as binary: " + err.what()); |
330 | 0 | } catch (const std::range_error &err) { |
331 | 0 | throw std::range_error("Failed to parse '" + std::string(s) + |
332 | 0 | "' as binary: " + err.what()); |
333 | 0 | } |
334 | 0 | } |
335 | | |
336 | 0 | if (starts_with("0"sv, s)) { |
337 | 0 | try { |
338 | 0 | return do_from_chars<T, radix_8>(rest); |
339 | 0 | } catch (const std::invalid_argument &err) { |
340 | 0 | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
341 | 0 | "' as octal: " + err.what()); |
342 | 0 | } catch (const std::range_error &err) { |
343 | 0 | throw std::range_error("Failed to parse '" + std::string(s) + |
344 | 0 | "' as octal: " + err.what()); |
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | 0 | try { |
349 | 0 | return do_from_chars<T, radix_10>(rest); |
350 | 0 | } catch (const std::invalid_argument &err) { |
351 | 0 | throw std::invalid_argument("Failed to parse '" + std::string(s) + |
352 | 0 | "' as decimal integer: " + err.what()); |
353 | 0 | } catch (const std::range_error &err) { |
354 | 0 | throw std::range_error("Failed to parse '" + std::string(s) + |
355 | 0 | "' as decimal integer: " + err.what()); |
356 | 0 | } |
357 | 0 | } |
358 | | }; |
359 | | |
360 | | namespace { |
361 | | |
362 | | template <class T> inline const auto generic_strtod = nullptr; |
363 | | template <> inline const auto generic_strtod<float> = ARGPARSE_CUSTOM_STRTOF; |
364 | | template <> inline const auto generic_strtod<double> = ARGPARSE_CUSTOM_STRTOD; |
365 | | template <> |
366 | | inline const auto generic_strtod<long double> = ARGPARSE_CUSTOM_STRTOLD; |
367 | | |
368 | | } // namespace |
369 | | |
370 | 0 | template <class T> inline auto do_strtod(std::string const &s) -> T { |
371 | 0 | if (isspace(static_cast<unsigned char>(s[0])) || s[0] == '+') { |
372 | 0 | throw std::invalid_argument{"pattern '" + s + "' not found"}; |
373 | 0 | } |
374 | | |
375 | 0 | auto [first, last] = pointer_range(s); |
376 | 0 | char *ptr; |
377 | |
|
378 | 0 | errno = 0; |
379 | 0 | auto x = generic_strtod<T>(first, &ptr); |
380 | 0 | if (errno == 0) { |
381 | 0 | if (ptr == last) { |
382 | 0 | return x; |
383 | 0 | } |
384 | 0 | throw std::invalid_argument{"pattern '" + s + |
385 | 0 | "' does not match to the end"}; |
386 | 0 | } |
387 | 0 | if (errno == ERANGE) { |
388 | 0 | throw std::range_error{"'" + s + "' not representable"}; |
389 | 0 | } |
390 | 0 | return x; // unreachable |
391 | 0 | } |
392 | | |
393 | | template <class T> struct parse_number<T, chars_format::general> { |
394 | 0 | auto operator()(std::string const &s) -> T { |
395 | 0 | if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { |
396 | 0 | throw std::invalid_argument{ |
397 | 0 | "chars_format::general does not parse hexfloat"}; |
398 | 0 | } |
399 | 0 | if (auto r = consume_binary_prefix(s); r.is_binary) { |
400 | 0 | throw std::invalid_argument{ |
401 | 0 | "chars_format::general does not parse binfloat"}; |
402 | 0 | } |
403 | | |
404 | 0 | try { |
405 | 0 | return do_strtod<T>(s); |
406 | 0 | } catch (const std::invalid_argument &err) { |
407 | 0 | throw std::invalid_argument("Failed to parse '" + s + |
408 | 0 | "' as number: " + err.what()); |
409 | 0 | } catch (const std::range_error &err) { |
410 | 0 | throw std::range_error("Failed to parse '" + s + |
411 | 0 | "' as number: " + err.what()); |
412 | 0 | } |
413 | 0 | } |
414 | | }; |
415 | | |
416 | | template <class T> struct parse_number<T, chars_format::hex> { |
417 | | auto operator()(std::string const &s) -> T { |
418 | | if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { |
419 | | throw std::invalid_argument{"chars_format::hex parses hexfloat"}; |
420 | | } |
421 | | if (auto r = consume_binary_prefix(s); r.is_binary) { |
422 | | throw std::invalid_argument{"chars_format::hex does not parse binfloat"}; |
423 | | } |
424 | | |
425 | | try { |
426 | | return do_strtod<T>(s); |
427 | | } catch (const std::invalid_argument &err) { |
428 | | throw std::invalid_argument("Failed to parse '" + s + |
429 | | "' as hexadecimal: " + err.what()); |
430 | | } catch (const std::range_error &err) { |
431 | | throw std::range_error("Failed to parse '" + s + |
432 | | "' as hexadecimal: " + err.what()); |
433 | | } |
434 | | } |
435 | | }; |
436 | | |
437 | | template <class T> struct parse_number<T, chars_format::binary> { |
438 | | auto operator()(std::string const &s) -> T { |
439 | | if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { |
440 | | throw std::invalid_argument{ |
441 | | "chars_format::binary does not parse hexfloat"}; |
442 | | } |
443 | | if (auto r = consume_binary_prefix(s); !r.is_binary) { |
444 | | throw std::invalid_argument{"chars_format::binary parses binfloat"}; |
445 | | } |
446 | | |
447 | | return do_strtod<T>(s); |
448 | | } |
449 | | }; |
450 | | |
451 | | template <class T> struct parse_number<T, chars_format::scientific> { |
452 | | auto operator()(std::string const &s) -> T { |
453 | | if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { |
454 | | throw std::invalid_argument{ |
455 | | "chars_format::scientific does not parse hexfloat"}; |
456 | | } |
457 | | if (auto r = consume_binary_prefix(s); r.is_binary) { |
458 | | throw std::invalid_argument{ |
459 | | "chars_format::scientific does not parse binfloat"}; |
460 | | } |
461 | | if (s.find_first_of("eE") == std::string::npos) { |
462 | | throw std::invalid_argument{ |
463 | | "chars_format::scientific requires exponent part"}; |
464 | | } |
465 | | |
466 | | try { |
467 | | return do_strtod<T>(s); |
468 | | } catch (const std::invalid_argument &err) { |
469 | | throw std::invalid_argument("Failed to parse '" + s + |
470 | | "' as scientific notation: " + err.what()); |
471 | | } catch (const std::range_error &err) { |
472 | | throw std::range_error("Failed to parse '" + s + |
473 | | "' as scientific notation: " + err.what()); |
474 | | } |
475 | | } |
476 | | }; |
477 | | |
478 | | template <class T> struct parse_number<T, chars_format::fixed> { |
479 | | auto operator()(std::string const &s) -> T { |
480 | | if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { |
481 | | throw std::invalid_argument{ |
482 | | "chars_format::fixed does not parse hexfloat"}; |
483 | | } |
484 | | if (auto r = consume_binary_prefix(s); r.is_binary) { |
485 | | throw std::invalid_argument{ |
486 | | "chars_format::fixed does not parse binfloat"}; |
487 | | } |
488 | | if (s.find_first_of("eE") != std::string::npos) { |
489 | | throw std::invalid_argument{ |
490 | | "chars_format::fixed does not parse exponent part"}; |
491 | | } |
492 | | |
493 | | try { |
494 | | return do_strtod<T>(s); |
495 | | } catch (const std::invalid_argument &err) { |
496 | | throw std::invalid_argument("Failed to parse '" + s + |
497 | | "' as fixed notation: " + err.what()); |
498 | | } catch (const std::range_error &err) { |
499 | | throw std::range_error("Failed to parse '" + s + |
500 | | "' as fixed notation: " + err.what()); |
501 | | } |
502 | | } |
503 | | }; |
504 | | |
505 | | template <typename StrIt> |
506 | 0 | std::string join(StrIt first, StrIt last, const std::string &separator) { |
507 | 0 | if (first == last) { |
508 | 0 | return ""; |
509 | 0 | } |
510 | 0 | std::stringstream value; |
511 | 0 | value << *first; |
512 | 0 | ++first; |
513 | 0 | while (first != last) { |
514 | 0 | value << separator << *first; |
515 | 0 | ++first; |
516 | 0 | } |
517 | 0 | return value.str(); |
518 | 0 | } |
519 | | |
520 | | template <typename T> struct can_invoke_to_string { |
521 | | template <typename U> |
522 | | static auto test(int) |
523 | | -> decltype(std::to_string(std::declval<U>()), std::true_type{}); |
524 | | |
525 | | template <typename U> static auto test(...) -> std::false_type; |
526 | | |
527 | | static constexpr bool value = decltype(test<T>(0))::value; |
528 | | }; |
529 | | |
530 | | template <typename T> struct IsChoiceTypeSupported { |
531 | | using CleanType = typename std::decay<T>::type; |
532 | | static const bool value = std::is_integral<CleanType>::value || |
533 | | std::is_same<CleanType, std::string>::value || |
534 | | std::is_same<CleanType, std::string_view>::value || |
535 | | std::is_same<CleanType, const char *>::value; |
536 | | }; |
537 | | |
538 | | template <typename StringType> |
539 | | std::size_t get_levenshtein_distance(const StringType &s1, |
540 | 0 | const StringType &s2) { |
541 | 0 | std::vector<std::vector<std::size_t>> dp( |
542 | 0 | s1.size() + 1, std::vector<std::size_t>(s2.size() + 1, 0)); |
543 | |
|
544 | 0 | for (std::size_t i = 0; i <= s1.size(); ++i) { |
545 | 0 | for (std::size_t j = 0; j <= s2.size(); ++j) { |
546 | 0 | if (i == 0) { |
547 | 0 | dp[i][j] = j; |
548 | 0 | } else if (j == 0) { |
549 | 0 | dp[i][j] = i; |
550 | 0 | } else if (s1[i - 1] == s2[j - 1]) { |
551 | 0 | dp[i][j] = dp[i - 1][j - 1]; |
552 | 0 | } else { |
553 | 0 | dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}); |
554 | 0 | } |
555 | 0 | } |
556 | 0 | } |
557 | |
|
558 | 0 | return dp[s1.size()][s2.size()]; |
559 | 0 | } |
560 | | |
561 | | template <typename ValueType> |
562 | | std::string get_most_similar_string(const std::map<std::string, ValueType> &map, |
563 | 0 | const std::string &input) { |
564 | 0 | std::string most_similar{}; |
565 | 0 | std::size_t min_distance = std::numeric_limits<std::size_t>::max(); |
566 | |
|
567 | 0 | for (const auto &entry : map) { |
568 | 0 | std::size_t distance = get_levenshtein_distance(entry.first, input); |
569 | 0 | if (distance < min_distance) { |
570 | 0 | min_distance = distance; |
571 | 0 | most_similar = entry.first; |
572 | 0 | } |
573 | 0 | } |
574 | |
|
575 | 0 | return most_similar; |
576 | 0 | } |
577 | | |
578 | | } // namespace details |
579 | | |
580 | | enum class nargs_pattern { optional, any, at_least_one }; |
581 | | |
582 | | enum class default_arguments : unsigned int { |
583 | | none = 0, |
584 | | help = 1, |
585 | | version = 2, |
586 | | all = help | version, |
587 | | }; |
588 | | |
589 | | inline default_arguments operator&(const default_arguments &a, |
590 | 0 | const default_arguments &b) { |
591 | 0 | return static_cast<default_arguments>( |
592 | 0 | static_cast<std::underlying_type<default_arguments>::type>(a) & |
593 | 0 | static_cast<std::underlying_type<default_arguments>::type>(b)); |
594 | 0 | } |
595 | | |
596 | | class ArgumentParser; |
597 | | |
598 | | class Argument { |
599 | | friend class ArgumentParser; |
600 | | friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) |
601 | | -> std::ostream &; |
602 | | |
603 | | template <std::size_t N, std::size_t... I> |
604 | | explicit Argument(std::string_view prefix_chars, |
605 | | std::array<std::string_view, N> &&a, |
606 | | std::index_sequence<I...> /*unused*/) |
607 | 0 | : m_accepts_optional_like_value(false), |
608 | 0 | m_is_optional((is_optional(a[I], prefix_chars) || ...)), |
609 | 0 | m_is_required(false), m_is_repeatable(false), m_is_used(false), |
610 | 0 | m_is_hidden(false), m_prefix_chars(prefix_chars) { |
611 | 0 | ((void)m_names.emplace_back(a[I]), ...); |
612 | 0 | std::sort( |
613 | 0 | m_names.begin(), m_names.end(), [](const auto &lhs, const auto &rhs) { |
614 | 0 | return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); |
615 | 0 | }); Unexecuted instantiation: auto gdal_argparse::Argument::Argument<1ul, 0ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 1ul>&&, std::__1::integer_sequence<unsigned long, 0ul>)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<char> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::allocator<char> const&) const Unexecuted instantiation: auto gdal_argparse::Argument::Argument<2ul, 0ul, 1ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 2ul>&&, std::__1::integer_sequence<unsigned long, 0ul, 1ul>)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<char> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::allocator<char> const&) const |
616 | 0 | } Unexecuted instantiation: gdal_argparse::Argument::Argument<1ul, 0ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 1ul>&&, std::__1::integer_sequence<unsigned long, 0ul>) Unexecuted instantiation: gdal_argparse::Argument::Argument<2ul, 0ul, 1ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 2ul>&&, std::__1::integer_sequence<unsigned long, 0ul, 1ul>) |
617 | | |
618 | | public: |
619 | | template <std::size_t N> |
620 | | explicit Argument(std::string_view prefix_chars, |
621 | | std::array<std::string_view, N> &&a) |
622 | 0 | : Argument(prefix_chars, std::move(a), std::make_index_sequence<N>{}) {} Unexecuted instantiation: gdal_argparse::Argument::Argument<1ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 1ul>&&) Unexecuted instantiation: gdal_argparse::Argument::Argument<2ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::array<std::__1::basic_string_view<char, std::__1::char_traits<char> >, 2ul>&&) |
623 | | |
624 | 0 | Argument &help(std::string help_text) { |
625 | 0 | m_help = std::move(help_text); |
626 | 0 | return *this; |
627 | 0 | } |
628 | | |
629 | 0 | Argument &metavar(std::string metavar) { |
630 | 0 | m_metavar = std::move(metavar); |
631 | 0 | return *this; |
632 | 0 | } |
633 | | |
634 | 0 | template <typename T> Argument &default_value(T &&value) { |
635 | 0 | m_num_args_range = NArgsRange{0, m_num_args_range.get_max()}; |
636 | 0 | m_default_value_repr = details::repr(value); |
637 | |
|
638 | | if constexpr (std::is_convertible_v<T, std::string_view>) { |
639 | | m_default_value_str = std::string{std::string_view{value}}; |
640 | 0 | } else if constexpr (details::can_invoke_to_string<T>::value) { |
641 | 0 | m_default_value_str = std::to_string(value); |
642 | 0 | } |
643 | |
|
644 | 0 | m_default_value = std::forward<T>(value); |
645 | 0 | return *this; |
646 | 0 | } Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::default_value<bool>(bool&&) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::default_value<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::default_value<double&>(double&) |
647 | | |
648 | 0 | Argument &default_value(const char *value) { |
649 | 0 | return default_value(std::string(value)); |
650 | 0 | } |
651 | | |
652 | 0 | Argument &required() { |
653 | 0 | m_is_required = true; |
654 | 0 | return *this; |
655 | 0 | } |
656 | | |
657 | 0 | Argument &implicit_value(std::any value) { |
658 | 0 | m_implicit_value = std::move(value); |
659 | 0 | m_num_args_range = NArgsRange{0, 0}; |
660 | 0 | return *this; |
661 | 0 | } |
662 | | |
663 | | // This is shorthand for: |
664 | | // program.add_argument("foo") |
665 | | // .default_value(false) |
666 | | // .implicit_value(true) |
667 | 0 | Argument &flag() { |
668 | 0 | default_value(false); |
669 | 0 | implicit_value(true); |
670 | 0 | return *this; |
671 | 0 | } |
672 | | |
673 | | template <class F, class... Args> |
674 | | auto action(F &&callable, Args &&... bound_args) |
675 | | -> std::enable_if_t<std::is_invocable_v<F, Args..., std::string const>, |
676 | 0 | Argument &> { |
677 | 0 | using action_type = std::conditional_t< |
678 | 0 | std::is_void_v<std::invoke_result_t<F, Args..., std::string const>>, |
679 | 0 | void_action, valued_action>; |
680 | 0 | if constexpr (sizeof...(Args) == 0) { |
681 | 0 | m_actions.emplace_back<action_type>(std::forward<F>(callable)); |
682 | | } else { |
683 | | m_actions.emplace_back<action_type>( |
684 | | [f = std::forward<F>(callable), |
685 | | tup = std::make_tuple(std::forward<Args>(bound_args)...)]( |
686 | | std::string const &opt) mutable { |
687 | | return details::apply_plus_one(f, tup, opt); |
688 | | }); |
689 | | } |
690 | 0 | return *this; |
691 | 0 | } Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_1JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_2JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_3JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERbEUlRKT_E_JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIS3_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS3_DpOS9_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_4JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionINS_7details12parse_numberIdLNS2_12chars_formatE243EEEJEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_5JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEUlRKS8_E_JEEENS2_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSE_DpOSF_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_6JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERdEUlRKT_E_JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIS3_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS3_DpOS9_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_7JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_8JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE3$_9JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdal_translate_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL29GDALTranslateOptionsGetParserP20GDALTranslateOptionsP29GDALTranslateOptionsForBinaryE4$_10JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoIiTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS5_EUlRKS5_E_JEEENS4_IXsr3stdE14is_invocable_vIS5_DpT0_KNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEERS0_E4typeEOS5_DpOSF_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERNSt3__16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEEEUlRKS9_E_JEEENS2_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SD_EERS0_E4typeEOSH_DpOSI_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERNSt3__16vectorIiNS2_9allocatorIiEEEEEUlRKNS2_12basic_stringIcNS2_11char_traitsIcEENS4_IcEEEEE_JEEENS2_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SD_EERS0_E4typeEOSH_DpOSI_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERNSt3__13setINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS2_4lessIS9_EENS7_IS9_EEEEEUlRKS9_E_JEEENS2_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SF_EERS0_E4typeEOSJ_DpOSK_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoERNSt3__13setIiNS2_4lessIiEENS2_9allocatorIiEEEEEUlRKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEEE_JEEENS2_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SF_EERS0_E4typeEOSJ_DpOSK_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS_14ArgumentParserC1ENSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEES9_NS_17default_argumentsEbRNS3_13basic_ostreamIcS6_EEEUlRKT_E_JEEENS3_9enable_ifIXsr3stdE14is_invocable_vISE_DpT0_KS9_EERS0_E4typeEOSE_DpOSJ_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS_14ArgumentParserC1ENSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEES9_NS_17default_argumentsEbRNS3_13basic_ostreamIcS6_EEEUlRKT_E0_JEEENS3_9enable_ifIXsr3stdE14is_invocable_vISE_DpT0_KS9_EERS0_E4typeEOSE_DpOSJ_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_1JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_2JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_3JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionINS_7details12parse_numberIiLi0EEEJEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEEERS0_E4typeEOS7_DpOS8_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_4JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_5JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_6JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_7JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_8JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE3$_9JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_10JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_11JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_12JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_13JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_14JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_15JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_16JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_17JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_18JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_19JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_20JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_21JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_22JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_23JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_24JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_25JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_26JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_27JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_28JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_29JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_30JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_31JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalwarp_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL27GDALWarpAppOptionsGetParserP18GDALWarpAppOptionsP27GDALWarpAppOptionsForBinaryE4$_32JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParserC1ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbE3$_0JEEENS3_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSE_DpOSF_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParserC1ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbE3$_1JEEENS3_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSE_DpOSF_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParserC1ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbE3$_2JEEENS3_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSE_DpOSF_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParserC1ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbE3$_3JEEENS3_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSE_DpOSF_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser25add_input_format_argumentEP13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser29add_creation_options_argumentER13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser34add_metadata_item_options_argumentER13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser25add_open_options_argumentEP13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser24add_output_type_argumentER12GDALDataTypeE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser35add_layer_creation_options_argumentER13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser37add_dataset_creation_options_argumentER13CPLStringListE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS6_12basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEERS0_E4typeEOS8_DpOS9_ Unexecuted instantiation: gdalargumentparser.cpp:_ZN13gdal_argparse8Argument6actionIZN18GDALArgumentParser23add_inverted_logic_flagERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPbSB_E3$_0JEEENS3_9enable_ifIXsr3stdE14is_invocable_vIT_DpT0_SA_EERS0_E4typeEOSF_DpOSG_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_1JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_2JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_3JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_4JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_5JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_6JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_7JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: gdalbuildvrt_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL28GDALBuildVRTOptionsGetParserP19GDALBuildVRTOptionsP28GDALBuildVRTOptionsForBinaryE3$_8JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_0JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_1JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_2JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_3JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_4JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_5JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_6JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_7JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_8JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE3$_9JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_10JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_11JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_12JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_13JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_14JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_15JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_16JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_17JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_18JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_19JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_20JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_21JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_22JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_23JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_24JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_25JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_26JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_27JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_28JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_29JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: _ZN13gdal_argparse8Argument6actionIZNS0_10store_intoIxTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS5_EUlRKS5_E_JEEENS4_IXsr3stdE14is_invocable_vIS5_DpT0_KNS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEERS0_E4typeEOS5_DpOSF_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_30JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_31JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_32JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_33JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ Unexecuted instantiation: ogr2ogr_lib.cpp:_ZN13gdal_argparse8Argument6actionIZL35GDALVectorTranslateOptionsGetParserP26GDALVectorTranslateOptionsP35GDALVectorTranslateOptionsForBinaryiiE4$_34JEEENSt3__19enable_ifIXsr3stdE14is_invocable_vIT_DpT0_KNS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEEERS0_E4typeEOS9_DpOSA_ |
692 | | |
693 | 0 | auto &store_into(bool &var) { |
694 | 0 | flag(); |
695 | 0 | if (m_default_value.has_value()) { |
696 | 0 | var = std::any_cast<bool>(m_default_value); |
697 | 0 | } |
698 | 0 | action([&var](const auto & /*unused*/) { var = true; }); |
699 | 0 | return *this; |
700 | 0 | } |
701 | | |
702 | | template <typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr> |
703 | 0 | auto &store_into(T &var) { |
704 | 0 | if (m_default_value.has_value()) { |
705 | 0 | try |
706 | 0 | { |
707 | 0 | var = std::any_cast<T>(m_default_value); |
708 | 0 | } |
709 | 0 | catch (...) |
710 | 0 | { |
711 | 0 | var = static_cast<T>(std::any_cast<int>(m_default_value)); |
712 | 0 | } |
713 | 0 | } |
714 | 0 | action([&var](const auto &s) { |
715 | 0 | var = details::parse_number<T, details::radix_10>()(s); |
716 | 0 | }); Unexecuted instantiation: _ZZN13gdal_argparse8Argument10store_intoIiTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS4_ENKUlRKS4_E_clINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEDaSC_ Unexecuted instantiation: _ZZN13gdal_argparse8Argument10store_intoIxTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS4_ENKUlRKS4_E_clINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEDaSC_ |
717 | 0 | return *this; |
718 | 0 | } Unexecuted instantiation: _ZN13gdal_argparse8Argument10store_intoIiTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS4_ Unexecuted instantiation: _ZN13gdal_argparse8Argument10store_intoIxTnPNSt3__19enable_ifIXsr3std11is_integralIT_EE5valueEvE4typeELPv0EEERDaRS4_ |
719 | | |
720 | 0 | auto &store_into(double &var) { |
721 | 0 | if (m_default_value.has_value()) { |
722 | 0 | try |
723 | 0 | { |
724 | 0 | var = std::any_cast<double>(m_default_value); |
725 | 0 | } |
726 | 0 | catch (...) |
727 | 0 | { |
728 | 0 | var = std::any_cast<int>(m_default_value); |
729 | 0 | } |
730 | 0 | } |
731 | 0 | action([&var](const auto &s) { |
732 | 0 | var = details::parse_number<double, details::chars_format::general>()(s); |
733 | 0 | }); |
734 | 0 | return *this; |
735 | 0 | } |
736 | | |
737 | 0 | auto &store_into(std::string &var) { |
738 | 0 | if (m_default_value.has_value()) { |
739 | 0 | var = std::any_cast<std::string>(m_default_value); |
740 | 0 | } |
741 | 0 | action([&var](const std::string &s) { var = s; }); |
742 | 0 | return *this; |
743 | 0 | } |
744 | | |
745 | 0 | auto &store_into(std::vector<std::string> &var) { |
746 | 0 | if (m_default_value.has_value()) { |
747 | 0 | var = std::any_cast<std::vector<std::string>>(m_default_value); |
748 | 0 | } |
749 | 0 | action([this, &var](const std::string &s) { |
750 | 0 | if (!m_is_used) { |
751 | 0 | var.clear(); |
752 | 0 | } |
753 | 0 | m_is_used = true; |
754 | 0 | var.push_back(s); |
755 | 0 | }); |
756 | 0 | return *this; |
757 | 0 | } |
758 | | |
759 | 0 | auto &store_into(std::vector<int> &var) { |
760 | 0 | if (m_default_value.has_value()) { |
761 | 0 | var = std::any_cast<std::vector<int>>(m_default_value); |
762 | 0 | } |
763 | 0 | action([this, &var](const std::string &s) { |
764 | 0 | if (!m_is_used) { |
765 | 0 | var.clear(); |
766 | 0 | } |
767 | 0 | m_is_used = true; |
768 | 0 | var.push_back(details::parse_number<int, details::radix_10>()(s)); |
769 | 0 | }); |
770 | 0 | return *this; |
771 | 0 | } |
772 | | |
773 | 0 | auto &store_into(std::set<std::string> &var) { |
774 | 0 | if (m_default_value.has_value()) { |
775 | 0 | var = std::any_cast<std::set<std::string>>(m_default_value); |
776 | 0 | } |
777 | 0 | action([this, &var](const std::string &s) { |
778 | 0 | if (!m_is_used) { |
779 | 0 | var.clear(); |
780 | 0 | } |
781 | 0 | m_is_used = true; |
782 | 0 | var.insert(s); |
783 | 0 | }); |
784 | 0 | return *this; |
785 | 0 | } |
786 | | |
787 | 0 | auto &store_into(std::set<int> &var) { |
788 | 0 | if (m_default_value.has_value()) { |
789 | 0 | var = std::any_cast<std::set<int>>(m_default_value); |
790 | 0 | } |
791 | 0 | action([this, &var](const std::string &s) { |
792 | 0 | if (!m_is_used) { |
793 | 0 | var.clear(); |
794 | 0 | } |
795 | 0 | m_is_used = true; |
796 | 0 | var.insert(details::parse_number<int, details::radix_10>()(s)); |
797 | 0 | }); |
798 | 0 | return *this; |
799 | 0 | } |
800 | | |
801 | 0 | auto &append() { |
802 | 0 | m_is_repeatable = true; |
803 | 0 | return *this; |
804 | 0 | } |
805 | | |
806 | | // Cause the argument to be invisible in usage and help |
807 | 0 | auto &hidden() { |
808 | 0 | m_is_hidden = true; |
809 | 0 | return *this; |
810 | 0 | } |
811 | | |
812 | | template <char Shape, typename T> |
813 | 0 | auto scan() -> std::enable_if_t<std::is_arithmetic_v<T>, Argument &> { |
814 | 0 | static_assert(!(std::is_const_v<T> || std::is_volatile_v<T>), |
815 | 0 | "T should not be cv-qualified"); |
816 | 0 | auto is_one_of = [](char c, auto... x) constexpr { |
817 | 0 | return ((c == x) || ...); |
818 | 0 | }; Unexecuted instantiation: _ZZN13gdal_argparse8Argument4scanILc103EdEENSt3__19enable_ifIXsr3stdE15is_arithmetic_vIT0_EERS0_E4typeEvENKUlcDpT_E_clIJcEEEDacS9_ Unexecuted instantiation: _ZZN13gdal_argparse8Argument4scanILc103EdEENSt3__19enable_ifIXsr3stdE15is_arithmetic_vIT0_EERS0_E4typeEvENKUlcDpT_E_clIJccEEEDacS9_ Unexecuted instantiation: _ZZN13gdal_argparse8Argument4scanILc105EiEENSt3__19enable_ifIXsr3stdE15is_arithmetic_vIT0_EERS0_E4typeEvENKUlcDpT_E_clIJcEEEDacS9_ |
819 | |
|
820 | | if constexpr (is_one_of(Shape, 'd') && details::standard_integer<T>) { |
821 | | action(details::parse_number<T, details::radix_10>()); |
822 | | } else if constexpr (is_one_of(Shape, 'i') && |
823 | 0 | details::standard_integer<T>) { |
824 | 0 | action(details::parse_number<T>()); |
825 | | } else if constexpr (is_one_of(Shape, 'u') && |
826 | | details::standard_unsigned_integer<T>) { |
827 | | action(details::parse_number<T, details::radix_10>()); |
828 | | } else if constexpr (is_one_of(Shape, 'b') && |
829 | | details::standard_unsigned_integer<T>) { |
830 | | action(details::parse_number<T, details::radix_2>()); |
831 | | } else if constexpr (is_one_of(Shape, 'o') && |
832 | | details::standard_unsigned_integer<T>) { |
833 | | action(details::parse_number<T, details::radix_8>()); |
834 | | } else if constexpr (is_one_of(Shape, 'x', 'X') && |
835 | | details::standard_unsigned_integer<T>) { |
836 | | action(details::parse_number<T, details::radix_16>()); |
837 | | } else if constexpr (is_one_of(Shape, 'a', 'A') && |
838 | | std::is_floating_point_v<T>) { |
839 | | action(details::parse_number<T, details::chars_format::hex>()); |
840 | | } else if constexpr (is_one_of(Shape, 'e', 'E') && |
841 | | std::is_floating_point_v<T>) { |
842 | | action(details::parse_number<T, details::chars_format::scientific>()); |
843 | | } else if constexpr (is_one_of(Shape, 'f', 'F') && |
844 | | std::is_floating_point_v<T>) { |
845 | | action(details::parse_number<T, details::chars_format::fixed>()); |
846 | | } else if constexpr (is_one_of(Shape, 'g', 'G') && |
847 | 0 | std::is_floating_point_v<T>) { |
848 | 0 | action(details::parse_number<T, details::chars_format::general>()); |
849 | | } else { |
850 | | static_assert(alignof(T) == 0, "No scan specification for T"); |
851 | | } |
852 | |
|
853 | 0 | return *this; |
854 | 0 | } Unexecuted instantiation: _ZN13gdal_argparse8Argument4scanILc103EdEENSt3__19enable_ifIXsr3stdE15is_arithmetic_vIT0_EERS0_E4typeEv Unexecuted instantiation: _ZN13gdal_argparse8Argument4scanILc105EiEENSt3__19enable_ifIXsr3stdE15is_arithmetic_vIT0_EERS0_E4typeEv |
855 | | |
856 | 0 | Argument &nargs(std::size_t num_args) { |
857 | 0 | m_num_args_range = NArgsRange{num_args, num_args}; |
858 | 0 | return *this; |
859 | 0 | } |
860 | | |
861 | 0 | Argument &nargs(std::size_t num_args_min, std::size_t num_args_max) { |
862 | 0 | m_num_args_range = NArgsRange{num_args_min, num_args_max}; |
863 | 0 | return *this; |
864 | 0 | } |
865 | | |
866 | 0 | Argument &nargs(nargs_pattern pattern) { |
867 | 0 | switch (pattern) { |
868 | 0 | case nargs_pattern::optional: |
869 | 0 | m_num_args_range = NArgsRange{0, 1}; |
870 | 0 | break; |
871 | 0 | case nargs_pattern::any: |
872 | 0 | m_num_args_range = |
873 | 0 | NArgsRange{0, (std::numeric_limits<std::size_t>::max)()}; |
874 | 0 | break; |
875 | 0 | case nargs_pattern::at_least_one: |
876 | 0 | m_num_args_range = |
877 | 0 | NArgsRange{1, (std::numeric_limits<std::size_t>::max)()}; |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | return *this; |
881 | 0 | } |
882 | | |
883 | 0 | Argument &remaining() { |
884 | 0 | m_accepts_optional_like_value = true; |
885 | 0 | return nargs(nargs_pattern::any); |
886 | 0 | } |
887 | | |
888 | 0 | template <typename T> void add_choice(T &&choice) { |
889 | 0 | static_assert(details::IsChoiceTypeSupported<T>::value, |
890 | 0 | "Only string or integer type supported for choice"); |
891 | 0 | static_assert(std::is_convertible_v<T, std::string_view> || |
892 | 0 | details::can_invoke_to_string<T>::value, |
893 | 0 | "Choice is not convertible to string_type"); |
894 | 0 | if (!m_choices.has_value()) { |
895 | 0 | m_choices = std::vector<std::string>{}; |
896 | 0 | } |
897 | |
|
898 | 0 | if constexpr (std::is_convertible_v<T, std::string_view>) { |
899 | 0 | m_choices.value().push_back( |
900 | 0 | std::string{std::string_view{std::forward<T>(choice)}}); |
901 | | } else if constexpr (details::can_invoke_to_string<T>::value) { |
902 | | m_choices.value().push_back(std::to_string(std::forward<T>(choice))); |
903 | | } |
904 | 0 | } |
905 | | |
906 | 0 | Argument &choices() { |
907 | 0 | if (!m_choices.has_value()) { |
908 | 0 | throw std::runtime_error("Zero choices provided"); |
909 | 0 | } |
910 | 0 | return *this; |
911 | 0 | } |
912 | | |
913 | | template <typename T, typename... U> |
914 | 0 | Argument &choices(T &&first, U &&... rest) { |
915 | 0 | add_choice(std::forward<T>(first)); |
916 | 0 | choices(std::forward<U>(rest)...); |
917 | 0 | return *this; |
918 | 0 | } Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::choices<char const (&) [2], char const (&) [2], char const (&) [2]>(char const (&) [2], char const (&) [2], char const (&) [2]) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::choices<char const (&) [2], char const (&) [2]>(char const (&) [2], char const (&) [2]) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::Argument::choices<char const (&) [2]>(char const (&) [2]) |
919 | | |
920 | 0 | void find_default_value_in_choices_or_throw() const { |
921 | |
|
922 | 0 | const auto &choices = m_choices.value(); |
923 | |
|
924 | 0 | if (m_default_value.has_value()) { |
925 | 0 | if (std::find(choices.begin(), choices.end(), m_default_value_str) == |
926 | 0 | choices.end()) { |
927 | | // provided arg not in list of allowed choices |
928 | | // report error |
929 | |
|
930 | 0 | std::string choices_as_csv = |
931 | 0 | std::accumulate(choices.begin(), choices.end(), std::string(), |
932 | 0 | [](const std::string &a, const std::string &b) { |
933 | 0 | return a + (a.empty() ? "" : ", ") + b; |
934 | 0 | }); |
935 | |
|
936 | 0 | throw std::runtime_error( |
937 | 0 | std::string{"Invalid default value "} + m_default_value_repr + |
938 | 0 | " - allowed options: {" + choices_as_csv + "}"); |
939 | 0 | } |
940 | 0 | } |
941 | 0 | } |
942 | | |
943 | | template <typename Iterator> |
944 | 0 | void find_value_in_choices_or_throw(Iterator it) const { |
945 | |
|
946 | 0 | const auto &choices = m_choices.value(); |
947 | |
|
948 | 0 | if (std::find(choices.begin(), choices.end(), *it) == choices.end()) { |
949 | | // provided arg not in list of allowed choices |
950 | | // report error |
951 | |
|
952 | 0 | std::string choices_as_csv = |
953 | 0 | std::accumulate(choices.begin(), choices.end(), std::string(), |
954 | 0 | [](const std::string &a, const std::string &b) { |
955 | 0 | return a + (a.empty() ? "" : ", ") + b; |
956 | 0 | }); |
957 | |
|
958 | 0 | throw std::runtime_error(std::string{"Invalid argument "} + |
959 | 0 | details::repr(*it) + " - allowed options: {" + |
960 | 0 | choices_as_csv + "}"); |
961 | 0 | } |
962 | 0 | } |
963 | | |
964 | | /* The dry_run parameter can be set to true to avoid running the actions, |
965 | | * and setting m_is_used. This may be used by a pre-processing step to do |
966 | | * a first iteration over arguments. |
967 | | */ |
968 | | template <typename Iterator> |
969 | | Iterator consume(Iterator start, Iterator end, |
970 | 0 | std::string_view used_name = {}, bool dry_run = false) { |
971 | 0 | if (!m_is_repeatable && m_is_used) { |
972 | 0 | throw std::runtime_error( |
973 | 0 | std::string("Duplicate argument ").append(used_name)); |
974 | 0 | } |
975 | 0 | m_used_name = used_name; |
976 | |
|
977 | 0 | if (m_choices.has_value()) { |
978 | | // Check each value in (start, end) and make sure |
979 | | // it is in the list of allowed choices/options |
980 | 0 | std::size_t i = 0; |
981 | 0 | auto max_number_of_args = m_num_args_range.get_max(); |
982 | 0 | for (auto it = start; it != end; ++it) { |
983 | 0 | if (i == max_number_of_args) { |
984 | 0 | break; |
985 | 0 | } |
986 | 0 | find_value_in_choices_or_throw(it); |
987 | 0 | i += 1; |
988 | 0 | } |
989 | 0 | } |
990 | |
|
991 | 0 | const auto num_args_max = m_num_args_range.get_max(); |
992 | 0 | const auto num_args_min = m_num_args_range.get_min(); |
993 | 0 | std::size_t dist = 0; |
994 | 0 | if (num_args_max == 0) { |
995 | 0 | if (!dry_run) { |
996 | 0 | m_values.emplace_back(m_implicit_value); |
997 | 0 | for(auto &action: m_actions) { |
998 | 0 | std::visit([&](const auto &f) { f({}); }, action); Unexecuted instantiation: auto gdal_argparse::Argument::consume<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::basic_string_view<char, std::__1::char_traits<char> >, bool)::{lambda(auto:1 const&)#1}::operator()<std::__1::function<std::__1::any (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> >(std::__1::function<std::__1::any (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> const&) const Unexecuted instantiation: auto gdal_argparse::Argument::consume<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::basic_string_view<char, std::__1::char_traits<char> >, bool)::{lambda(auto:1 const&)#1}::operator()<std::__1::function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> >(std::__1::function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> const&) const |
999 | 0 | } |
1000 | 0 | if(m_actions.empty()){ |
1001 | 0 | std::visit([&](const auto &f) { f({}); }, m_default_action); Unexecuted instantiation: auto gdal_argparse::Argument::consume<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::basic_string_view<char, std::__1::char_traits<char> >, bool)::{lambda(auto:1 const&)#2}::operator()<std::__1::function<std::__1::any (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> >(std::__1::function<std::__1::any (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> const&) const Unexecuted instantiation: auto gdal_argparse::Argument::consume<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*> >(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::basic_string_view<char, std::__1::char_traits<char> >, bool)::{lambda(auto:1 const&)#2}::operator()<std::__1::function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> >(std::__1::function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> const&) const |
1002 | 0 | } |
1003 | 0 | m_is_used = true; |
1004 | 0 | } |
1005 | 0 | return start; |
1006 | 0 | } |
1007 | 0 | if ((dist = static_cast<std::size_t>(std::distance(start, end))) >= |
1008 | 0 | num_args_min) { |
1009 | 0 | if (num_args_max < dist) { |
1010 | 0 | end = std::next(start, num_args_max); |
1011 | 0 | } |
1012 | 0 | if (!m_accepts_optional_like_value) { |
1013 | 0 | end = std::find_if( |
1014 | 0 | start, end, |
1015 | 0 | std::bind(is_optional, std::placeholders::_1, m_prefix_chars)); |
1016 | 0 | dist = static_cast<std::size_t>(std::distance(start, end)); |
1017 | 0 | if (dist < num_args_min) { |
1018 | 0 | throw std::runtime_error("Too few arguments for '" + |
1019 | 0 | std::string(m_used_name) + "'."); |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | 0 | struct ActionApply { |
1024 | 0 | void operator()(valued_action &f) { |
1025 | 0 | std::transform(first, last, std::back_inserter(self.m_values), f); |
1026 | 0 | } |
1027 | |
|
1028 | 0 | void operator()(void_action &f) { |
1029 | 0 | std::for_each(first, last, f); |
1030 | 0 | if (!self.m_default_value.has_value()) { |
1031 | 0 | if (!self.m_accepts_optional_like_value) { |
1032 | 0 | self.m_values.resize( |
1033 | 0 | static_cast<std::size_t>(std::distance(first, last))); |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | } |
1037 | |
|
1038 | 0 | Iterator first, last; |
1039 | 0 | Argument &self; |
1040 | 0 | }; |
1041 | 0 | if (!dry_run) { |
1042 | 0 | for(auto &action: m_actions) { |
1043 | 0 | std::visit(ActionApply{start, end, *this}, action); |
1044 | 0 | } |
1045 | 0 | if(m_actions.empty()){ |
1046 | 0 | std::visit(ActionApply{start, end, *this}, m_default_action); |
1047 | 0 | } |
1048 | 0 | m_is_used = true; |
1049 | 0 | } |
1050 | 0 | return end; |
1051 | 0 | } |
1052 | 0 | if (m_default_value.has_value()) { |
1053 | 0 | if (!dry_run) { |
1054 | 0 | m_is_used = true; |
1055 | 0 | } |
1056 | 0 | return start; |
1057 | 0 | } |
1058 | 0 | throw std::runtime_error("Too few arguments for '" + |
1059 | 0 | std::string(m_used_name) + "'."); |
1060 | 0 | } |
1061 | | |
1062 | | /* |
1063 | | * @throws std::runtime_error if argument values are not valid |
1064 | | */ |
1065 | 0 | void validate() const { |
1066 | 0 | if (m_is_optional) { |
1067 | | // TODO: check if an implicit value was programmed for this argument |
1068 | 0 | if (!m_is_used && !m_default_value.has_value() && m_is_required) { |
1069 | 0 | throw_required_arg_not_used_error(); |
1070 | 0 | } |
1071 | 0 | if (m_is_used && m_is_required && m_values.empty()) { |
1072 | 0 | throw_required_arg_no_value_provided_error(); |
1073 | 0 | } |
1074 | 0 | } else { |
1075 | 0 | if (!m_num_args_range.contains(m_values.size()) && |
1076 | 0 | !m_default_value.has_value()) { |
1077 | 0 | throw_nargs_range_validation_error(); |
1078 | 0 | } |
1079 | 0 | } |
1080 | |
|
1081 | 0 | if (m_choices.has_value()) { |
1082 | | // Make sure the default value (if provided) |
1083 | | // is in the list of choices |
1084 | 0 | find_default_value_in_choices_or_throw(); |
1085 | 0 | } |
1086 | 0 | } |
1087 | | |
1088 | 0 | std::string get_names_csv(char separator = ',') const { |
1089 | 0 | return std::accumulate( |
1090 | 0 | m_names.begin(), m_names.end(), std::string{""}, |
1091 | 0 | [&](const std::string &result, const std::string &name) { |
1092 | 0 | return result.empty() ? name : result + separator + name; |
1093 | 0 | }); |
1094 | 0 | } |
1095 | | |
1096 | 0 | std::string get_usage_full() const { |
1097 | 0 | std::stringstream usage; |
1098 | |
|
1099 | 0 | usage << get_names_csv('/'); |
1100 | 0 | const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; |
1101 | 0 | if (m_num_args_range.get_max() > 0) { |
1102 | 0 | usage << " " << metavar; |
1103 | 0 | if (m_num_args_range.get_max() > 1) { |
1104 | 0 | usage << "..."; |
1105 | 0 | } |
1106 | 0 | } |
1107 | 0 | return usage.str(); |
1108 | 0 | } |
1109 | | |
1110 | 0 | std::string get_inline_usage() const { |
1111 | 0 | std::stringstream usage; |
1112 | | // Find the longest variant to show in the usage string |
1113 | 0 | std::string longest_name = m_names.front(); |
1114 | 0 | for (const auto &s : m_names) { |
1115 | 0 | if (s.size() > longest_name.size()) { |
1116 | 0 | longest_name = s; |
1117 | 0 | } |
1118 | 0 | } |
1119 | 0 | if (!m_is_required) { |
1120 | 0 | usage << "["; |
1121 | 0 | } |
1122 | 0 | usage << longest_name; |
1123 | 0 | const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; |
1124 | 0 | if (m_num_args_range.get_max() > 0) { |
1125 | 0 | usage << " " << metavar; |
1126 | 0 | if (m_num_args_range.get_max() > 1 && |
1127 | 0 | m_metavar.find("> <") == std::string::npos) { |
1128 | 0 | usage << "..."; |
1129 | 0 | } |
1130 | 0 | } |
1131 | 0 | if (!m_is_required) { |
1132 | 0 | usage << "]"; |
1133 | 0 | } |
1134 | 0 | if (m_is_repeatable) { |
1135 | 0 | usage << "..."; |
1136 | 0 | } |
1137 | 0 | return usage.str(); |
1138 | 0 | } |
1139 | | |
1140 | 0 | std::size_t get_arguments_length() const { |
1141 | |
|
1142 | 0 | std::size_t names_size = std::accumulate( |
1143 | 0 | std::begin(m_names), std::end(m_names), std::size_t(0), |
1144 | 0 | [](const auto &sum, const auto &s) { return sum + s.size(); }); |
1145 | |
|
1146 | 0 | if (is_positional(m_names.front(), m_prefix_chars)) { |
1147 | | // A set metavar means this replaces the names |
1148 | 0 | if (!m_metavar.empty()) { |
1149 | | // Indent and metavar |
1150 | 0 | return 2 + m_metavar.size(); |
1151 | 0 | } |
1152 | | |
1153 | | // Indent and space-separated |
1154 | 0 | return 2 + names_size + (m_names.size() - 1); |
1155 | 0 | } |
1156 | | // Is an option - include both names _and_ metavar |
1157 | | // size = text + (", " between names) |
1158 | 0 | std::size_t size = names_size + 2 * (m_names.size() - 1); |
1159 | 0 | if (!m_metavar.empty() && m_num_args_range == NArgsRange{1, 1}) { |
1160 | 0 | size += m_metavar.size() + 1; |
1161 | 0 | } |
1162 | 0 | return size + 2; // indent |
1163 | 0 | } |
1164 | | |
1165 | | friend std::ostream &operator<<(std::ostream &stream, |
1166 | 0 | const Argument &argument) { |
1167 | 0 | std::stringstream name_stream; |
1168 | 0 | name_stream << " "; // indent |
1169 | 0 | if (argument.is_positional(argument.m_names.front(), |
1170 | 0 | argument.m_prefix_chars)) { |
1171 | 0 | if (!argument.m_metavar.empty()) { |
1172 | 0 | name_stream << argument.m_metavar; |
1173 | 0 | } else { |
1174 | 0 | name_stream << details::join(argument.m_names.begin(), |
1175 | 0 | argument.m_names.end(), " "); |
1176 | 0 | } |
1177 | 0 | } else { |
1178 | 0 | name_stream << details::join(argument.m_names.begin(), |
1179 | 0 | argument.m_names.end(), ", "); |
1180 | | // If we have a metavar, and one narg - print the metavar |
1181 | 0 | if (!argument.m_metavar.empty() && |
1182 | 0 | argument.m_num_args_range == NArgsRange{1, 1}) { |
1183 | 0 | name_stream << " " << argument.m_metavar; |
1184 | 0 | } |
1185 | 0 | else if (!argument.m_metavar.empty() && |
1186 | 0 | argument.m_num_args_range.get_min() == argument.m_num_args_range.get_max() && |
1187 | 0 | argument.m_metavar.find("> <") != std::string::npos) { |
1188 | 0 | name_stream << " " << argument.m_metavar; |
1189 | 0 | } |
1190 | 0 | } |
1191 | | |
1192 | | // align multiline help message |
1193 | 0 | auto stream_width = stream.width(); |
1194 | 0 | auto name_padding = std::string(name_stream.str().size(), ' '); |
1195 | 0 | auto pos = std::string::size_type{}; |
1196 | 0 | auto prev = std::string::size_type{}; |
1197 | 0 | auto first_line = true; |
1198 | 0 | auto hspace = " "; // minimal space between name and help message |
1199 | 0 | stream << name_stream.str(); |
1200 | 0 | std::string_view help_view(argument.m_help); |
1201 | 0 | while ((pos = argument.m_help.find('\n', prev)) != std::string::npos) { |
1202 | 0 | auto line = help_view.substr(prev, pos - prev + 1); |
1203 | 0 | if (first_line) { |
1204 | 0 | stream << hspace << line; |
1205 | 0 | first_line = false; |
1206 | 0 | } else { |
1207 | 0 | stream.width(stream_width); |
1208 | 0 | stream << name_padding << hspace << line; |
1209 | 0 | } |
1210 | 0 | prev += pos - prev + 1; |
1211 | 0 | } |
1212 | 0 | if (first_line) { |
1213 | 0 | stream << hspace << argument.m_help; |
1214 | 0 | } else { |
1215 | 0 | auto leftover = help_view.substr(prev, argument.m_help.size() - prev); |
1216 | 0 | if (!leftover.empty()) { |
1217 | 0 | stream.width(stream_width); |
1218 | 0 | stream << name_padding << hspace << leftover; |
1219 | 0 | } |
1220 | 0 | } |
1221 | | |
1222 | | // print nargs spec |
1223 | 0 | if (!argument.m_help.empty()) { |
1224 | 0 | stream << " "; |
1225 | 0 | } |
1226 | 0 | stream << argument.m_num_args_range; |
1227 | |
|
1228 | 0 | bool add_space = false; |
1229 | 0 | if (argument.m_default_value.has_value() && |
1230 | 0 | argument.m_num_args_range != NArgsRange{0, 0}) { |
1231 | 0 | stream << "[default: " << argument.m_default_value_repr << "]"; |
1232 | 0 | add_space = true; |
1233 | 0 | } else if (argument.m_is_required) { |
1234 | 0 | stream << "[required]"; |
1235 | 0 | add_space = true; |
1236 | 0 | } |
1237 | 0 | if (argument.m_is_repeatable) { |
1238 | 0 | if (add_space) { |
1239 | 0 | stream << " "; |
1240 | 0 | } |
1241 | 0 | stream << "[may be repeated]"; |
1242 | 0 | } |
1243 | 0 | stream << "\n"; |
1244 | 0 | return stream; |
1245 | 0 | } |
1246 | | |
1247 | | template <typename T> bool operator!=(const T &rhs) const { |
1248 | | return !(*this == rhs); |
1249 | | } |
1250 | | |
1251 | | /* |
1252 | | * Compare to an argument value of known type |
1253 | | * @throws std::logic_error in case of incompatible types |
1254 | | */ |
1255 | | template <typename T> bool operator==(const T &rhs) const { |
1256 | | if constexpr (!details::IsContainer<T>) { |
1257 | | return get<T>() == rhs; |
1258 | | } else { |
1259 | | using ValueType = typename T::value_type; |
1260 | | auto lhs = get<T>(); |
1261 | | return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), |
1262 | | std::end(rhs), [](const auto &a, const auto &b) { |
1263 | | return std::any_cast<const ValueType &>(a) == b; |
1264 | | }); |
1265 | | } |
1266 | | } |
1267 | | |
1268 | | /* |
1269 | | * positional: |
1270 | | * _empty_ |
1271 | | * '-' |
1272 | | * '-' decimal-literal |
1273 | | * !'-' anything |
1274 | | */ |
1275 | | static bool is_positional(std::string_view name, |
1276 | 0 | std::string_view prefix_chars) { |
1277 | 0 | auto first = lookahead(name); |
1278 | |
|
1279 | 0 | if (first == eof) { |
1280 | 0 | return true; |
1281 | 0 | } |
1282 | 0 | if (prefix_chars.find(static_cast<char>(first)) != |
1283 | 0 | std::string_view::npos) { |
1284 | 0 | name.remove_prefix(1); |
1285 | 0 | if (name.empty()) { |
1286 | 0 | return true; |
1287 | 0 | } |
1288 | 0 | return is_decimal_literal(name); |
1289 | 0 | } |
1290 | 0 | return true; |
1291 | 0 | } |
1292 | | |
1293 | | private: |
1294 | | class NArgsRange { |
1295 | | std::size_t m_min; |
1296 | | std::size_t m_max; |
1297 | | |
1298 | | public: |
1299 | | NArgsRange(std::size_t minimum, std::size_t maximum) |
1300 | 0 | : m_min(minimum), m_max(maximum) { |
1301 | 0 | if (minimum > maximum) { |
1302 | 0 | throw std::logic_error("Range of number of arguments is invalid"); |
1303 | 0 | } |
1304 | 0 | } |
1305 | | |
1306 | 0 | bool contains(std::size_t value) const { |
1307 | 0 | return value >= m_min && value <= m_max; |
1308 | 0 | } |
1309 | | |
1310 | 0 | bool is_exact() const { return m_min == m_max; } |
1311 | | |
1312 | 0 | bool is_right_bounded() const { |
1313 | 0 | return m_max < (std::numeric_limits<std::size_t>::max)(); |
1314 | 0 | } |
1315 | | |
1316 | 0 | std::size_t get_min() const { return m_min; } |
1317 | | |
1318 | 0 | std::size_t get_max() const { return m_max; } |
1319 | | |
1320 | | // Print help message |
1321 | | friend auto operator<<(std::ostream &stream, const NArgsRange &range) |
1322 | 0 | -> std::ostream & { |
1323 | 0 | if (range.m_min == range.m_max) { |
1324 | 0 | if (range.m_min != 0 && range.m_min != 1) { |
1325 | 0 | stream << "[nargs: " << range.m_min << "] "; |
1326 | 0 | } |
1327 | 0 | } else { |
1328 | 0 | if (range.m_max == (std::numeric_limits<std::size_t>::max)()) { |
1329 | 0 | stream << "[nargs: " << range.m_min << " or more] "; |
1330 | 0 | } else { |
1331 | 0 | stream << "[nargs=" << range.m_min << ".." << range.m_max << "] "; |
1332 | 0 | } |
1333 | 0 | } |
1334 | 0 | return stream; |
1335 | 0 | } |
1336 | | |
1337 | 0 | bool operator==(const NArgsRange &rhs) const { |
1338 | 0 | return rhs.m_min == m_min && rhs.m_max == m_max; |
1339 | 0 | } |
1340 | | |
1341 | 0 | bool operator!=(const NArgsRange &rhs) const { return !(*this == rhs); } |
1342 | | }; |
1343 | | |
1344 | 0 | void throw_nargs_range_validation_error() const { |
1345 | 0 | std::stringstream stream; |
1346 | 0 | if (!m_used_name.empty()) { |
1347 | 0 | stream << m_used_name << ": "; |
1348 | 0 | } else { |
1349 | 0 | stream << m_names.front() << ": "; |
1350 | 0 | } |
1351 | 0 | if (m_num_args_range.is_exact()) { |
1352 | 0 | stream << m_num_args_range.get_min(); |
1353 | 0 | } else if (m_num_args_range.is_right_bounded()) { |
1354 | 0 | stream << m_num_args_range.get_min() << " to " |
1355 | 0 | << m_num_args_range.get_max(); |
1356 | 0 | } else { |
1357 | 0 | stream << m_num_args_range.get_min() << " or more"; |
1358 | 0 | } |
1359 | 0 | stream << " argument(s) expected. " << m_values.size() << " provided."; |
1360 | 0 | throw std::runtime_error(stream.str()); |
1361 | 0 | } |
1362 | | |
1363 | 0 | void throw_required_arg_not_used_error() const { |
1364 | 0 | std::stringstream stream; |
1365 | 0 | stream << m_names.front() << ": required."; |
1366 | 0 | throw std::runtime_error(stream.str()); |
1367 | 0 | } |
1368 | | |
1369 | 0 | void throw_required_arg_no_value_provided_error() const { |
1370 | 0 | std::stringstream stream; |
1371 | 0 | stream << m_used_name << ": no value provided."; |
1372 | 0 | throw std::runtime_error(stream.str()); |
1373 | 0 | } |
1374 | | |
1375 | | static constexpr int eof = std::char_traits<char>::eof(); |
1376 | | |
1377 | 0 | static auto lookahead(std::string_view s) -> int { |
1378 | 0 | if (s.empty()) { |
1379 | 0 | return eof; |
1380 | 0 | } |
1381 | 0 | return static_cast<int>(static_cast<unsigned char>(s[0])); |
1382 | 0 | } |
1383 | | |
1384 | | /* |
1385 | | * decimal-literal: |
1386 | | * '0' |
1387 | | * nonzero-digit digit-sequence_opt |
1388 | | * integer-part fractional-part |
1389 | | * fractional-part |
1390 | | * integer-part '.' exponent-part_opt |
1391 | | * integer-part exponent-part |
1392 | | * |
1393 | | * integer-part: |
1394 | | * digit-sequence |
1395 | | * |
1396 | | * fractional-part: |
1397 | | * '.' post-decimal-point |
1398 | | * |
1399 | | * post-decimal-point: |
1400 | | * digit-sequence exponent-part_opt |
1401 | | * |
1402 | | * exponent-part: |
1403 | | * 'e' post-e |
1404 | | * 'E' post-e |
1405 | | * |
1406 | | * post-e: |
1407 | | * sign_opt digit-sequence |
1408 | | * |
1409 | | * sign: one of |
1410 | | * '+' '-' |
1411 | | */ |
1412 | 0 | static bool is_decimal_literal(std::string_view s) { |
1413 | 0 | if (s == "inf") { |
1414 | 0 | return true; |
1415 | 0 | } |
1416 | | |
1417 | 0 | auto is_digit = [](auto c) constexpr { |
1418 | 0 | switch (c) { |
1419 | 0 | case '0': |
1420 | 0 | case '1': |
1421 | 0 | case '2': |
1422 | 0 | case '3': |
1423 | 0 | case '4': |
1424 | 0 | case '5': |
1425 | 0 | case '6': |
1426 | 0 | case '7': |
1427 | 0 | case '8': |
1428 | 0 | case '9': |
1429 | 0 | return true; |
1430 | 0 | default: |
1431 | 0 | return false; |
1432 | 0 | } |
1433 | 0 | }; Unexecuted instantiation: auto gdal_argparse::Argument::is_decimal_literal(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(auto:1)#1}::operator()<char>(char) const Unexecuted instantiation: auto gdal_argparse::Argument::is_decimal_literal(std::__1::basic_string_view<char, std::__1::char_traits<char> >)::{lambda(auto:1)#1}::operator()<int>(int) const |
1434 | | |
1435 | | // precondition: we have consumed or will consume at least one digit |
1436 | 0 | auto consume_digits = [=](std::string_view sd) { |
1437 | | // NOLINTNEXTLINE(readability-qualified-auto) |
1438 | 0 | auto it = std::find_if_not(std::begin(sd), std::end(sd), is_digit); |
1439 | 0 | return sd.substr(static_cast<std::size_t>(it - std::begin(sd))); |
1440 | 0 | }; |
1441 | |
|
1442 | 0 | switch (lookahead(s)) { |
1443 | 0 | case '0': { |
1444 | 0 | s.remove_prefix(1); |
1445 | 0 | if (s.empty()) { |
1446 | 0 | return true; |
1447 | 0 | } |
1448 | 0 | goto integer_part; |
1449 | 0 | } |
1450 | 0 | case '1': |
1451 | 0 | case '2': |
1452 | 0 | case '3': |
1453 | 0 | case '4': |
1454 | 0 | case '5': |
1455 | 0 | case '6': |
1456 | 0 | case '7': |
1457 | 0 | case '8': |
1458 | 0 | case '9': { |
1459 | 0 | s = consume_digits(s); |
1460 | 0 | if (s.empty()) { |
1461 | 0 | return true; |
1462 | 0 | } |
1463 | 0 | goto integer_part_consumed; |
1464 | 0 | } |
1465 | 0 | case '.': { |
1466 | 0 | s.remove_prefix(1); |
1467 | 0 | goto post_decimal_point; |
1468 | 0 | } |
1469 | 0 | default: |
1470 | 0 | return false; |
1471 | 0 | } |
1472 | | |
1473 | 0 | integer_part: |
1474 | 0 | s = consume_digits(s); |
1475 | 0 | integer_part_consumed: |
1476 | 0 | switch (lookahead(s)) { |
1477 | 0 | case '.': { |
1478 | 0 | s.remove_prefix(1); |
1479 | 0 | if (is_digit(lookahead(s))) { |
1480 | 0 | goto post_decimal_point; |
1481 | 0 | } else { |
1482 | 0 | goto exponent_part_opt; |
1483 | 0 | } |
1484 | 0 | } |
1485 | 0 | case 'e': |
1486 | 0 | case 'E': { |
1487 | 0 | s.remove_prefix(1); |
1488 | 0 | goto post_e; |
1489 | 0 | } |
1490 | 0 | default: |
1491 | 0 | return false; |
1492 | 0 | } |
1493 | | |
1494 | 0 | post_decimal_point: |
1495 | 0 | if (is_digit(lookahead(s))) { |
1496 | 0 | s = consume_digits(s); |
1497 | 0 | goto exponent_part_opt; |
1498 | 0 | } |
1499 | 0 | return false; |
1500 | | |
1501 | 0 | exponent_part_opt: |
1502 | 0 | switch (lookahead(s)) { |
1503 | 0 | case eof: |
1504 | 0 | return true; |
1505 | 0 | case 'e': |
1506 | 0 | case 'E': { |
1507 | 0 | s.remove_prefix(1); |
1508 | 0 | goto post_e; |
1509 | 0 | } |
1510 | 0 | default: |
1511 | 0 | return false; |
1512 | 0 | } |
1513 | | |
1514 | 0 | post_e: |
1515 | 0 | switch (lookahead(s)) { |
1516 | 0 | case '-': |
1517 | 0 | case '+': |
1518 | 0 | s.remove_prefix(1); |
1519 | 0 | } |
1520 | 0 | if (is_digit(lookahead(s))) { |
1521 | 0 | s = consume_digits(s); |
1522 | 0 | return s.empty(); |
1523 | 0 | } |
1524 | 0 | return false; |
1525 | 0 | } |
1526 | | |
1527 | | static bool is_optional(std::string_view name, |
1528 | 0 | std::string_view prefix_chars) { |
1529 | 0 | return !is_positional(name, prefix_chars); |
1530 | 0 | } |
1531 | | |
1532 | | /* |
1533 | | * Get argument value given a type |
1534 | | * @throws std::logic_error in case of incompatible types |
1535 | | */ |
1536 | | template <typename T> T get() const { |
1537 | | if (!m_values.empty()) { |
1538 | | if constexpr (details::IsContainer<T>) { |
1539 | | return any_cast_container<T>(m_values); |
1540 | | } else { |
1541 | | return std::any_cast<T>(m_values.front()); |
1542 | | } |
1543 | | } |
1544 | | if (m_default_value.has_value()) { |
1545 | | return std::any_cast<T>(m_default_value); |
1546 | | } |
1547 | | if constexpr (details::IsContainer<T>) { |
1548 | | if (!m_accepts_optional_like_value) { |
1549 | | return any_cast_container<T>(m_values); |
1550 | | } |
1551 | | } |
1552 | | |
1553 | | throw std::logic_error("No value provided for '" + m_names.back() + "'."); |
1554 | | } |
1555 | | |
1556 | | /* |
1557 | | * Get argument value given a type. |
1558 | | * @pre The object has no default value. |
1559 | | * @returns The stored value if any, std::nullopt otherwise. |
1560 | | */ |
1561 | 0 | template <typename T> auto present() const -> std::optional<T> { |
1562 | 0 | if (m_default_value.has_value()) { |
1563 | 0 | throw std::logic_error("Argument with default value always presents"); |
1564 | 0 | } |
1565 | 0 | if (m_values.empty()) { |
1566 | 0 | return std::nullopt; |
1567 | 0 | } |
1568 | 0 | if constexpr (details::IsContainer<T>) { |
1569 | 0 | return any_cast_container<T>(m_values); |
1570 | 0 | } |
1571 | 0 | return std::any_cast<T>(m_values.front()); |
1572 | 0 | } Unexecuted instantiation: std::__1::optional<std::__1::vector<double, std::__1::allocator<double> > > gdal_argparse::Argument::present<std::__1::vector<double, std::__1::allocator<double> > >() const Unexecuted instantiation: std::__1::optional<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > gdal_argparse::Argument::present<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >() const Unexecuted instantiation: std::__1::optional<std::__1::vector<int, std::__1::allocator<int> > > gdal_argparse::Argument::present<std::__1::vector<int, std::__1::allocator<int> > >() const |
1573 | | |
1574 | | template <typename T> |
1575 | 0 | static auto any_cast_container(const std::vector<std::any> &operand) -> T { |
1576 | 0 | using ValueType = typename T::value_type; |
1577 | |
|
1578 | 0 | T result; |
1579 | 0 | std::transform( |
1580 | 0 | std::begin(operand), std::end(operand), std::back_inserter(result), |
1581 | 0 | [](const auto &value) { return std::any_cast<ValueType>(value); }); Unexecuted instantiation: auto gdal_argparse::Argument::any_cast_container<std::__1::vector<double, std::__1::allocator<double> > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&)::{lambda(auto:1 const&)#1}::operator()<std::__1::any>(std::__1::any const&) const Unexecuted instantiation: auto gdal_argparse::Argument::any_cast_container<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&)::{lambda(auto:1 const&)#1}::operator()<std::__1::any>(std::__1::any const&) const Unexecuted instantiation: auto gdal_argparse::Argument::any_cast_container<std::__1::vector<int, std::__1::allocator<int> > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&)::{lambda(auto:1 const&)#1}::operator()<std::__1::any>(std::__1::any const&) const |
1582 | 0 | return result; |
1583 | 0 | } Unexecuted instantiation: std::__1::vector<double, std::__1::allocator<double> > gdal_argparse::Argument::any_cast_container<std::__1::vector<double, std::__1::allocator<double> > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&) Unexecuted instantiation: std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > gdal_argparse::Argument::any_cast_container<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&) Unexecuted instantiation: std::__1::vector<int, std::__1::allocator<int> > gdal_argparse::Argument::any_cast_container<std::__1::vector<int, std::__1::allocator<int> > >(std::__1::vector<std::__1::any, std::__1::allocator<std::__1::any> > const&) |
1584 | | |
1585 | 0 | void set_usage_newline_counter(int i) { m_usage_newline_counter = i; } |
1586 | | |
1587 | 0 | void set_group_idx(std::size_t i) { m_group_idx = i; } |
1588 | | |
1589 | | std::vector<std::string> m_names; |
1590 | | std::string_view m_used_name; |
1591 | | std::string m_help; |
1592 | | std::string m_metavar; |
1593 | | std::any m_default_value; |
1594 | | std::string m_default_value_repr; |
1595 | | std::optional<std::string> |
1596 | | m_default_value_str; // used for checking default_value against choices |
1597 | | std::any m_implicit_value; |
1598 | | std::optional<std::vector<std::string>> m_choices{std::nullopt}; |
1599 | | using valued_action = std::function<std::any(const std::string &)>; |
1600 | | using void_action = std::function<void(const std::string &)>; |
1601 | | std::vector<std::variant<valued_action, void_action>> m_actions; |
1602 | | std::variant<valued_action, void_action> m_default_action{ |
1603 | | std::in_place_type<valued_action>, |
1604 | 0 | [](const std::string &value) { return value; }}; |
1605 | | std::vector<std::any> m_values; |
1606 | | NArgsRange m_num_args_range{1, 1}; |
1607 | | // Bit field of bool values. Set default value in ctor. |
1608 | | bool m_accepts_optional_like_value : 1; |
1609 | | bool m_is_optional : 1; |
1610 | | bool m_is_required : 1; |
1611 | | bool m_is_repeatable : 1; |
1612 | | bool m_is_used : 1; |
1613 | | bool m_is_hidden : 1; // if set, does not appear in usage or help |
1614 | | std::string_view m_prefix_chars; // ArgumentParser has the prefix_chars |
1615 | | int m_usage_newline_counter = 0; |
1616 | | std::size_t m_group_idx = 0; |
1617 | | }; |
1618 | | |
1619 | | class ArgumentParser { |
1620 | | public: |
1621 | | explicit ArgumentParser(std::string program_name = {}, |
1622 | | std::string version = "1.0", |
1623 | | default_arguments add_args = default_arguments::all, |
1624 | | bool exit_on_default_arguments = true, |
1625 | | std::ostream &os = std::cout) |
1626 | 0 | : m_program_name(std::move(program_name)), m_version(std::move(version)), |
1627 | 0 | m_exit_on_default_arguments(exit_on_default_arguments), |
1628 | 0 | m_parser_path(m_program_name) { |
1629 | 0 | if ((add_args & default_arguments::help) == default_arguments::help) { |
1630 | 0 | add_argument("-h", "--help") |
1631 | 0 | .action([&](const auto & /*unused*/) { |
1632 | 0 | os << help().str(); |
1633 | 0 | if (m_exit_on_default_arguments) { |
1634 | 0 | std::exit(0); |
1635 | 0 | } |
1636 | 0 | }) |
1637 | 0 | .default_value(false) |
1638 | 0 | .help("shows help message and exits") |
1639 | 0 | .implicit_value(true) |
1640 | 0 | .nargs(0); |
1641 | 0 | } |
1642 | 0 | if ((add_args & default_arguments::version) == default_arguments::version) { |
1643 | 0 | add_argument("-v", "--version") |
1644 | 0 | .action([&](const auto & /*unused*/) { |
1645 | 0 | os << m_version << std::endl; |
1646 | 0 | if (m_exit_on_default_arguments) { |
1647 | 0 | std::exit(0); |
1648 | 0 | } |
1649 | 0 | }) |
1650 | 0 | .default_value(false) |
1651 | 0 | .help("prints version information and exits") |
1652 | 0 | .implicit_value(true) |
1653 | 0 | .nargs(0); |
1654 | 0 | } |
1655 | 0 | } |
1656 | | |
1657 | 0 | ~ArgumentParser() = default; |
1658 | | |
1659 | | // ArgumentParser is meant to be used in a single function. |
1660 | | // Setup everything and parse arguments in one place. |
1661 | | // |
1662 | | // ArgumentParser internally uses std::string_views, |
1663 | | // references, iterators, etc. |
1664 | | // Many of these elements become invalidated after a copy or move. |
1665 | | ArgumentParser(const ArgumentParser &other) = delete; |
1666 | | ArgumentParser &operator=(const ArgumentParser &other) = delete; |
1667 | | ArgumentParser(ArgumentParser &&) noexcept = delete; |
1668 | | ArgumentParser &operator=(ArgumentParser &&) = delete; |
1669 | | |
1670 | 0 | explicit operator bool() const { |
1671 | 0 | auto arg_used = std::any_of(m_argument_map.cbegin(), m_argument_map.cend(), |
1672 | 0 | [](auto &it) { return it.second->m_is_used; }); |
1673 | 0 | auto subparser_used = |
1674 | 0 | std::any_of(m_subparser_used.cbegin(), m_subparser_used.cend(), |
1675 | 0 | [](auto &it) { return it.second; }); |
1676 | 0 |
|
1677 | 0 | return m_is_parsed && (arg_used || subparser_used); |
1678 | 0 | } |
1679 | | |
1680 | | // Parameter packing |
1681 | | // Call add_argument with variadic number of string arguments |
1682 | 0 | template <typename... Targs> Argument &add_argument(Targs... f_args) { |
1683 | 0 | using array_of_sv = std::array<std::string_view, sizeof...(Targs)>; |
1684 | 0 | auto argument = |
1685 | 0 | m_optional_arguments.emplace(std::cend(m_optional_arguments), |
1686 | 0 | m_prefix_chars, array_of_sv{f_args...}); |
1687 | |
|
1688 | 0 | if (!argument->m_is_optional) { |
1689 | 0 | m_positional_arguments.splice(std::cend(m_positional_arguments), |
1690 | 0 | m_optional_arguments, argument); |
1691 | 0 | } |
1692 | 0 | argument->set_usage_newline_counter(m_usage_newline_counter); |
1693 | 0 | argument->set_group_idx(m_group_names.size()); |
1694 | |
|
1695 | 0 | index_argument(argument); |
1696 | 0 | return *argument; |
1697 | 0 | } Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::ArgumentParser::add_argument<char const*>(char const*) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::ArgumentParser::add_argument<char const*, char const*>(char const*, char const*) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::ArgumentParser::add_argument<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) |
1698 | | |
1699 | | class MutuallyExclusiveGroup { |
1700 | | friend class ArgumentParser; |
1701 | | |
1702 | | public: |
1703 | | MutuallyExclusiveGroup() = delete; |
1704 | | |
1705 | | explicit MutuallyExclusiveGroup(ArgumentParser &parent, |
1706 | | bool required = false) |
1707 | 0 | : m_parent(parent), m_required(required), m_elements({}) {} |
1708 | | |
1709 | | MutuallyExclusiveGroup(const MutuallyExclusiveGroup &other) = delete; |
1710 | | MutuallyExclusiveGroup & |
1711 | | operator=(const MutuallyExclusiveGroup &other) = delete; |
1712 | | |
1713 | | MutuallyExclusiveGroup(MutuallyExclusiveGroup &&other) noexcept |
1714 | 0 | : m_parent(other.m_parent), m_required(other.m_required), |
1715 | 0 | m_elements(std::move(other.m_elements)) { |
1716 | 0 | other.m_elements.clear(); |
1717 | 0 | } |
1718 | | |
1719 | 0 | template <typename... Targs> Argument &add_argument(Targs... f_args) { |
1720 | 0 | auto &argument = m_parent.add_argument(std::forward<Targs>(f_args)...); |
1721 | 0 | m_elements.push_back(&argument); |
1722 | 0 | argument.set_usage_newline_counter(m_parent.m_usage_newline_counter); |
1723 | 0 | argument.set_group_idx(m_parent.m_group_names.size()); |
1724 | 0 | return argument; |
1725 | 0 | } Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::ArgumentParser::MutuallyExclusiveGroup::add_argument<char const*>(char const*) Unexecuted instantiation: gdal_argparse::Argument& gdal_argparse::ArgumentParser::MutuallyExclusiveGroup::add_argument<char const*, char const*>(char const*, char const*) |
1726 | | |
1727 | | private: |
1728 | | ArgumentParser &m_parent; |
1729 | | bool m_required{false}; |
1730 | | std::vector<Argument *> m_elements{}; |
1731 | | }; |
1732 | | |
1733 | 0 | MutuallyExclusiveGroup &add_mutually_exclusive_group(bool required = false) { |
1734 | 0 | m_mutually_exclusive_groups.emplace_back(*this, required); |
1735 | 0 | return m_mutually_exclusive_groups.back(); |
1736 | 0 | } |
1737 | | |
1738 | | // Parameter packed add_parents method |
1739 | | // Accepts a variadic number of ArgumentParser objects |
1740 | | template <typename... Targs> |
1741 | | ArgumentParser &add_parents(const Targs &... f_args) { |
1742 | | for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) { |
1743 | | for (const auto &argument : parent_parser.m_positional_arguments) { |
1744 | | auto it = m_positional_arguments.insert( |
1745 | | std::cend(m_positional_arguments), argument); |
1746 | | index_argument(it); |
1747 | | } |
1748 | | for (const auto &argument : parent_parser.m_optional_arguments) { |
1749 | | auto it = m_optional_arguments.insert(std::cend(m_optional_arguments), |
1750 | | argument); |
1751 | | index_argument(it); |
1752 | | } |
1753 | | } |
1754 | | return *this; |
1755 | | } |
1756 | | |
1757 | | // Ask for the next optional arguments to be displayed on a separate |
1758 | | // line in usage() output. Only effective if set_usage_max_line_width() is |
1759 | | // also used. |
1760 | 0 | ArgumentParser &add_usage_newline() { |
1761 | 0 | ++m_usage_newline_counter; |
1762 | 0 | return *this; |
1763 | 0 | } |
1764 | | |
1765 | | // Ask for the next optional arguments to be displayed in a separate section |
1766 | | // in usage() and help (<< *this) output. |
1767 | | // For usage(), this is only effective if set_usage_max_line_width() is |
1768 | | // also used. |
1769 | 0 | ArgumentParser &add_group(std::string group_name) { |
1770 | 0 | m_group_names.emplace_back(std::move(group_name)); |
1771 | 0 | return *this; |
1772 | 0 | } |
1773 | | |
1774 | 0 | ArgumentParser &add_description(std::string description) { |
1775 | 0 | m_description = std::move(description); |
1776 | 0 | return *this; |
1777 | 0 | } |
1778 | | |
1779 | 0 | ArgumentParser &add_epilog(std::string epilog) { |
1780 | 0 | m_epilog = std::move(epilog); |
1781 | 0 | return *this; |
1782 | 0 | } |
1783 | | |
1784 | | // Add a un-documented/hidden alias for an argument. |
1785 | | // Ideally we'd want this to be a method of Argument, but Argument |
1786 | | // does not own its owing ArgumentParser. |
1787 | 0 | ArgumentParser &add_hidden_alias_for(Argument &arg, std::string_view alias) { |
1788 | 0 | for (auto it = m_optional_arguments.begin(); |
1789 | 0 | it != m_optional_arguments.end(); ++it) { |
1790 | 0 | if (&(*it) == &arg) { |
1791 | 0 | m_argument_map.insert_or_assign(std::string(alias), it); |
1792 | 0 | return *this; |
1793 | 0 | } |
1794 | 0 | } |
1795 | 0 | throw std::logic_error( |
1796 | 0 | "Argument is not an optional argument of this parser"); |
1797 | 0 | } |
1798 | | |
1799 | | /* Getter for arguments and subparsers. |
1800 | | * @throws std::logic_error in case of an invalid argument or subparser name |
1801 | | */ |
1802 | | template <typename T = Argument> T &at(std::string_view name) { |
1803 | | if constexpr (std::is_same_v<T, Argument>) { |
1804 | | return (*this)[name]; |
1805 | | } else { |
1806 | | std::string str_name(name); |
1807 | | auto subparser_it = m_subparser_map.find(str_name); |
1808 | | if (subparser_it != m_subparser_map.end()) { |
1809 | | return subparser_it->second->get(); |
1810 | | } |
1811 | | throw std::logic_error("No such subparser: " + str_name); |
1812 | | } |
1813 | | } |
1814 | | |
1815 | 0 | ArgumentParser &set_prefix_chars(std::string prefix_chars) { |
1816 | 0 | m_prefix_chars = std::move(prefix_chars); |
1817 | 0 | return *this; |
1818 | 0 | } |
1819 | | |
1820 | 0 | ArgumentParser &set_assign_chars(std::string assign_chars) { |
1821 | 0 | m_assign_chars = std::move(assign_chars); |
1822 | 0 | return *this; |
1823 | 0 | } |
1824 | | |
1825 | | /* Call parse_args_internal - which does all the work |
1826 | | * Then, validate the parsed arguments |
1827 | | * This variant is used mainly for testing |
1828 | | * @throws std::runtime_error in case of any invalid argument |
1829 | | */ |
1830 | 0 | void parse_args(const std::vector<std::string> &arguments) { |
1831 | 0 | parse_args_internal(arguments); |
1832 | | // Check if all arguments are parsed |
1833 | 0 | for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { |
1834 | 0 | argument->validate(); |
1835 | 0 | } |
1836 | | |
1837 | | // Check each mutually exclusive group and make sure |
1838 | | // there are no constraint violations |
1839 | 0 | for (const auto &group : m_mutually_exclusive_groups) { |
1840 | 0 | auto mutex_argument_used{false}; |
1841 | 0 | Argument *mutex_argument_it{nullptr}; |
1842 | 0 | for (Argument *arg : group.m_elements) { |
1843 | 0 | if (!mutex_argument_used && arg->m_is_used) { |
1844 | 0 | mutex_argument_used = true; |
1845 | 0 | mutex_argument_it = arg; |
1846 | 0 | } else if (mutex_argument_used && arg->m_is_used) { |
1847 | | // Violation |
1848 | 0 | throw std::runtime_error("Argument '" + arg->get_usage_full() + |
1849 | 0 | "' not allowed with '" + |
1850 | 0 | mutex_argument_it->get_usage_full() + "'"); |
1851 | 0 | } |
1852 | 0 | } |
1853 | | |
1854 | 0 | if (!mutex_argument_used && group.m_required) { |
1855 | | // at least one argument from the group is |
1856 | | // required |
1857 | 0 | std::string argument_names{}; |
1858 | 0 | std::size_t i = 0; |
1859 | 0 | std::size_t size = group.m_elements.size(); |
1860 | 0 | for (Argument *arg : group.m_elements) { |
1861 | 0 | if (i + 1 == size) { |
1862 | | // last |
1863 | 0 | argument_names += "'" + arg->get_usage_full() + "' "; |
1864 | 0 | } else { |
1865 | 0 | argument_names += "'" + arg->get_usage_full() + "' or "; |
1866 | 0 | } |
1867 | 0 | i += 1; |
1868 | 0 | } |
1869 | 0 | throw std::runtime_error("One of the arguments " + argument_names + |
1870 | 0 | "is required"); |
1871 | 0 | } |
1872 | 0 | } |
1873 | 0 | } |
1874 | | |
1875 | | /* Call parse_known_args_internal - which does all the work |
1876 | | * Then, validate the parsed arguments |
1877 | | * This variant is used mainly for testing |
1878 | | * @throws std::runtime_error in case of any invalid argument |
1879 | | */ |
1880 | | std::vector<std::string> |
1881 | 0 | parse_known_args(const std::vector<std::string> &arguments) { |
1882 | 0 | auto unknown_arguments = parse_known_args_internal(arguments); |
1883 | 0 | // Check if all arguments are parsed |
1884 | 0 | for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { |
1885 | 0 | argument->validate(); |
1886 | 0 | } |
1887 | 0 | return unknown_arguments; |
1888 | 0 | } |
1889 | | |
1890 | | /* Main entry point for parsing command-line arguments using this |
1891 | | * ArgumentParser |
1892 | | * @throws std::runtime_error in case of any invalid argument |
1893 | | */ |
1894 | | // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) |
1895 | 0 | void parse_args(int argc, const char *const argv[]) { |
1896 | 0 | parse_args({argv, argv + argc}); |
1897 | 0 | } |
1898 | | |
1899 | | /* Main entry point for parsing command-line arguments using this |
1900 | | * ArgumentParser |
1901 | | * @throws std::runtime_error in case of any invalid argument |
1902 | | */ |
1903 | | // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) |
1904 | 0 | auto parse_known_args(int argc, const char *const argv[]) { |
1905 | 0 | return parse_known_args({argv, argv + argc}); |
1906 | 0 | } |
1907 | | |
1908 | | /* Getter for options with default values. |
1909 | | * @throws std::logic_error if parse_args() has not been previously called |
1910 | | * @throws std::logic_error if there is no such option |
1911 | | * @throws std::logic_error if the option has no value |
1912 | | * @throws std::bad_any_cast if the option is not of type T |
1913 | | */ |
1914 | | template <typename T = std::string> T get(std::string_view arg_name) const { |
1915 | | if (!m_is_parsed) { |
1916 | | throw std::logic_error("Nothing parsed, no arguments are available."); |
1917 | | } |
1918 | | return (*this)[arg_name].get<T>(); |
1919 | | } |
1920 | | |
1921 | | /* Getter for options without default values. |
1922 | | * @pre The option has no default value. |
1923 | | * @throws std::logic_error if there is no such option |
1924 | | * @throws std::bad_any_cast if the option is not of type T |
1925 | | */ |
1926 | | template <typename T = std::string> |
1927 | 0 | auto present(std::string_view arg_name) const -> std::optional<T> { |
1928 | 0 | return (*this)[arg_name].present<T>(); |
1929 | 0 | } Unexecuted instantiation: std::__1::optional<std::__1::vector<double, std::__1::allocator<double> > > gdal_argparse::ArgumentParser::present<std::__1::vector<double, std::__1::allocator<double> > >(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const Unexecuted instantiation: std::__1::optional<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > gdal_argparse::ArgumentParser::present<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const Unexecuted instantiation: std::__1::optional<std::__1::vector<int, std::__1::allocator<int> > > gdal_argparse::ArgumentParser::present<std::__1::vector<int, std::__1::allocator<int> > >(std::__1::basic_string_view<char, std::__1::char_traits<char> >) const |
1930 | | |
1931 | | /* Getter that returns true for user-supplied options. Returns false if not |
1932 | | * user-supplied, even with a default value. |
1933 | | */ |
1934 | 0 | auto is_used(std::string_view arg_name) const { |
1935 | 0 | return (*this)[arg_name].m_is_used; |
1936 | 0 | } |
1937 | | |
1938 | | /* Getter that returns true if a subcommand is used. |
1939 | | */ |
1940 | 0 | auto is_subcommand_used(std::string_view subcommand_name) const { |
1941 | 0 | return m_subparser_used.at(std::string(subcommand_name)); |
1942 | 0 | } |
1943 | | |
1944 | | /* Getter that returns true if a subcommand is used. |
1945 | | */ |
1946 | 0 | auto is_subcommand_used(const ArgumentParser &subparser) const { |
1947 | 0 | return is_subcommand_used(subparser.m_program_name); |
1948 | 0 | } |
1949 | | |
1950 | | /* Indexing operator. Return a reference to an Argument object |
1951 | | * Used in conjunction with Argument.operator== e.g., parser["foo"] == true |
1952 | | * @throws std::logic_error in case of an invalid argument name |
1953 | | */ |
1954 | 0 | Argument &operator[](std::string_view arg_name) const { |
1955 | 0 | std::string name(arg_name); |
1956 | 0 | auto it = m_argument_map.find(name); |
1957 | 0 | if (it != m_argument_map.end()) { |
1958 | 0 | return *(it->second); |
1959 | 0 | } |
1960 | 0 | if (!is_valid_prefix_char(arg_name.front())) { |
1961 | 0 | const auto legal_prefix_char = get_any_valid_prefix_char(); |
1962 | 0 | const auto prefix = std::string(1, legal_prefix_char); |
1963 | | |
1964 | | // "-" + arg_name |
1965 | 0 | name = prefix + name; |
1966 | 0 | it = m_argument_map.find(name); |
1967 | 0 | if (it != m_argument_map.end()) { |
1968 | 0 | return *(it->second); |
1969 | 0 | } |
1970 | | // "--" + arg_name |
1971 | 0 | name = prefix + name; |
1972 | 0 | it = m_argument_map.find(name); |
1973 | 0 | if (it != m_argument_map.end()) { |
1974 | 0 | return *(it->second); |
1975 | 0 | } |
1976 | 0 | } |
1977 | 0 | throw std::logic_error("No such argument: " + std::string(arg_name)); |
1978 | 0 | } |
1979 | | |
1980 | | // Print help message |
1981 | | friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) |
1982 | 0 | -> std::ostream & { |
1983 | 0 | stream.setf(std::ios_base::left); |
1984 | |
|
1985 | 0 | auto longest_arg_length = parser.get_length_of_longest_argument(); |
1986 | |
|
1987 | 0 | stream << parser.usage() << "\n\n"; |
1988 | |
|
1989 | 0 | if (!parser.m_description.empty()) { |
1990 | 0 | stream << parser.m_description << "\n\n"; |
1991 | 0 | } |
1992 | |
|
1993 | 0 | const bool has_visible_positional_args = std::find_if( |
1994 | 0 | parser.m_positional_arguments.begin(), |
1995 | 0 | parser.m_positional_arguments.end(), |
1996 | 0 | [](const auto &argument) { |
1997 | 0 | return !argument.m_is_hidden; }) != |
1998 | 0 | parser.m_positional_arguments.end(); |
1999 | 0 | if (has_visible_positional_args) { |
2000 | 0 | stream << "Positional arguments:\n"; |
2001 | 0 | } |
2002 | |
|
2003 | 0 | for (const auto &argument : parser.m_positional_arguments) { |
2004 | 0 | if (!argument.m_is_hidden) { |
2005 | 0 | stream.width(static_cast<std::streamsize>(longest_arg_length)); |
2006 | 0 | stream << argument; |
2007 | 0 | } |
2008 | 0 | } |
2009 | |
|
2010 | 0 | if (!parser.m_optional_arguments.empty()) { |
2011 | 0 | stream << (!has_visible_positional_args ? "" : "\n") |
2012 | 0 | << "Optional arguments:\n"; |
2013 | 0 | } |
2014 | |
|
2015 | 0 | for (const auto &argument : parser.m_optional_arguments) { |
2016 | 0 | if (argument.m_group_idx == 0 && !argument.m_is_hidden) { |
2017 | 0 | stream.width(static_cast<std::streamsize>(longest_arg_length)); |
2018 | 0 | stream << argument; |
2019 | 0 | } |
2020 | 0 | } |
2021 | |
|
2022 | 0 | for (size_t i_group = 0; i_group < parser.m_group_names.size(); ++i_group) { |
2023 | 0 | stream << "\n" << parser.m_group_names[i_group] << " (detailed usage):\n"; |
2024 | 0 | for (const auto &argument : parser.m_optional_arguments) { |
2025 | 0 | if (argument.m_group_idx == i_group + 1 && !argument.m_is_hidden) { |
2026 | 0 | stream.width(static_cast<std::streamsize>(longest_arg_length)); |
2027 | 0 | stream << argument; |
2028 | 0 | } |
2029 | 0 | } |
2030 | 0 | } |
2031 | |
|
2032 | 0 | bool has_visible_subcommands = std::any_of( |
2033 | 0 | parser.m_subparser_map.begin(), parser.m_subparser_map.end(), |
2034 | 0 | [](auto &p) { return !p.second->get().m_suppress; }); |
2035 | |
|
2036 | 0 | if (has_visible_subcommands) { |
2037 | 0 | stream << (parser.m_positional_arguments.empty() |
2038 | 0 | ? (parser.m_optional_arguments.empty() ? "" : "\n") |
2039 | 0 | : "\n") |
2040 | 0 | << "Subcommands:\n"; |
2041 | 0 | for (const auto &[command, subparser] : parser.m_subparser_map) { |
2042 | 0 | if (subparser->get().m_suppress) { |
2043 | 0 | continue; |
2044 | 0 | } |
2045 | | |
2046 | 0 | stream << std::setw(2) << " "; |
2047 | 0 | if (longest_arg_length >= 2) { |
2048 | 0 | stream << std::setw(static_cast<int>(longest_arg_length - 2)) |
2049 | 0 | << command; |
2050 | 0 | } |
2051 | 0 | stream << " " << subparser->get().m_description << "\n"; |
2052 | 0 | } |
2053 | 0 | } |
2054 | |
|
2055 | 0 | if (!parser.m_epilog.empty()) { |
2056 | 0 | stream << '\n'; |
2057 | 0 | stream << parser.m_epilog << "\n\n"; |
2058 | 0 | } |
2059 | |
|
2060 | 0 | return stream; |
2061 | 0 | } |
2062 | | |
2063 | | // Format help message |
2064 | 0 | auto help() const -> std::stringstream { |
2065 | 0 | std::stringstream out; |
2066 | 0 | out << *this; |
2067 | 0 | return out; |
2068 | 0 | } |
2069 | | |
2070 | | // Sets the maximum width for a line of the Usage message |
2071 | 0 | ArgumentParser &set_usage_max_line_width(size_t w) { |
2072 | 0 | this->m_usage_max_line_width = w; |
2073 | 0 | return *this; |
2074 | 0 | } |
2075 | | |
2076 | | // Asks to display arguments of mutually exclusive group on separate lines in |
2077 | | // the Usage message |
2078 | 0 | ArgumentParser &set_usage_break_on_mutex() { |
2079 | 0 | this->m_usage_break_on_mutex = true; |
2080 | 0 | return *this; |
2081 | 0 | } |
2082 | | |
2083 | | // Format usage part of help only |
2084 | 0 | auto usage() const -> std::string { |
2085 | 0 | std::stringstream stream; |
2086 | |
|
2087 | 0 | std::string curline("Usage: "); |
2088 | 0 | curline += this->m_parser_path; |
2089 | 0 | const bool multiline_usage = |
2090 | 0 | this->m_usage_max_line_width < std::numeric_limits<std::size_t>::max(); |
2091 | 0 | const size_t indent_size = curline.size(); |
2092 | |
|
2093 | 0 | const auto deal_with_options_of_group = [&](std::size_t group_idx) { |
2094 | 0 | bool found_options = false; |
2095 | | // Add any options inline here |
2096 | 0 | const MutuallyExclusiveGroup *cur_mutex = nullptr; |
2097 | 0 | int usage_newline_counter = -1; |
2098 | 0 | for (const auto &argument : this->m_optional_arguments) { |
2099 | 0 | if (argument.m_is_hidden) { |
2100 | 0 | continue; |
2101 | 0 | } |
2102 | 0 | if (multiline_usage) { |
2103 | 0 | if (argument.m_group_idx != group_idx) { |
2104 | 0 | continue; |
2105 | 0 | } |
2106 | 0 | if (usage_newline_counter != argument.m_usage_newline_counter) { |
2107 | 0 | if (usage_newline_counter >= 0) { |
2108 | 0 | if (curline.size() > indent_size) { |
2109 | 0 | stream << curline << std::endl; |
2110 | 0 | curline = std::string(indent_size, ' '); |
2111 | 0 | } |
2112 | 0 | } |
2113 | 0 | usage_newline_counter = argument.m_usage_newline_counter; |
2114 | 0 | } |
2115 | 0 | } |
2116 | 0 | found_options = true; |
2117 | 0 | const std::string arg_inline_usage = argument.get_inline_usage(); |
2118 | 0 | const MutuallyExclusiveGroup *arg_mutex = |
2119 | 0 | get_belonging_mutex(&argument); |
2120 | 0 | if ((cur_mutex != nullptr) && (arg_mutex == nullptr)) { |
2121 | 0 | curline += ']'; |
2122 | 0 | if (this->m_usage_break_on_mutex) { |
2123 | 0 | stream << curline << std::endl; |
2124 | 0 | curline = std::string(indent_size, ' '); |
2125 | 0 | } |
2126 | 0 | } else if ((cur_mutex == nullptr) && (arg_mutex != nullptr)) { |
2127 | 0 | if ((this->m_usage_break_on_mutex && curline.size() > indent_size) || |
2128 | 0 | curline.size() + 3 + arg_inline_usage.size() > |
2129 | 0 | this->m_usage_max_line_width) { |
2130 | 0 | stream << curline << std::endl; |
2131 | 0 | curline = std::string(indent_size, ' '); |
2132 | 0 | } |
2133 | 0 | curline += " ["; |
2134 | 0 | } else if ((cur_mutex != nullptr) && (arg_mutex != nullptr)) { |
2135 | 0 | if (cur_mutex != arg_mutex) { |
2136 | 0 | curline += ']'; |
2137 | 0 | if (this->m_usage_break_on_mutex || |
2138 | 0 | curline.size() + 3 + arg_inline_usage.size() > |
2139 | 0 | this->m_usage_max_line_width) { |
2140 | 0 | stream << curline << std::endl; |
2141 | 0 | curline = std::string(indent_size, ' '); |
2142 | 0 | } |
2143 | 0 | curline += " ["; |
2144 | 0 | } else { |
2145 | 0 | curline += '|'; |
2146 | 0 | } |
2147 | 0 | } |
2148 | 0 | cur_mutex = arg_mutex; |
2149 | 0 | if (curline.size() != indent_size && |
2150 | 0 | curline.size() + 1 + arg_inline_usage.size() > |
2151 | 0 | this->m_usage_max_line_width) { |
2152 | 0 | stream << curline << std::endl; |
2153 | 0 | curline = std::string(indent_size, ' '); |
2154 | 0 | curline += " "; |
2155 | 0 | } else if (cur_mutex == nullptr) { |
2156 | 0 | curline += " "; |
2157 | 0 | } |
2158 | 0 | curline += arg_inline_usage; |
2159 | 0 | } |
2160 | 0 | if (cur_mutex != nullptr) { |
2161 | 0 | curline += ']'; |
2162 | 0 | } |
2163 | 0 | return found_options; |
2164 | 0 | }; |
2165 | |
|
2166 | 0 | const bool found_options = deal_with_options_of_group(0); |
2167 | |
|
2168 | 0 | if (found_options && multiline_usage && |
2169 | 0 | !this->m_positional_arguments.empty()) { |
2170 | 0 | stream << curline << std::endl; |
2171 | 0 | curline = std::string(indent_size, ' '); |
2172 | 0 | } |
2173 | | // Put positional arguments after the optionals |
2174 | 0 | for (const auto &argument : this->m_positional_arguments) { |
2175 | 0 | if (argument.m_is_hidden) { |
2176 | 0 | continue; |
2177 | 0 | } |
2178 | 0 | const std::string pos_arg = !argument.m_metavar.empty() |
2179 | 0 | ? argument.m_metavar |
2180 | 0 | : argument.m_names.front(); |
2181 | 0 | if (curline.size() + 1 + pos_arg.size() > this->m_usage_max_line_width) { |
2182 | 0 | stream << curline << std::endl; |
2183 | 0 | curline = std::string(indent_size, ' '); |
2184 | 0 | } |
2185 | 0 | curline += " "; |
2186 | 0 | if (argument.m_num_args_range.get_min() == 0 && |
2187 | 0 | !argument.m_num_args_range.is_right_bounded()) { |
2188 | 0 | curline += "["; |
2189 | 0 | curline += pos_arg; |
2190 | 0 | curline += "]..."; |
2191 | 0 | } else if (argument.m_num_args_range.get_min() == 1 && |
2192 | 0 | !argument.m_num_args_range.is_right_bounded()) { |
2193 | 0 | curline += pos_arg; |
2194 | 0 | curline += "..."; |
2195 | 0 | } else { |
2196 | 0 | curline += pos_arg; |
2197 | 0 | } |
2198 | 0 | } |
2199 | |
|
2200 | 0 | if (multiline_usage) { |
2201 | | // Display options of other groups |
2202 | 0 | for (std::size_t i = 0; i < m_group_names.size(); ++i) { |
2203 | 0 | stream << curline << std::endl << std::endl; |
2204 | 0 | stream << m_group_names[i] << ":" << std::endl; |
2205 | 0 | curline = std::string(indent_size, ' '); |
2206 | 0 | deal_with_options_of_group(i + 1); |
2207 | 0 | } |
2208 | 0 | } |
2209 | |
|
2210 | 0 | stream << curline; |
2211 | | |
2212 | | // Put subcommands after positional arguments |
2213 | 0 | if (!m_subparser_map.empty()) { |
2214 | 0 | stream << " {"; |
2215 | 0 | std::size_t i{0}; |
2216 | 0 | for (const auto &[command, subparser] : m_subparser_map) { |
2217 | 0 | if (subparser->get().m_suppress) { |
2218 | 0 | continue; |
2219 | 0 | } |
2220 | | |
2221 | 0 | if (i == 0) { |
2222 | 0 | stream << command; |
2223 | 0 | } else { |
2224 | 0 | stream << "," << command; |
2225 | 0 | } |
2226 | 0 | ++i; |
2227 | 0 | } |
2228 | 0 | stream << "}"; |
2229 | 0 | } |
2230 | |
|
2231 | 0 | return stream.str(); |
2232 | 0 | } |
2233 | | |
2234 | | // Printing the one and only help message |
2235 | | // I've stuck with a simple message format, nothing fancy. |
2236 | | [[deprecated("Use cout << program; instead. See also help().")]] std::string |
2237 | 0 | print_help() const { |
2238 | 0 | auto out = help(); |
2239 | 0 | std::cout << out.rdbuf(); |
2240 | 0 | return out.str(); |
2241 | 0 | } |
2242 | | |
2243 | 0 | void add_subparser(ArgumentParser &parser) { |
2244 | 0 | parser.m_parser_path = m_program_name + " " + parser.m_program_name; |
2245 | 0 | auto it = m_subparsers.emplace(std::cend(m_subparsers), parser); |
2246 | 0 | m_subparser_map.insert_or_assign(parser.m_program_name, it); |
2247 | 0 | m_subparser_used.insert_or_assign(parser.m_program_name, false); |
2248 | 0 | } |
2249 | | |
2250 | 0 | void set_suppress(bool suppress) { m_suppress = suppress; } |
2251 | | |
2252 | | protected: |
2253 | 0 | const MutuallyExclusiveGroup *get_belonging_mutex(const Argument *arg) const { |
2254 | 0 | for (const auto &mutex : m_mutually_exclusive_groups) { |
2255 | 0 | if (std::find(mutex.m_elements.begin(), mutex.m_elements.end(), arg) != |
2256 | 0 | mutex.m_elements.end()) { |
2257 | 0 | return &mutex; |
2258 | 0 | } |
2259 | 0 | } |
2260 | 0 | return nullptr; |
2261 | 0 | } |
2262 | | |
2263 | 0 | bool is_valid_prefix_char(char c) const { |
2264 | 0 | return m_prefix_chars.find(c) != std::string::npos; |
2265 | 0 | } |
2266 | | |
2267 | 0 | char get_any_valid_prefix_char() const { return m_prefix_chars[0]; } |
2268 | | |
2269 | | /* |
2270 | | * Pre-process this argument list. Anything starting with "--", that |
2271 | | * contains an =, where the prefix before the = has an entry in the |
2272 | | * options table, should be split. |
2273 | | */ |
2274 | | std::vector<std::string> |
2275 | 0 | preprocess_arguments(const std::vector<std::string> &raw_arguments) const { |
2276 | 0 | std::vector<std::string> arguments{}; |
2277 | 0 | for (const auto &arg : raw_arguments) { |
2278 | |
|
2279 | 0 | const auto argument_starts_with_prefix_chars = |
2280 | 0 | [this](const std::string &a) -> bool { |
2281 | 0 | if (!a.empty()) { |
2282 | |
|
2283 | 0 | const auto legal_prefix = [this](char c) -> bool { |
2284 | 0 | return m_prefix_chars.find(c) != std::string::npos; |
2285 | 0 | }; |
2286 | | |
2287 | | // Windows-style |
2288 | | // if '/' is a legal prefix char |
2289 | | // then allow single '/' followed by argument name, followed by an |
2290 | | // assign char, e.g., ':' e.g., 'test.exe /A:Foo' |
2291 | 0 | const auto windows_style = legal_prefix('/'); |
2292 | |
|
2293 | 0 | if (windows_style) { |
2294 | 0 | if (legal_prefix(a[0])) { |
2295 | 0 | return true; |
2296 | 0 | } |
2297 | 0 | } else { |
2298 | | // Slash '/' is not a legal prefix char |
2299 | | // For all other characters, only support long arguments |
2300 | | // i.e., the argument must start with 2 prefix chars, e.g, |
2301 | | // '--foo' e,g, './test --foo=Bar -DARG=yes' |
2302 | 0 | if (a.size() > 1) { |
2303 | 0 | return (legal_prefix(a[0]) && legal_prefix(a[1])); |
2304 | 0 | } |
2305 | 0 | } |
2306 | 0 | } |
2307 | 0 | return false; |
2308 | 0 | }; |
2309 | | |
2310 | | // Check that: |
2311 | | // - We don't have an argument named exactly this |
2312 | | // - The argument starts with a prefix char, e.g., "--" |
2313 | | // - The argument contains an assign char, e.g., "=" |
2314 | 0 | auto assign_char_pos = arg.find_first_of(m_assign_chars); |
2315 | |
|
2316 | 0 | if (m_argument_map.find(arg) == m_argument_map.end() && |
2317 | 0 | argument_starts_with_prefix_chars(arg) && |
2318 | 0 | assign_char_pos != std::string::npos) { |
2319 | | // Get the name of the potential option, and check it exists |
2320 | 0 | std::string opt_name = arg.substr(0, assign_char_pos); |
2321 | 0 | if (m_argument_map.find(opt_name) != m_argument_map.end()) { |
2322 | | // This is the name of an option! Split it into two parts |
2323 | 0 | arguments.push_back(std::move(opt_name)); |
2324 | 0 | arguments.push_back(arg.substr(assign_char_pos + 1)); |
2325 | 0 | continue; |
2326 | 0 | } |
2327 | 0 | } |
2328 | | // If we've fallen through to here, then it's a standard argument |
2329 | 0 | arguments.push_back(arg); |
2330 | 0 | } |
2331 | 0 | return arguments; |
2332 | 0 | } |
2333 | | |
2334 | | /* |
2335 | | * @throws std::runtime_error in case of any invalid argument |
2336 | | */ |
2337 | 0 | void parse_args_internal(const std::vector<std::string> &raw_arguments) { |
2338 | 0 | auto arguments = preprocess_arguments(raw_arguments); |
2339 | 0 | if (m_program_name.empty() && !arguments.empty()) { |
2340 | 0 | m_program_name = arguments.front(); |
2341 | 0 | } |
2342 | 0 | auto end = std::end(arguments); |
2343 | 0 | auto positional_argument_it = std::begin(m_positional_arguments); |
2344 | 0 | for (auto it = std::next(std::begin(arguments)); it != end;) { |
2345 | 0 | const auto ¤t_argument = *it; |
2346 | 0 | if (Argument::is_positional(current_argument, m_prefix_chars)) { |
2347 | 0 | if (positional_argument_it == std::end(m_positional_arguments)) { |
2348 | | |
2349 | | // Check sub-parsers |
2350 | 0 | auto subparser_it = m_subparser_map.find(current_argument); |
2351 | 0 | if (subparser_it != m_subparser_map.end()) { |
2352 | | |
2353 | | // build list of remaining args |
2354 | 0 | const auto unprocessed_arguments = |
2355 | 0 | std::vector<std::string>(it, end); |
2356 | | |
2357 | | // invoke subparser |
2358 | 0 | m_is_parsed = true; |
2359 | 0 | m_subparser_used[current_argument] = true; |
2360 | 0 | return subparser_it->second->get().parse_args( |
2361 | 0 | unprocessed_arguments); |
2362 | 0 | } |
2363 | | |
2364 | 0 | if (m_positional_arguments.empty()) { |
2365 | | |
2366 | | // Ask the user if they argument they provided was a typo |
2367 | | // for some sub-parser, |
2368 | | // e.g., user provided `git totes` instead of `git notes` |
2369 | 0 | if (!m_subparser_map.empty()) { |
2370 | 0 | throw std::runtime_error( |
2371 | 0 | "Failed to parse '" + current_argument + "', did you mean '" + |
2372 | 0 | std::string{details::get_most_similar_string( |
2373 | 0 | m_subparser_map, current_argument)} + |
2374 | 0 | "'"); |
2375 | 0 | } |
2376 | | |
2377 | | // Ask the user if they meant to use a specific optional argument |
2378 | 0 | if (!m_optional_arguments.empty()) { |
2379 | 0 | for (const auto &opt : m_optional_arguments) { |
2380 | 0 | if (!opt.m_implicit_value.has_value()) { |
2381 | | // not a flag, requires a value |
2382 | 0 | if (!opt.m_is_used) { |
2383 | 0 | throw std::runtime_error( |
2384 | 0 | "Zero positional arguments expected, did you mean " + |
2385 | 0 | opt.get_usage_full()); |
2386 | 0 | } |
2387 | 0 | } |
2388 | 0 | } |
2389 | | |
2390 | 0 | throw std::runtime_error("Zero positional arguments expected"); |
2391 | 0 | } else { |
2392 | 0 | throw std::runtime_error("Zero positional arguments expected"); |
2393 | 0 | } |
2394 | 0 | } else { |
2395 | 0 | throw std::runtime_error("Maximum number of positional arguments " |
2396 | 0 | "exceeded, failed to parse '" + |
2397 | 0 | current_argument + "'"); |
2398 | 0 | } |
2399 | 0 | } |
2400 | 0 | auto argument = positional_argument_it++; |
2401 | | |
2402 | | // Deal with the situation of <positional_arg1>... <positional_arg2> |
2403 | 0 | if (argument->m_num_args_range.get_min() == 1 && |
2404 | 0 | argument->m_num_args_range.get_max() == (std::numeric_limits<std::size_t>::max)() && |
2405 | 0 | positional_argument_it != std::end(m_positional_arguments) && |
2406 | 0 | std::next(positional_argument_it) == std::end(m_positional_arguments) && |
2407 | 0 | positional_argument_it->m_num_args_range.get_min() == 1 && |
2408 | 0 | positional_argument_it->m_num_args_range.get_max() == 1 ) { |
2409 | 0 | if (std::next(it) != end) { |
2410 | 0 | positional_argument_it->consume(std::prev(end), end); |
2411 | 0 | end = std::prev(end); |
2412 | 0 | } else { |
2413 | 0 | throw std::runtime_error("Missing " + positional_argument_it->m_names.front()); |
2414 | 0 | } |
2415 | 0 | } |
2416 | | |
2417 | 0 | it = argument->consume(it, end); |
2418 | 0 | continue; |
2419 | 0 | } |
2420 | | |
2421 | 0 | auto arg_map_it = m_argument_map.find(current_argument); |
2422 | 0 | if (arg_map_it != m_argument_map.end()) { |
2423 | 0 | auto argument = arg_map_it->second; |
2424 | 0 | it = argument->consume(std::next(it), end, arg_map_it->first); |
2425 | 0 | } else if (const auto &compound_arg = current_argument; |
2426 | 0 | compound_arg.size() > 1 && |
2427 | 0 | is_valid_prefix_char(compound_arg[0]) && |
2428 | 0 | !is_valid_prefix_char(compound_arg[1])) { |
2429 | 0 | ++it; |
2430 | 0 | for (std::size_t j = 1; j < compound_arg.size(); j++) { |
2431 | 0 | auto hypothetical_arg = std::string{'-', compound_arg[j]}; |
2432 | 0 | auto arg_map_it2 = m_argument_map.find(hypothetical_arg); |
2433 | 0 | if (arg_map_it2 != m_argument_map.end()) { |
2434 | 0 | auto argument = arg_map_it2->second; |
2435 | 0 | it = argument->consume(it, end, arg_map_it2->first); |
2436 | 0 | } else { |
2437 | 0 | throw std::runtime_error("Unknown argument: " + current_argument); |
2438 | 0 | } |
2439 | 0 | } |
2440 | 0 | } else { |
2441 | 0 | throw std::runtime_error("Unknown argument: " + current_argument); |
2442 | 0 | } |
2443 | 0 | } |
2444 | 0 | m_is_parsed = true; |
2445 | 0 | } |
2446 | | |
2447 | | /* |
2448 | | * Like parse_args_internal but collects unused args into a vector<string> |
2449 | | */ |
2450 | | std::vector<std::string> |
2451 | 0 | parse_known_args_internal(const std::vector<std::string> &raw_arguments) { |
2452 | 0 | auto arguments = preprocess_arguments(raw_arguments); |
2453 | 0 |
|
2454 | 0 | std::vector<std::string> unknown_arguments{}; |
2455 | 0 |
|
2456 | 0 | if (m_program_name.empty() && !arguments.empty()) { |
2457 | 0 | m_program_name = arguments.front(); |
2458 | 0 | } |
2459 | 0 | auto end = std::end(arguments); |
2460 | 0 | auto positional_argument_it = std::begin(m_positional_arguments); |
2461 | 0 | for (auto it = std::next(std::begin(arguments)); it != end;) { |
2462 | 0 | const auto ¤t_argument = *it; |
2463 | 0 | if (Argument::is_positional(current_argument, m_prefix_chars)) { |
2464 | 0 | if (positional_argument_it == std::end(m_positional_arguments)) { |
2465 | 0 |
|
2466 | 0 | // Check sub-parsers |
2467 | 0 | auto subparser_it = m_subparser_map.find(current_argument); |
2468 | 0 | if (subparser_it != m_subparser_map.end()) { |
2469 | 0 |
|
2470 | 0 | // build list of remaining args |
2471 | 0 | const auto unprocessed_arguments = |
2472 | 0 | std::vector<std::string>(it, end); |
2473 | 0 |
|
2474 | 0 | // invoke subparser |
2475 | 0 | m_is_parsed = true; |
2476 | 0 | m_subparser_used[current_argument] = true; |
2477 | 0 | return subparser_it->second->get().parse_known_args_internal( |
2478 | 0 | unprocessed_arguments); |
2479 | 0 | } |
2480 | 0 |
|
2481 | 0 | // save current argument as unknown and go to next argument |
2482 | 0 | unknown_arguments.push_back(current_argument); |
2483 | 0 | ++it; |
2484 | 0 | } else { |
2485 | 0 | // current argument is the value of a positional argument |
2486 | 0 | // consume it |
2487 | 0 | auto argument = positional_argument_it++; |
2488 | 0 | it = argument->consume(it, end); |
2489 | 0 | } |
2490 | 0 | continue; |
2491 | 0 | } |
2492 | 0 |
|
2493 | 0 | auto arg_map_it = m_argument_map.find(current_argument); |
2494 | 0 | if (arg_map_it != m_argument_map.end()) { |
2495 | 0 | auto argument = arg_map_it->second; |
2496 | 0 | it = argument->consume(std::next(it), end, arg_map_it->first); |
2497 | 0 | } else if (const auto &compound_arg = current_argument; |
2498 | 0 | compound_arg.size() > 1 && |
2499 | 0 | is_valid_prefix_char(compound_arg[0]) && |
2500 | 0 | !is_valid_prefix_char(compound_arg[1])) { |
2501 | 0 | ++it; |
2502 | 0 | for (std::size_t j = 1; j < compound_arg.size(); j++) { |
2503 | 0 | auto hypothetical_arg = std::string{'-', compound_arg[j]}; |
2504 | 0 | auto arg_map_it2 = m_argument_map.find(hypothetical_arg); |
2505 | 0 | if (arg_map_it2 != m_argument_map.end()) { |
2506 | 0 | auto argument = arg_map_it2->second; |
2507 | 0 | it = argument->consume(it, end, arg_map_it2->first); |
2508 | 0 | } else { |
2509 | 0 | unknown_arguments.push_back(current_argument); |
2510 | 0 | break; |
2511 | 0 | } |
2512 | 0 | } |
2513 | 0 | } else { |
2514 | 0 | // current argument is an optional-like argument that is unknown |
2515 | 0 | // save it and move to next argument |
2516 | 0 | unknown_arguments.push_back(current_argument); |
2517 | 0 | ++it; |
2518 | 0 | } |
2519 | 0 | } |
2520 | 0 | m_is_parsed = true; |
2521 | 0 | return unknown_arguments; |
2522 | 0 | } |
2523 | | |
2524 | | // Used by print_help. |
2525 | 0 | std::size_t get_length_of_longest_argument() const { |
2526 | 0 | if (m_argument_map.empty()) { |
2527 | 0 | return 0; |
2528 | 0 | } |
2529 | 0 | std::size_t max_size = 0; |
2530 | 0 | for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { |
2531 | 0 | max_size = |
2532 | 0 | std::max<std::size_t>(max_size, argument->get_arguments_length()); |
2533 | 0 | } |
2534 | 0 | for ([[maybe_unused]] const auto &[command, unused] : m_subparser_map) { |
2535 | 0 | max_size = std::max<std::size_t>(max_size, command.size()); |
2536 | 0 | } |
2537 | 0 | return max_size; |
2538 | 0 | } |
2539 | | |
2540 | | using argument_it = std::list<Argument>::iterator; |
2541 | | using mutex_group_it = std::vector<MutuallyExclusiveGroup>::iterator; |
2542 | | using argument_parser_it = |
2543 | | std::list<std::reference_wrapper<ArgumentParser>>::iterator; |
2544 | | |
2545 | 0 | void index_argument(argument_it it) { |
2546 | 0 | for (const auto &name : std::as_const(it->m_names)) { |
2547 | 0 | m_argument_map.insert_or_assign(name, it); |
2548 | 0 | } |
2549 | 0 | } |
2550 | | |
2551 | | std::string m_program_name; |
2552 | | std::string m_version; |
2553 | | std::string m_description; |
2554 | | std::string m_epilog; |
2555 | | bool m_exit_on_default_arguments = true; |
2556 | | std::string m_prefix_chars{"-"}; |
2557 | | std::string m_assign_chars{"="}; |
2558 | | bool m_is_parsed = false; |
2559 | | std::list<Argument> m_positional_arguments; |
2560 | | std::list<Argument> m_optional_arguments; |
2561 | | std::map<std::string, argument_it> m_argument_map; |
2562 | | std::string m_parser_path; |
2563 | | std::list<std::reference_wrapper<ArgumentParser>> m_subparsers; |
2564 | | std::map<std::string, argument_parser_it> m_subparser_map; |
2565 | | std::map<std::string, bool> m_subparser_used; |
2566 | | std::vector<MutuallyExclusiveGroup> m_mutually_exclusive_groups; |
2567 | | bool m_suppress = false; |
2568 | | std::size_t m_usage_max_line_width = std::numeric_limits<std::size_t>::max(); |
2569 | | bool m_usage_break_on_mutex = false; |
2570 | | int m_usage_newline_counter = 0; |
2571 | | std::vector<std::string> m_group_names; |
2572 | | }; |
2573 | | |
2574 | | } // namespace argparse |