Simo 0.0.1
Loading...
Searching...
No Matches
CLI11.hpp
1// CLI11: Version 2.6.2
2// Originally designed by Henry Schreiner
3// https://github.com/CLIUtils/CLI11
4//
5// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts
6// from: v2.6.2
7//
8// CLI11 2.6.2 Copyright (c) 2017-2026 University of Cincinnati, developed by Henry
9// Schreiner under NSF AWARD 1414736. All rights reserved.
10//
11// Redistribution and use in source and binary forms of CLI11, with or without
12// modification, are permitted provided that the following conditions are met:
13//
14// 1. Redistributions of source code must retain the above copyright notice, this
15// list of conditions and the following disclaimer.
16// 2. Redistributions in binary form must reproduce the above copyright notice,
17// this list of conditions and the following disclaimer in the documentation
18// and/or other materials provided with the distribution.
19// 3. Neither the name of the copyright holder nor the names of its contributors
20// may be used to endorse or promote products derived from this software without
21// specific prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34#pragma once
35
36// Standard combined includes:
37#include <algorithm>
38#include <array>
39#include <cctype>
40#include <clocale>
41#include <cmath>
42#include <cstdint>
43#include <cstdlib>
44#include <cstring>
45#include <cwchar>
46#include <exception>
47#include <fstream>
48#include <functional>
49#include <iomanip>
50#include <iostream>
51#include <iterator>
52#include <limits>
53#include <locale>
54#include <map>
55#include <memory>
56#include <numeric>
57#include <set>
58#include <sstream>
59#include <stdexcept>
60#include <string>
61#include <tuple>
62#include <type_traits>
63#include <utility>
64#include <vector>
65
66
67#define CLI11_VERSION_MAJOR 2
68#define CLI11_VERSION_MINOR 6
69#define CLI11_VERSION_PATCH 2
70#define CLI11_VERSION "2.6.2"
71
72
73
74
75// The following version macro is very similar to the one in pybind11
76#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
77#if __cplusplus >= 201402L
78#define CLI11_CPP14
79#if __cplusplus >= 201703L
80#define CLI11_CPP17
81#if __cplusplus > 201703L
82#define CLI11_CPP20
83#if __cplusplus > 202002L
84#define CLI11_CPP23
85#if __cplusplus > 202302L
86#define CLI11_CPP26
87#endif
88#endif
89#endif
90#endif
91#endif
92#elif defined(_MSC_VER) && __cplusplus == 199711L
93// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard was fully implemented)
94// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
95#if _MSVC_LANG >= 201402L
96#define CLI11_CPP14
97#if _MSVC_LANG > 201402L && _MSC_VER >= 1910
98#define CLI11_CPP17
99#if _MSVC_LANG > 201703L && _MSC_VER >= 1910
100#define CLI11_CPP20
101#if _MSVC_LANG > 202002L && _MSC_VER >= 1922
102#define CLI11_CPP23
103#endif
104#endif
105#endif
106#endif
107#endif
108
109#if defined(CLI11_CPP14)
110#define CLI11_DEPRECATED(reason) [[deprecated(reason)]]
111#elif defined(_MSC_VER)
112#define CLI11_DEPRECATED(reason) __declspec(deprecated(reason))
113#else
114#define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason)))
115#endif
116
117// GCC < 10 doesn't ignore this in unevaluated contexts
118#if !defined(CLI11_CPP17) || \
119 (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4)
120#define CLI11_NODISCARD
121#else
122#define CLI11_NODISCARD [[nodiscard]]
123#endif
124
126#ifndef CLI11_USE_STATIC_RTTI
127#if (defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI)
128#define CLI11_USE_STATIC_RTTI 1
129#elif defined(__cpp_rtti)
130#if (defined(_CPPRTTI) && _CPPRTTI == 0)
131#define CLI11_USE_STATIC_RTTI 1
132#else
133#define CLI11_USE_STATIC_RTTI 0
134#endif
135#elif (defined(__GCC_RTTI) && __GXX_RTTI)
136#define CLI11_USE_STATIC_RTTI 0
137#else
138#define CLI11_USE_STATIC_RTTI 1
139#endif
140#endif
141
143#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM
144#if __has_include(<filesystem>)
145// Filesystem cannot be used if targeting macOS < 10.15
146#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
147#define CLI11_HAS_FILESYSTEM 0
148#elif defined(__wasi__)
149// As of wasi-sdk-14, filesystem is not implemented
150#define CLI11_HAS_FILESYSTEM 0
151#else
152#include <filesystem>
153#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703
154#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9
155#define CLI11_HAS_FILESYSTEM 1
156#elif defined(__GLIBCXX__)
157// if we are using gcc and Version <9 default to no filesystem
158#define CLI11_HAS_FILESYSTEM 0
159#else
160#define CLI11_HAS_FILESYSTEM 1
161#endif
162#else
163#define CLI11_HAS_FILESYSTEM 0
164#endif
165#endif
166#endif
167#endif
168
170#if !defined(CLI11_CPP26) && !defined(CLI11_HAS_CODECVT)
171#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 5
172#define CLI11_HAS_CODECVT 0
173#else
174#define CLI11_HAS_CODECVT 1
175#include <codecvt>
176#endif
177#else
178#if defined(CLI11_HAS_CODECVT)
179#if CLI11_HAS_CODECVT > 0
180#include <codecvt>
181#endif
182#else
183#define CLI11_HAS_CODECVT 0
184#endif
185#endif
186
188#ifndef CLI11_HAS_RTTI
189#if defined(__GXX_RTTI) && __GXX_RTTI == 1
190// gcc
191#define CLI11_HAS_RTTI 1
192#elif defined(_CPPRTTI) && _CPPRTTI == 1
193// msvc
194#define CLI11_HAS_RTTI 1
195#elif defined(__NO_RTTI__) && __NO_RTTI__ == 1
196// intel
197#define CLI11_HAS_RTTI 0
198#elif defined(__has_feature)
199// clang and other newer compilers
200#if __has_feature(cxx_rtti)
201#define CLI11_HAS_RTTI 1
202#else
203#define CLI11_HAS_RTTI 0
204#endif
205#elif defined(__RTTI) || defined(__INTEL_RTTI__)
206// more intel and some other compilers
207#define CLI11_HAS_RTTI 1
208#else
209#define CLI11_HAS_RTTI 0
210#endif
211#endif
212
214#if defined(__GNUC__) // GCC or clang
215#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
216#define CLI11_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
217
218#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
219
220#elif defined(_MSC_VER)
221#define CLI11_DIAGNOSTIC_PUSH __pragma(warning(push))
222#define CLI11_DIAGNOSTIC_POP __pragma(warning(pop))
223
224#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED __pragma(warning(disable : 4996))
225
226#else
227#define CLI11_DIAGNOSTIC_PUSH
228#define CLI11_DIAGNOSTIC_POP
229
230#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
231
232#endif
233
235#ifdef CLI11_COMPILE
236#define CLI11_INLINE
237#else
238#define CLI11_INLINE inline
239#endif
240
242#if defined CLI11_CPP17
243#define CLI11_MODULE_INLINE inline
244#else
245#define CLI11_MODULE_INLINE static
246#endif
247
248
249
250#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
251#include <filesystem> // NOLINT(build/include)
252#else
253#include <sys/stat.h>
254#include <sys/types.h>
255#endif
256
257
258
259
260#ifdef CLI11_CPP17
261#include <string_view>
262#endif // CLI11_CPP17
263
264#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
265#include <filesystem>
266#include <string_view> // NOLINT(build/include)
267#endif // CLI11_HAS_FILESYSTEM
268
269
270
271#if defined(_WIN32)
272#if !(defined(_AMD64_) || defined(_X86_) || defined(_ARM_))
273#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || \
274 defined(_M_AMD64)
275#define _AMD64_
276#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__i386__) || defined(_M_IX86)
277#define _X86_
278#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARMT)
279#define _ARM_
280#elif defined(__aarch64__) || defined(_M_ARM64)
281#define _ARM64_
282#elif defined(_M_ARM64EC)
283#define _ARM64EC_
284#endif
285#endif
286
287// first
288#ifndef NOMINMAX
289// if NOMINMAX is already defined we don't want to mess with that either way
290#define NOMINMAX
291#include <windef.h>
292#undef NOMINMAX
293#else
294#include <windef.h>
295#endif
296
297// second
298#include <winbase.h>
299// third
300#include <processthreadsapi.h>
301#include <shellapi.h>
302#endif
303
304
305namespace CLI {
306
307
309CLI11_INLINE std::string narrow(const std::wstring &str);
310CLI11_INLINE std::string narrow(const wchar_t *str);
311CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t size);
312
314CLI11_INLINE std::wstring widen(const std::string &str);
315CLI11_INLINE std::wstring widen(const char *str);
316CLI11_INLINE std::wstring widen(const char *str, std::size_t size);
317
318#ifdef CLI11_CPP17
319CLI11_INLINE std::string narrow(std::wstring_view str);
320CLI11_INLINE std::wstring widen(std::string_view str);
321#endif // CLI11_CPP17
322
323#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
325CLI11_INLINE std::filesystem::path to_path(std::string_view str);
326#endif // CLI11_HAS_FILESYSTEM
327
328
329
330
331namespace detail {
332
333#if !CLI11_HAS_CODECVT
335CLI11_INLINE void set_unicode_locale() {
336 static const std::array<const char *, 3> unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}};
337
338 for(const auto &locale_name : unicode_locales) {
339 if(std::setlocale(LC_ALL, locale_name) != nullptr) {
340 return;
341 }
342 }
343 throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8");
344}
345
346template <typename F> struct scope_guard_t {
347 F closure;
348
349 explicit scope_guard_t(F closure_) : closure(closure_) {}
350 ~scope_guard_t() { closure(); }
351};
352
353template <typename F> CLI11_NODISCARD CLI11_INLINE scope_guard_t<F> scope_guard(F &&closure) {
354 return scope_guard_t<F>{std::forward<F>(closure)};
355}
356
357#endif // !CLI11_HAS_CODECVT
358
359CLI11_DIAGNOSTIC_PUSH
360CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
361
362CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) {
363#if CLI11_HAS_CODECVT
364#ifdef _WIN32
365 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(str, str + str_size);
366
367#else
368 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(str, str + str_size);
369
370#endif // _WIN32
371#else // CLI11_HAS_CODECVT
372 (void)str_size;
373 std::mbstate_t state = std::mbstate_t();
374 const wchar_t *it = str;
375
376 std::string old_locale = std::setlocale(LC_ALL, nullptr);
377 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
378 set_unicode_locale();
379
380 std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state);
381 if(new_size == static_cast<std::size_t>(-1)) {
382 throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " +
383 std::to_string(it - str));
384 }
385 std::string result(new_size, '\0');
386 std::wcsrtombs(const_cast<char *>(result.data()), &str, new_size, &state);
387
388 return result;
389
390#endif // CLI11_HAS_CODECVT
391}
392
393CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) {
394#if CLI11_HAS_CODECVT
395#ifdef _WIN32
396 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(str, str + str_size);
397
398#else
399 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(str, str + str_size);
400
401#endif // _WIN32
402#else // CLI11_HAS_CODECVT
403 (void)str_size;
404 std::mbstate_t state = std::mbstate_t();
405 const char *it = str;
406
407 std::string old_locale = std::setlocale(LC_ALL, nullptr);
408 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
409 set_unicode_locale();
410
411 std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state);
412 if(new_size == static_cast<std::size_t>(-1)) {
413 throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " +
414 std::to_string(it - str));
415 }
416 std::wstring result(new_size, L'\0');
417 std::mbsrtowcs(const_cast<wchar_t *>(result.data()), &str, new_size, &state);
418
419 return result;
420
421#endif // CLI11_HAS_CODECVT
422}
423
424CLI11_DIAGNOSTIC_POP
425
426} // namespace detail
427
428CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); }
429CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); }
430// Flawfinder: ignore
431CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); }
432
433CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); }
434CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); }
435// Flawfinder: ignore
436CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); }
437
438#ifdef CLI11_CPP17
439CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); }
440CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); }
441#endif // CLI11_CPP17
442
443#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
444CLI11_INLINE std::filesystem::path to_path(std::string_view str) {
445 return std::filesystem::path{
446#ifdef _WIN32
447 widen(str)
448#else
449 str
450#endif // _WIN32
451 };
452}
453#endif // CLI11_HAS_FILESYSTEM
454
455
456
457
458namespace detail {
459#ifdef _WIN32
461CLI11_INLINE std::vector<std::string> compute_win32_argv();
462#endif
463} // namespace detail
464
465
466
467namespace detail {
468
469#ifdef _WIN32
470CLI11_INLINE std::vector<std::string> compute_win32_argv() {
471 std::vector<std::string> result;
472 int argc = 0;
473
474 auto deleter = [](wchar_t **ptr) { LocalFree(ptr); };
475 // NOLINTBEGIN(*-avoid-c-arrays)
476 auto wargv = std::unique_ptr<wchar_t *[], decltype(deleter)>(CommandLineToArgvW(GetCommandLineW(), &argc), deleter);
477 // NOLINTEND(*-avoid-c-arrays)
478
479 if(wargv == nullptr) {
480 throw std::runtime_error("CommandLineToArgvW failed with code " + std::to_string(GetLastError()));
481 }
482
483 result.reserve(static_cast<size_t>(argc));
484 for(size_t i = 0; i < static_cast<size_t>(argc); ++i) {
485 result.push_back(narrow(wargv[i]));
486 }
487
488 return result;
489}
490#endif
491
492} // namespace detail
493
494
495
496
499namespace enums {
500
502template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
503std::ostream &operator<<(std::ostream &in, const T &item) {
504 // make sure this is out of the detail namespace otherwise it won't be found when needed
505 // https://isocpp.org/wiki/faq/input-output#print-char-or-ptr-as-number
506 return in << +static_cast<typename std::underlying_type<T>::type>(item);
507}
508
509} // namespace enums
510
512using enums::operator<<;
513
514namespace detail {
517CLI11_MODULE_INLINE constexpr int expected_max_vector_size{1 << 29};
518// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
520CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
521
523template <typename T> std::string join(const T &v, std::string delim = ",") {
524 std::ostringstream s;
525 auto beg = std::begin(v);
526 auto end = std::end(v);
527 if(beg != end)
528 s << *beg++;
529 while(beg != end) {
530 s << delim << *beg++;
531 }
532 auto rval = s.str();
533 if(!rval.empty() && delim.size() == 1 && rval.back() == delim[0]) {
534 // remove trailing delimiter if the last entry was empty
535 rval.pop_back();
536 }
537 return rval;
538}
539
541template <typename T,
542 typename Callable,
543 typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
544std::string join(const T &v, Callable func, std::string delim = ",") {
545 std::ostringstream s;
546 auto beg = std::begin(v);
547 auto end = std::end(v);
548 auto loc = s.tellp();
549 while(beg != end) {
550 auto nloc = s.tellp();
551 if(nloc > loc) {
552 s << delim;
553 loc = nloc;
554 }
555 s << func(*beg++);
556 }
557 return s.str();
558}
559
561template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
562 std::ostringstream s;
563 for(std::size_t start = 0; start < v.size(); start++) {
564 if(start > 0)
565 s << delim;
566 s << v[v.size() - start - 1];
567 }
568 return s.str();
569}
570
571// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
572
574CLI11_INLINE std::string &ltrim(std::string &str);
575
577CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter);
578
580CLI11_INLINE std::string &rtrim(std::string &str);
581
583CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter);
584
586inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
587
589inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
590
592inline std::string trim_copy(const std::string &str) {
593 std::string s = str;
594 return trim(s);
595}
596
598CLI11_INLINE std::string &remove_quotes(std::string &str);
599
601CLI11_INLINE void remove_quotes(std::vector<std::string> &args);
602
607CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input);
608
610inline std::string trim_copy(const std::string &str, const std::string &filter) {
611 std::string s = str;
612 return trim(s, filter);
613}
614
616CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid);
617
620template <typename T> bool valid_first_char(T c) {
621 return ((c != '-') && (static_cast<unsigned char>(c) > 33)); // space and '!' not allowed
622}
623
625template <typename T> bool valid_later_char(T c) {
626 // = and : are value separators, { has special meaning for option defaults,
627 // and control codes other than tab would just be annoying to deal with in many places allowing space here has too
628 // much potential for inadvertent entry errors and bugs
629 return ((c != '=') && (c != ':') && (c != '{') && ((static_cast<unsigned char>(c) > 32) || c == '\t'));
630}
631
633CLI11_INLINE bool valid_name_string(const std::string &str);
634
636inline bool valid_alias_name_string(const std::string &str) {
637 return ((str.find_first_of('\n') == std::string::npos) && (str.find_first_of('\0') == std::string::npos));
638}
639
641inline bool is_separator(const std::string &str) {
642 return (str.empty() || (str.size() == 2 && str[0] == '%' && str[1] == '%'));
643}
644
646inline bool isalpha(const std::string &str) {
647 return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); });
648}
649
651inline std::string to_lower(std::string str) {
652 std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
653 return std::tolower(x, std::locale());
654 });
655 return str;
656}
657
659inline std::string remove_underscore(std::string str) {
660 str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str));
661 return str;
662}
663
666CLI11_INLINE std::string get_group_separators();
667
669CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
670
672inline bool has_default_flag_values(const std::string &flags) {
673 return (flags.find_first_of("{!") != std::string::npos);
674}
675
676CLI11_INLINE void remove_default_flag_values(std::string &flags);
677
679CLI11_INLINE std::ptrdiff_t find_member(std::string name,
680 const std::vector<std::string> names,
681 bool ignore_case = false,
682 bool ignore_underscore = false);
683
686template <typename Callable> inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
687 std::size_t start_pos = 0;
688 while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
689 start_pos = modify(str, start_pos);
690 }
691 return str;
692}
693
696CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char);
697
700CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
701
703CLI11_INLINE std::string get_environment_value(const std::string &env_name);
704
709CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
710
714CLI11_INLINE bool has_escapable_character(const std::string &str);
715
719CLI11_INLINE std::string add_escaped_characters(const std::string &str);
720
722CLI11_INLINE std::string remove_escaped_characters(const std::string &str);
723
725CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force = false);
726
727CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string);
728
730CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string);
731
733CLI11_INLINE bool process_quoted_string(std::string &str,
734 char string_char = '\"',
735 char literal_char = '\'',
736 bool disable_secondary_array_processing = false);
737
740CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
741 const std::string &text,
742 std::size_t paragraphWidth,
743 const std::string &linePrefix = "",
744 bool skipPrefixOnFirstLine = false);
745
746} // namespace detail
747
748
749
750
751namespace detail {
752CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim) {
753 std::vector<std::string> elems;
754 // Check to see if empty string, give consistent result
755 if(s.empty()) {
756 elems.emplace_back();
757 } else {
758 std::stringstream ss;
759 ss.str(s);
760 std::string item;
761 while(std::getline(ss, item, delim)) {
762 elems.push_back(item);
763 }
764 }
765 return elems;
766}
767
768CLI11_INLINE std::string &ltrim(std::string &str) {
769 auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
770 str.erase(str.begin(), it);
771 return str;
772}
773
774CLI11_INLINE std::string &ltrim(std::string &str, const std::string &filter) {
775 auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
776 str.erase(str.begin(), it);
777 return str;
778}
779
780CLI11_INLINE std::string &rtrim(std::string &str) {
781 auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
782 str.erase(it.base(), str.end());
783 return str;
784}
785
786CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) {
787 auto it =
788 std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
789 str.erase(it.base(), str.end());
790 return str;
791}
792
793CLI11_INLINE std::string &remove_quotes(std::string &str) {
794 if(str.length() > 1 && (str.front() == '"' || str.front() == '\'' || str.front() == '`')) {
795 if(str.front() == str.back()) {
796 str.pop_back();
797 str.erase(str.begin(), str.begin() + 1);
798 }
799 }
800 return str;
801}
802
803CLI11_INLINE std::string &remove_outer(std::string &str, char key) {
804 if(str.length() > 1 && (str.front() == key)) {
805 if(str.front() == str.back()) {
806 str.pop_back();
807 str.erase(str.begin(), str.begin() + 1);
808 }
809 }
810 return str;
811}
812
813CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) {
814 std::string::size_type n = 0;
815 while(n != std::string::npos && n < input.size()) {
816 n = input.find_first_of("\r\n", n);
817 if(n != std::string::npos) {
818 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
819 n += leader.size();
820 }
821 }
822 return input;
823}
824
825CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
826 if(!aliases.empty()) {
827 out << std::setw(static_cast<int>(wid)) << " aliases: ";
828 bool front = true;
829 for(const auto &alias : aliases) {
830 if(!front) {
831 out << ", ";
832 } else {
833 front = false;
834 }
835 out << detail::fix_newlines(" ", alias);
836 }
837 out << "\n";
838 }
839 return out;
840}
841
842CLI11_INLINE bool valid_name_string(const std::string &str) {
843 if(str.empty() || !valid_first_char(str[0])) {
844 return false;
845 }
846 auto e = str.end();
847 for(auto c = str.begin() + 1; c != e; ++c)
848 if(!valid_later_char(*c))
849 return false;
850 return true;
851}
852
853CLI11_INLINE std::string get_group_separators() {
854 std::string separators{"_'"};
855#if CLI11_HAS_RTTI != 0
856 char group_separator = std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
857 separators.push_back(group_separator);
858#endif
859 return separators;
860}
861
862CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
863
864 std::size_t start_pos = 0;
865
866 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
867 str.replace(start_pos, from.length(), to);
868 start_pos += to.length();
869 }
870
871 return str;
872}
873
874CLI11_INLINE void remove_default_flag_values(std::string &flags) {
875 auto loc = flags.find_first_of('{', 2);
876 while(loc != std::string::npos) {
877 auto finish = flags.find_first_of("},", loc + 1);
878 if((finish != std::string::npos) && (flags[finish] == '}')) {
879 flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
880 flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
881 }
882 loc = flags.find_first_of('{', loc + 1);
883 }
884 flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
885}
886
887CLI11_INLINE std::ptrdiff_t
888find_member(std::string name, const std::vector<std::string> names, bool ignore_case, bool ignore_underscore) {
889 auto it = std::end(names);
890 if(ignore_case) {
891 if(ignore_underscore) {
892 name = detail::to_lower(detail::remove_underscore(name));
893 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
894 return detail::to_lower(detail::remove_underscore(local_name)) == name;
895 });
896 } else {
897 name = detail::to_lower(name);
898 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
899 return detail::to_lower(local_name) == name;
900 });
901 }
902
903 } else if(ignore_underscore) {
904 name = detail::remove_underscore(name);
905 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
906 return detail::remove_underscore(local_name) == name;
907 });
908 } else {
909 it = std::find(std::begin(names), std::end(names), name);
910 }
911
912 return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
913}
914
915CLI11_MODULE_INLINE const std::string &escapedChars("\b\t\n\f\r\"\\");
916CLI11_MODULE_INLINE const std::string &escapedCharsCode("btnfr\"\\");
917CLI11_MODULE_INLINE const std::string &bracketChars("\"'`[(<{");
918CLI11_MODULE_INLINE const std::string &matchBracketChars("\"'`])>}");
919
920CLI11_INLINE bool has_escapable_character(const std::string &str) {
921 return (str.find_first_of(escapedChars) != std::string::npos);
922}
923
924CLI11_INLINE std::string add_escaped_characters(const std::string &str) {
925 std::string out;
926 out.reserve(str.size() + 4);
927 for(char s : str) {
928 auto sloc = escapedChars.find_first_of(s);
929 if(sloc != std::string::npos) {
930 out.push_back('\\');
931 out.push_back(escapedCharsCode[sloc]);
932 } else {
933 out.push_back(s);
934 }
935 }
936 return out;
937}
938
939CLI11_INLINE std::uint32_t hexConvert(char hc) {
940 int hcode{0};
941 if(hc >= '0' && hc <= '9') {
942 hcode = (hc - '0');
943 } else if(hc >= 'A' && hc <= 'F') {
944 hcode = (hc - 'A' + 10);
945 } else if(hc >= 'a' && hc <= 'f') {
946 hcode = (hc - 'a' + 10);
947 } else {
948 hcode = -1;
949 }
950 return static_cast<uint32_t>(hcode);
951}
952
953CLI11_INLINE char make_char(std::uint32_t code) { return static_cast<char>(static_cast<unsigned char>(code)); }
954
955CLI11_INLINE void append_codepoint(std::string &str, std::uint32_t code) {
956 if(code < 0x80) { // ascii code equivalent
957 str.push_back(static_cast<char>(code));
958 } else if(code < 0x800) { // \u0080 to \u07FF
959 // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111
960 str.push_back(make_char(0xC0 | code >> 6));
961 str.push_back(make_char(0x80 | (code & 0x3F)));
962 } else if(code < 0x10000) { // U+0800...U+FFFF
963 if(0xD800 <= code && code <= 0xDFFF) {
964 throw std::invalid_argument("[0xD800, 0xDFFF] are not valid UTF-8.");
965 }
966 // 1110yyyy 10yxxxxx 10xxxxxx
967 str.push_back(make_char(0xE0 | code >> 12));
968 str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
969 str.push_back(make_char(0x80 | (code & 0x3F)));
970 } else if(code < 0x110000) { // U+010000 ... U+10FFFF
971 // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
972 str.push_back(make_char(0xF0 | code >> 18));
973 str.push_back(make_char(0x80 | (code >> 12 & 0x3F)));
974 str.push_back(make_char(0x80 | (code >> 6 & 0x3F)));
975 str.push_back(make_char(0x80 | (code & 0x3F)));
976 }
977}
978
979CLI11_INLINE std::string remove_escaped_characters(const std::string &str) {
980
981 std::string out;
982 out.reserve(str.size());
983 for(auto loc = str.begin(); loc < str.end(); ++loc) {
984 if(*loc == '\\') {
985 if(str.end() - loc < 2) {
986 throw std::invalid_argument("invalid escape sequence " + str);
987 }
988 auto ecloc = escapedCharsCode.find_first_of(*(loc + 1));
989 if(ecloc != std::string::npos) {
990 out.push_back(escapedChars[ecloc]);
991 ++loc;
992 } else if(*(loc + 1) == 'u') {
993 // must have 4 hex characters
994 if(str.end() - loc < 6) {
995 throw std::invalid_argument("unicode sequence must have 4 hex codes " + str);
996 }
997 std::uint32_t code{0};
998 std::uint32_t mplier{16 * 16 * 16};
999 for(int ii = 2; ii < 6; ++ii) {
1000 std::uint32_t res = hexConvert(*(loc + ii));
1001 if(res > 0x0F) {
1002 throw std::invalid_argument("unicode sequence must have 4 hex codes " + str);
1003 }
1004 code += res * mplier;
1005 mplier = mplier / 16;
1006 }
1007 append_codepoint(out, code);
1008 loc += 5;
1009 } else if(*(loc + 1) == 'U') {
1010 // must have 8 hex characters
1011 if(str.end() - loc < 10) {
1012 throw std::invalid_argument("unicode sequence must have 8 hex codes " + str);
1013 }
1014 std::uint32_t code{0};
1015 std::uint32_t mplier{16 * 16 * 16 * 16 * 16 * 16 * 16};
1016 for(int ii = 2; ii < 10; ++ii) {
1017 std::uint32_t res = hexConvert(*(loc + ii));
1018 if(res > 0x0F) {
1019 throw std::invalid_argument("unicode sequence must have 8 hex codes " + str);
1020 }
1021 code += res * mplier;
1022 mplier = mplier / 16;
1023 }
1024 append_codepoint(out, code);
1025 loc += 9;
1026 } else if(*(loc + 1) == '0') {
1027 out.push_back('\0');
1028 ++loc;
1029 } else {
1030 throw std::invalid_argument(std::string("unrecognized escape sequence \\") + *(loc + 1) + " in " + str);
1031 }
1032 } else {
1033 out.push_back(*loc);
1034 }
1035 }
1036 return out;
1037}
1038
1039CLI11_INLINE std::size_t close_string_quote(const std::string &str, std::size_t start, char closure_char) {
1040 std::size_t loc{0};
1041 for(loc = start + 1; loc < str.size(); ++loc) {
1042 if(str[loc] == closure_char) {
1043 break;
1044 }
1045 if(str[loc] == '\\') {
1046 // skip the next character for escaped sequences
1047 ++loc;
1048 }
1049 }
1050 return loc;
1051}
1052
1053CLI11_INLINE std::size_t close_literal_quote(const std::string &str, std::size_t start, char closure_char) {
1054 auto loc = str.find_first_of(closure_char, start + 1);
1055 return (loc != std::string::npos ? loc : str.size());
1056}
1057
1058CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char) {
1059
1060 auto bracket_loc = matchBracketChars.find(closure_char);
1061 switch(bracket_loc) {
1062 case 0:
1063 return close_string_quote(str, start, closure_char);
1064 case 1:
1065 case 2:
1066#if defined(_MSC_VER) && _MSC_VER < 1920
1067 case(std::size_t)-1:
1068#else
1069 case std::string::npos:
1070#endif
1071 return close_literal_quote(str, start, closure_char);
1072 default:
1073 break;
1074 }
1075
1076 std::string closures(1, closure_char);
1077 auto loc = start + 1;
1078
1079 while(loc < str.size()) {
1080 if(str[loc] == closures.back()) {
1081 closures.pop_back();
1082 if(closures.empty()) {
1083 return loc;
1084 }
1085 }
1086 bracket_loc = bracketChars.find(str[loc]);
1087 if(bracket_loc != std::string::npos) {
1088 switch(bracket_loc) {
1089 case 0:
1090 loc = close_string_quote(str, loc, str[loc]);
1091 break;
1092 case 1:
1093 case 2:
1094 loc = close_literal_quote(str, loc, str[loc]);
1095 break;
1096 default:
1097 closures.push_back(matchBracketChars[bracket_loc]);
1098 break;
1099 }
1100 }
1101 ++loc;
1102 }
1103 if(loc > str.size()) {
1104 loc = str.size();
1105 }
1106 return loc;
1107}
1108
1109CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter) {
1110
1111 auto find_ws = [delimiter](char ch) {
1112 return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
1113 };
1114 trim(str);
1115
1116 std::vector<std::string> output;
1117 while(!str.empty()) {
1118 if(bracketChars.find_first_of(str[0]) != std::string::npos) {
1119 auto bracketLoc = bracketChars.find_first_of(str[0]);
1120 auto end = close_sequence(str, 0, matchBracketChars[bracketLoc]);
1121 if(end >= str.size()) {
1122 output.push_back(std::move(str));
1123 str.clear();
1124 } else {
1125 output.push_back(str.substr(0, end + 1));
1126 if(end + 2 < str.size()) {
1127 str = str.substr(end + 2);
1128 } else {
1129 str.clear();
1130 }
1131 }
1132
1133 } else {
1134 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
1135 if(it != std::end(str)) {
1136 std::string value = std::string(str.begin(), it);
1137 output.push_back(value);
1138 str = std::string(it + 1, str.end());
1139 } else {
1140 output.push_back(str);
1141 str.clear();
1142 }
1143 }
1144 trim(str);
1145 }
1146 return output;
1147}
1148
1149CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
1150 auto next = str[offset + 1];
1151 if((next == '\"') || (next == '\'') || (next == '`')) {
1152 auto astart = str.find_last_of("-/ \"\'`", offset - 1);
1153 if(astart != std::string::npos) {
1154 if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
1155 str[offset] = ' '; // interpret this as a space so the split_up works properly
1156 }
1157 }
1158 return offset + 1;
1159}
1160
1161CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape, bool force) {
1162 // s is our escaped output string
1163 std::string escaped_string{};
1164 // loop through all characters
1165 for(char c : string_to_escape) {
1166 // check if a given character is printable
1167 // the cast is necessary to avoid undefined behaviour
1168 if(isprint(static_cast<unsigned char>(c)) == 0) {
1169 std::stringstream stream;
1170 // if the character is not printable
1171 // we'll convert it to a hex string using a stringstream
1172 // note that since char is signed we have to cast it to unsigned first
1173 stream << std::hex << static_cast<unsigned int>(static_cast<unsigned char>(c));
1174 std::string code = stream.str();
1175 escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code;
1176 } else if(c == 'x' || c == 'X') {
1177 // need to check for inadvertent binary sequences
1178 if(!escaped_string.empty() && escaped_string.back() == '\\') {
1179 escaped_string += std::string("\\x") + (c == 'x' ? "78" : "58");
1180 } else {
1181 escaped_string.push_back(c);
1182 }
1183
1184 } else {
1185 escaped_string.push_back(c);
1186 }
1187 }
1188 if(escaped_string != string_to_escape || force) {
1189 auto sqLoc = escaped_string.find('\'');
1190 while(sqLoc != std::string::npos) {
1191 escaped_string[sqLoc] = '\\';
1192 escaped_string.insert(sqLoc + 1, "x27");
1193 sqLoc = escaped_string.find('\'');
1194 }
1195 escaped_string.insert(0, "'B\"(");
1196 escaped_string.push_back(')');
1197 escaped_string.push_back('"');
1198 escaped_string.push_back('\'');
1199 }
1200 return escaped_string;
1201}
1202
1203CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string) {
1204 size_t ssize = escaped_string.size();
1205 if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
1206 return true;
1207 }
1208 return (escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0);
1209}
1210
1211CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string) {
1212 std::size_t start{0};
1213 std::size_t tail{0};
1214 size_t ssize = escaped_string.size();
1215 if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) {
1216 start = 3;
1217 tail = 2;
1218 } else if(escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0) {
1219 start = 4;
1220 tail = 3;
1221 }
1222
1223 if(start == 0) {
1224 return escaped_string;
1225 }
1226 std::string outstring;
1227
1228 outstring.reserve(ssize - start - tail);
1229 std::size_t loc = start;
1230 while(loc < ssize - tail) {
1231 // ssize-2 to skip )" at the end
1232 if(escaped_string[loc] == '\\' && (escaped_string[loc + 1] == 'x' || escaped_string[loc + 1] == 'X')) {
1233 auto c1 = escaped_string[loc + 2];
1234 auto c2 = escaped_string[loc + 3];
1235
1236 std::uint32_t res1 = hexConvert(c1);
1237 std::uint32_t res2 = hexConvert(c2);
1238 if(res1 <= 0x0F && res2 <= 0x0F) {
1239 loc += 4;
1240 outstring.push_back(static_cast<char>(res1 * 16 + res2));
1241 continue;
1242 }
1243 }
1244 outstring.push_back(escaped_string[loc]);
1245 ++loc;
1246 }
1247 return outstring;
1248}
1249
1250CLI11_INLINE void remove_quotes(std::vector<std::string> &args) {
1251 for(auto &arg : args) {
1252 if(arg.front() == '\"' && arg.back() == '\"') {
1253 remove_quotes(arg);
1254 // only remove escaped for string arguments not literal strings
1255 arg = remove_escaped_characters(arg);
1256 } else {
1257 remove_quotes(arg);
1258 }
1259 }
1260}
1261
1262CLI11_INLINE void handle_secondary_array(std::string &str) {
1263 if(str.size() >= 2 && str.front() == '[' && str.back() == ']') {
1264 // handle some special array processing for arguments if it might be interpreted as a secondary array
1265 std::string tstr{"[["};
1266 for(std::size_t ii = 1; ii < str.size(); ++ii) {
1267 tstr.push_back(str[ii]);
1268 tstr.push_back(str[ii]);
1269 }
1270 str = std::move(tstr);
1271 }
1272}
1273
1274CLI11_INLINE bool
1275process_quoted_string(std::string &str, char string_char, char literal_char, bool disable_secondary_array_processing) {
1276 if(str.size() <= 1) {
1277 return false;
1278 }
1279 if(detail::is_binary_escaped_string(str)) {
1280 str = detail::extract_binary_string(str);
1281 if(!disable_secondary_array_processing)
1282 handle_secondary_array(str);
1283 return true;
1284 }
1285 if(str.front() == string_char && str.back() == string_char) {
1286 detail::remove_outer(str, string_char);
1287 if(str.find_first_of('\\') != std::string::npos) {
1288 str = detail::remove_escaped_characters(str);
1289 }
1290 if(!disable_secondary_array_processing)
1291 handle_secondary_array(str);
1292 return true;
1293 }
1294 if((str.front() == literal_char || str.front() == '`') && str.back() == str.front()) {
1295 detail::remove_outer(str, str.front());
1296 if(!disable_secondary_array_processing)
1297 handle_secondary_array(str);
1298 return true;
1299 }
1300 return false;
1301}
1302
1303std::string get_environment_value(const std::string &env_name) {
1304 std::string ename_string;
1305
1306#ifdef _MSC_VER
1307 // Windows version
1308 char *buffer = nullptr;
1309 std::size_t sz = 0;
1310 if(_dupenv_s(&buffer, &sz, env_name.c_str()) == 0 && buffer != nullptr) {
1311 ename_string = std::string(buffer);
1312 free(buffer);
1313 }
1314#else
1315 // This also works on Windows, but gives a warning
1316
1317 // MISRA static analysis need. MISRACPP2023-25_5_2-a-1
1318 const char *buffer = nullptr;
1319 buffer = std::getenv(env_name.c_str());
1320 if(buffer != nullptr) {
1321 ename_string = std::string(buffer);
1322 }
1323#endif
1324 return ename_string;
1325}
1326
1327CLI11_INLINE std::ostream &streamOutAsParagraph(std::ostream &out,
1328 const std::string &text,
1329 std::size_t paragraphWidth,
1330 const std::string &linePrefix,
1331 bool skipPrefixOnFirstLine) {
1332 if(!skipPrefixOnFirstLine)
1333 out << linePrefix; // First line prefix
1334
1335 std::istringstream lss(text);
1336 std::string line = "";
1337 while(std::getline(lss, line)) {
1338 std::istringstream iss(line);
1339 std::string word = "";
1340 std::size_t charsWritten = 0;
1341
1342 while(iss >> word) {
1343 if(charsWritten > 0 && (word.length() + 1 + charsWritten > paragraphWidth)) {
1344 out << '\n' << linePrefix;
1345 charsWritten = 0;
1346 }
1347 if(charsWritten == 0) {
1348 out << word;
1349 charsWritten += word.length();
1350 } else {
1351 out << ' ' << word;
1352 charsWritten += word.length() + 1;
1353 }
1354 }
1355
1356 if(!lss.eof())
1357 out << '\n' << linePrefix;
1358 }
1359 return out;
1360}
1361
1362} // namespace detail
1363
1364
1365
1366// Use one of these on all error classes.
1367// These are temporary and are undef'd at the end of this file.
1368#define CLI11_ERROR_DEF(parent, name) \
1369 protected: \
1370 name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
1371 name(std::string ename, std::string msg, ExitCodes exit_code) \
1372 : parent(std::move(ename), std::move(msg), exit_code) {} \
1373 \
1374 public: \
1375 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
1376 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
1377
1378// This is added after the one above if a class is used directly and builds its own message
1379#define CLI11_ERROR_SIMPLE(name) \
1380 explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
1381
1384enum class ExitCodes : int {
1385 Success = 0,
1389 FileError,
1401 BaseClass = 127
1402};
1403
1404// Error definitions
1405
1411
1413class Error : public std::runtime_error {
1414 int actual_exit_code;
1415 std::string error_name{"Error"};
1416
1417 public:
1418 CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; }
1419
1420 CLI11_NODISCARD std::string get_name() const { return error_name; }
1421
1422 Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
1423 : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
1424
1425 Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
1426};
1427
1428// Note: Using Error::Error constructors does not work on GCC 4.7
1429
1431class ConstructionError : public Error {
1432 CLI11_ERROR_DEF(Error, ConstructionError)
1433};
1434
1438 CLI11_ERROR_SIMPLE(IncorrectConstruction)
1439 static IncorrectConstruction PositionalFlag(std::string name) {
1440 return IncorrectConstruction(name + ": Flags cannot be positional");
1441 }
1442 static IncorrectConstruction Set0Opt(std::string name) {
1443 return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
1444 }
1445 static IncorrectConstruction SetFlag(std::string name) {
1446 return IncorrectConstruction(name + ": Cannot set an expected number for flags");
1447 }
1448 static IncorrectConstruction ChangeNotVector(std::string name) {
1449 return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
1450 }
1451 static IncorrectConstruction AfterMultiOpt(std::string name) {
1452 return IncorrectConstruction(
1453 name + ": You can't change expected arguments after you've changed the multi option policy!");
1454 }
1455 static IncorrectConstruction MissingOption(std::string name) {
1456 return IncorrectConstruction("Option " + name + " is not defined");
1457 }
1458 static IncorrectConstruction MultiOptionPolicy(std::string name) {
1459 return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
1460 }
1461};
1462
1465 CLI11_ERROR_DEF(ConstructionError, BadNameString)
1466 CLI11_ERROR_SIMPLE(BadNameString)
1467 static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
1468 static BadNameString MissingDash(std::string name) {
1469 return BadNameString("Long names strings require 2 dashes " + name);
1470 }
1471 static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
1472 static BadNameString BadPositionalName(std::string name) {
1473 return BadNameString("Invalid positional Name: " + name);
1474 }
1475 static BadNameString ReservedName(std::string name) {
1476 return BadNameString("Names '-','--','++' are reserved and not allowed as option names " + name);
1477 }
1478 static BadNameString MultiPositionalNames(std::string name) {
1479 return BadNameString("Only one positional name allowed, remove: " + name);
1480 }
1481};
1482
1484class OptionAlreadyAdded : public ConstructionError {
1485 CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
1486 explicit OptionAlreadyAdded(std::string name)
1487 : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
1488 static OptionAlreadyAdded Requires(std::string name, std::string other) {
1489 return {name + " requires " + other, ExitCodes::OptionAlreadyAdded};
1490 }
1491 static OptionAlreadyAdded Excludes(std::string name, std::string other) {
1492 return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded};
1493 }
1494};
1495
1496// Parsing errors
1497
1499class ParseError : public Error {
1500 CLI11_ERROR_DEF(Error, ParseError)
1501};
1502
1503// Not really "errors"
1504
1506class Success : public ParseError {
1507 CLI11_ERROR_DEF(ParseError, Success)
1508 Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
1509};
1510
1512class CallForHelp : public Success {
1513 CLI11_ERROR_DEF(Success, CallForHelp)
1514 CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
1515};
1516
1518class CallForAllHelp : public Success {
1519 CLI11_ERROR_DEF(Success, CallForAllHelp)
1520 CallForAllHelp()
1521 : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
1522};
1523
1525class CallForVersion : public Success {
1526 CLI11_ERROR_DEF(Success, CallForVersion)
1527 CallForVersion()
1528 : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
1529};
1530
1532class RuntimeError : public ParseError {
1533 CLI11_ERROR_DEF(ParseError, RuntimeError)
1534 explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
1535};
1536
1538class FileError : public ParseError {
1539 CLI11_ERROR_DEF(ParseError, FileError)
1540 CLI11_ERROR_SIMPLE(FileError)
1541 static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
1542};
1543
1545class ConversionError : public ParseError {
1546 CLI11_ERROR_DEF(ParseError, ConversionError)
1547 CLI11_ERROR_SIMPLE(ConversionError)
1548 ConversionError(std::string member, std::string name)
1549 : ConversionError("The value " + member + " is not an allowed value for " + name) {}
1550 ConversionError(std::string name, std::vector<std::string> results)
1551 : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
1552 static ConversionError TooManyInputsFlag(std::string name) {
1553 return ConversionError(name + ": too many inputs for a flag");
1554 }
1555 static ConversionError TrueFalse(std::string name) {
1556 return ConversionError(name + ": Should be true/false or a number");
1557 }
1558};
1559
1561class ValidationError : public ParseError {
1562 CLI11_ERROR_DEF(ParseError, ValidationError)
1563 CLI11_ERROR_SIMPLE(ValidationError)
1564 explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
1565};
1566
1568class RequiredError : public ParseError {
1569 CLI11_ERROR_DEF(ParseError, RequiredError)
1570 explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
1571 static RequiredError Subcommand(std::size_t min_subcom) {
1572 if(min_subcom == 1) {
1573 return RequiredError("A subcommand");
1574 }
1575 return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError};
1576 }
1577 static RequiredError
1578 Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) {
1579 if((min_option == 1) && (max_option == 1) && (used == 0))
1580 return RequiredError("Exactly 1 option from [" + option_list + "]");
1581 if((min_option == 1) && (max_option == 1) && (used > 1)) {
1582 return {"Exactly 1 option from [" + option_list + "] is required but " + std::to_string(used) +
1583 " were given",
1584 ExitCodes::RequiredError};
1585 }
1586 if((min_option == 1) && (used == 0))
1587 return RequiredError("At least 1 option from [" + option_list + "]");
1588 if(used < min_option) {
1589 return {"Requires at least " + std::to_string(min_option) + " options used but only " +
1590 std::to_string(used) + " were given from [" + option_list + "]",
1591 ExitCodes::RequiredError};
1592 }
1593 if(max_option == 1)
1594 return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError};
1595
1596 return {"Requires at most " + std::to_string(max_option) + " options be used but " + std::to_string(used) +
1597 " were given from [" + option_list + "]",
1598 ExitCodes::RequiredError};
1599 }
1600};
1601
1603class ArgumentMismatch : public ParseError {
1604 CLI11_ERROR_DEF(ParseError, ArgumentMismatch)
1605 CLI11_ERROR_SIMPLE(ArgumentMismatch)
1606 ArgumentMismatch(std::string name, int expected, std::size_t received)
1607 : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
1608 ", got " + std::to_string(received))
1609 : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
1610 ", got " + std::to_string(received)),
1611 ExitCodes::ArgumentMismatch) {}
1612
1613 static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) {
1614 return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " +
1615 std::to_string(received));
1616 }
1617 static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) {
1618 return ArgumentMismatch(name + ": At most " + std::to_string(num) + " required but received " +
1619 std::to_string(received));
1620 }
1621 static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
1622 return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
1623 }
1624 static ArgumentMismatch FlagOverride(std::string name) {
1625 return ArgumentMismatch(name + " was given a disallowed flag override");
1626 }
1627 static ArgumentMismatch PartialType(std::string name, int num, std::string type) {
1628 return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) +
1629 " required for each element");
1630 }
1631};
1632
1634class RequiresError : public ParseError {
1635 CLI11_ERROR_DEF(ParseError, RequiresError)
1636 RequiresError(std::string curname, std::string subname)
1637 : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
1638};
1639
1641class ExcludesError : public ParseError {
1642 CLI11_ERROR_DEF(ParseError, ExcludesError)
1643 ExcludesError(std::string curname, std::string subname)
1644 : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
1645};
1646
1648class ExtrasError : public ParseError {
1649 CLI11_ERROR_DEF(ParseError, ExtrasError)
1650 explicit ExtrasError(std::vector<std::string> args)
1651 : ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
1652 : "The following argument was not expected: ") +
1653 detail::join(args, " "),
1654 ExitCodes::ExtrasError) {}
1655 ExtrasError(const std::string &name, std::vector<std::string> args)
1656 : ExtrasError(name,
1657 (args.size() > 1 ? "The following arguments were not expected: "
1658 : "The following argument was not expected: ") +
1659 detail::join(args, " "),
1660 ExitCodes::ExtrasError) {}
1661};
1662
1664class ConfigError : public ParseError {
1665 CLI11_ERROR_DEF(ParseError, ConfigError)
1666 CLI11_ERROR_SIMPLE(ConfigError)
1667 static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); }
1668 static ConfigError NotConfigurable(std::string item) {
1669 return ConfigError(item + ": This option is not allowed in a configuration file");
1670 }
1671};
1672
1674class InvalidError : public ParseError {
1675 CLI11_ERROR_DEF(ParseError, InvalidError)
1676 explicit InvalidError(std::string name)
1677 : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
1678 }
1679};
1680
1684 CLI11_ERROR_DEF(ParseError, HorribleError)
1685 CLI11_ERROR_SIMPLE(HorribleError)
1686};
1687
1688// After parsing
1689
1691class OptionNotFound : public Error {
1692 CLI11_ERROR_DEF(Error, OptionNotFound)
1693 explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
1694};
1695
1696#undef CLI11_ERROR_DEF
1697#undef CLI11_ERROR_SIMPLE
1698
1700
1701
1702
1703
1704// Type tools
1705
1706// Utilities for type enabling
1707namespace detail {
1708// Based generally on https://rmf.io/cxx11/almost-static-if
1710enum class enabler : std::uint8_t {};
1711
1713CLI11_MODULE_INLINE constexpr enabler dummy = {};
1714} // namespace detail
1715
1721template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
1722
1724template <typename... Ts> struct make_void {
1725 using type = void;
1726};
1727
1729template <typename... Ts> using void_t = typename make_void<Ts...>::type;
1730
1732template <bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;
1733
1735template <typename T> struct is_bool : std::false_type {};
1736
1738template <> struct is_bool<bool> : std::true_type {};
1739
1741template <typename T> struct is_shared_ptr : std::false_type {};
1742
1744template <typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
1745
1747template <typename T> struct is_shared_ptr<const std::shared_ptr<T>> : std::true_type {};
1748
1750template <typename T> struct is_copyable_ptr {
1751 static bool const value = is_shared_ptr<T>::value || std::is_pointer<T>::value;
1752};
1753
1755template <typename T> struct IsMemberType {
1756 using type = T;
1757};
1758
1760template <> struct IsMemberType<const char *> {
1761 using type = std::string;
1762};
1763
1764namespace adl_detail {
1770template <typename T, typename S = std::string> class is_lexical_castable {
1771 template <typename TT, typename SS>
1772 static auto test(int) -> decltype(lexical_cast(std::declval<const SS &>(), std::declval<TT &>()), std::true_type());
1773
1774 template <typename, typename> static auto test(...) -> std::false_type;
1775
1776 public:
1777 static constexpr bool value = decltype(test<T, S>(0))::value;
1778};
1779} // namespace adl_detail
1780
1781namespace detail {
1782
1783// These are utilities for IsMember and other transforming objects
1784
1787
1789template <typename T, typename Enable = void> struct element_type {
1790 using type = T;
1791};
1792
1793template <typename T> struct element_type<T, typename std::enable_if<is_copyable_ptr<T>::value>::type> {
1794 using type = typename std::pointer_traits<T>::element_type;
1795};
1796
1799template <typename T> struct element_value_type {
1800 using type = typename element_type<T>::type::value_type;
1801};
1802
1804template <typename T, typename _ = void> struct pair_adaptor : std::false_type {
1805 using value_type = typename T::value_type;
1806 using first_type = typename std::remove_const<value_type>::type;
1807 using second_type = typename std::remove_const<value_type>::type;
1808
1810 template <typename Q> static auto first(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1811 return std::forward<Q>(pair_value);
1812 }
1813
1814 template <typename Q> static auto second(Q &&pair_value) -> decltype(std::forward<Q>(pair_value)) {
1815 return std::forward<Q>(pair_value);
1816 }
1817};
1818
1821template <typename T>
1823 T,
1824 conditional_t<false, void_t<typename T::value_type::first_type, typename T::value_type::second_type>, void>>
1825 : std::true_type {
1826 using value_type = typename T::value_type;
1827 using first_type = typename std::remove_const<typename value_type::first_type>::type;
1828 using second_type = typename std::remove_const<typename value_type::second_type>::type;
1829
1831 template <typename Q> static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward<Q>(pair_value))) {
1832 return std::get<0>(std::forward<Q>(pair_value));
1833 }
1834
1835 template <typename Q> static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward<Q>(pair_value))) {
1836 return std::get<1>(std::forward<Q>(pair_value));
1837 }
1838};
1839
1840// Warning is suppressed due to "bug" in gcc<5.0 and gcc 7.0 with c++17 enabled that generates a -Wnarrowing warning
1841// in the unevaluated context even if the function that was using this wasn't used. The standard says narrowing in
1842// brace initialization shouldn't be allowed but for backwards compatibility gcc allows it in some contexts. It is a
1843// little fuzzy what happens in template constructs and I think that was something GCC took a little while to work out.
1844// But regardless some versions of gcc generate a warning when they shouldn't from the following code so that should be
1845// suppressed
1846#ifdef __GNUC__
1847#pragma GCC diagnostic push
1848#pragma GCC diagnostic ignored "-Wnarrowing"
1849#endif
1850// check for constructibility from a specific type and copy assignable used in the parse detection
1851template <typename T, typename C> class is_direct_constructible {
1852 template <typename TT, typename CC>
1853 static auto test(int, std::true_type) -> decltype(
1854// NVCC warns about narrowing conversions here
1855#ifdef __CUDACC__
1856#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
1857#pragma nv_diag_suppress 2361
1858#else
1859#pragma diag_suppress 2361
1860#endif
1861#endif
1862 TT{std::declval<CC>()}
1863#ifdef __CUDACC__
1864#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
1865#pragma nv_diag_default 2361
1866#else
1867#pragma diag_default 2361
1868#endif
1869#endif
1870 ,
1871 std::is_move_assignable<TT>());
1872
1873 template <typename TT, typename CC> static auto test(int, std::false_type) -> std::false_type;
1874
1875 template <typename, typename> static auto test(...) -> std::false_type;
1876
1877 public:
1878 static constexpr bool value = decltype(test<T, C>(0, typename std::is_constructible<T, C>::type()))::value;
1879};
1880#ifdef __GNUC__
1881#pragma GCC diagnostic pop
1882#endif
1883
1884// Check for output streamability
1885// Based on https://stackoverflow.com/questions/22758291/how-can-i-detect-if-a-type-can-be-streamed-to-an-stdostream
1886
1887template <typename T, typename S = std::ostringstream> class is_ostreamable {
1888 template <typename TT, typename SS>
1889 static auto test(int) -> decltype(std::declval<SS &>() << std::declval<TT>(), std::true_type());
1890
1891 template <typename, typename> static auto test(...) -> std::false_type;
1892
1893 public:
1894 static constexpr bool value = decltype(test<T, S>(0))::value;
1895};
1896
1898template <typename T, typename S = std::istringstream> class is_istreamable {
1899 template <typename TT, typename SS>
1900 static auto test(int) -> decltype(std::declval<SS &>() >> std::declval<TT &>(), std::true_type());
1901
1902 template <typename, typename> static auto test(...) -> std::false_type;
1903
1904 public:
1905 static constexpr bool value = decltype(test<T, S>(0))::value;
1906};
1907
1909template <typename T> class is_complex {
1910 template <typename TT>
1911 static auto test(int) -> decltype(std::declval<TT>().real(), std::declval<TT>().imag(), std::true_type());
1912
1913 template <typename> static auto test(...) -> std::false_type;
1914
1915 public:
1916 static constexpr bool value = decltype(test<T>(0))::value;
1917};
1918
1920template <typename T, enable_if_t<is_istreamable<T>::value, detail::enabler> = detail::dummy>
1921bool from_stream(const std::string &istring, T &obj) {
1922 std::istringstream is;
1923 is.str(istring);
1924 is >> obj;
1925 return !is.fail() && !is.rdbuf()->in_avail();
1926}
1927
1928template <typename T, enable_if_t<!is_istreamable<T>::value, detail::enabler> = detail::dummy>
1929bool from_stream(const std::string & /*istring*/, T & /*obj*/) {
1930 return false;
1931}
1932
1933// check to see if an object is a mutable container (fail by default)
1934template <typename T, typename _ = void> struct is_mutable_container : std::false_type {};
1935
1939template <typename T>
1941 T,
1942 conditional_t<false,
1943 void_t<typename T::value_type,
1944 decltype(std::declval<T>().end()),
1945 decltype(std::declval<T>().clear()),
1946 decltype(std::declval<T>().insert(std::declval<decltype(std::declval<T>().end())>(),
1947 std::declval<const typename T::value_type &>()))>,
1948 void>> : public conditional_t<std::is_constructible<T, std::string>::value ||
1949 std::is_constructible<T, std::wstring>::value,
1950 std::false_type,
1951 std::true_type> {};
1952
1953// check to see if an object is a mutable container (fail by default)
1954template <typename T, typename _ = void> struct is_readable_container : std::false_type {};
1955
1958template <typename T>
1960 T,
1961 conditional_t<false, void_t<decltype(std::declval<T>().end()), decltype(std::declval<T>().begin())>, void>>
1962 : public std::true_type {};
1963
1964// check to see if an object is a wrapper (fail by default)
1965template <typename T, typename _ = void> struct is_wrapper : std::false_type {};
1966
1967// check if an object is a wrapper (it has a value_type defined)
1968template <typename T>
1969struct is_wrapper<T, conditional_t<false, void_t<typename T::value_type>, void>> : public std::true_type {};
1970
1971// Check for tuple like types, as in classes with a tuple_size type trait
1972// Even though in C++26 std::complex gains a std::tuple interface, for our purposes we treat is as NOT a tuple
1973template <typename S> class is_tuple_like {
1974 template <typename SS, enable_if_t<!is_complex<SS>::value, detail::enabler> = detail::dummy>
1975 // static auto test(int)
1976 // -> decltype(std::conditional<(std::tuple_size<SS>::value > 0), std::true_type, std::false_type>::type());
1977 static auto test(int) -> decltype(std::tuple_size<typename std::decay<SS>::type>::value, std::true_type{});
1978 template <typename> static auto test(...) -> std::false_type;
1979
1980 public:
1981 static constexpr bool value = decltype(test<S>(0))::value;
1982};
1983
1985template <typename T, typename Enable = void> struct type_count_base {
1986 static const int value{0};
1987};
1988
1990template <typename T>
1992 typename std::enable_if<!is_tuple_like<T>::value && !is_mutable_container<T>::value &&
1993 !std::is_void<T>::value>::type> {
1994 static constexpr int value{1};
1995};
1996
1998template <typename T>
1999struct type_count_base<T, typename std::enable_if<is_tuple_like<T>::value && !is_mutable_container<T>::value>::type> {
2000 static constexpr int value{// cppcheck-suppress unusedStructMember
2001 std::tuple_size<typename std::decay<T>::type>::value};
2002};
2003
2005template <typename T> struct type_count_base<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2006 static constexpr int value{type_count_base<typename T::value_type>::value};
2007};
2008
2010template <typename T, enable_if_t<std::is_convertible<T, std::string>::value, detail::enabler> = detail::dummy>
2011auto to_string(T &&value) -> decltype(std::forward<T>(value)) {
2012 return std::forward<T>(value);
2013}
2014
2016template <typename T,
2017 enable_if_t<std::is_constructible<std::string, T>::value && !std::is_convertible<T, std::string>::value,
2018 detail::enabler> = detail::dummy>
2019std::string to_string(T &&value) {
2020 return std::string(value); // NOLINT(google-readability-casting)
2021}
2022
2024template <typename T,
2025 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2026 is_ostreamable<T>::value,
2027 detail::enabler> = detail::dummy>
2028std::string to_string(T &&value) {
2029 std::stringstream stream;
2030 stream << value;
2031 return stream.str();
2032}
2033
2034// additional forward declarations
2035
2037template <typename T,
2038 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2039 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value == 1,
2040 detail::enabler> = detail::dummy>
2041inline std::string to_string(T &&value);
2042
2044template <typename T,
2045 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2046 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value >= 2,
2047 detail::enabler> = detail::dummy>
2048inline std::string to_string(T &&value);
2049
2051template <
2052 typename T,
2053 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2054 !is_ostreamable<T>::value && !is_readable_container<typename std::remove_const<T>::type>::value &&
2055 !is_tuple_like<T>::value,
2056 detail::enabler> = detail::dummy>
2057inline std::string to_string(T &&) {
2058 return {};
2059}
2060
2062template <typename T,
2063 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2064 !is_ostreamable<T>::value && is_readable_container<T>::value && !is_tuple_like<T>::value,
2065 detail::enabler> = detail::dummy>
2066inline std::string to_string(T &&variable) {
2067 auto cval = variable.begin();
2068 auto end = variable.end();
2069 if(cval == end) {
2070 return {"{}"};
2071 }
2072 std::vector<std::string> defaults;
2073 while(cval != end) {
2074 defaults.emplace_back(CLI::detail::to_string(*cval));
2075 ++cval;
2076 }
2077 return {"[" + detail::join(defaults) + "]"};
2078}
2079
2081
2083template <typename T, std::size_t I>
2084inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_value_string(T && /*value*/);
2085
2087template <typename T, std::size_t I>
2088inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_value_string(T &&value);
2089
2091template <typename T,
2092 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2093 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value == 1,
2094 detail::enabler>>
2095inline std::string to_string(T &&value) {
2096 return to_string(std::get<0>(value));
2097}
2098
2100template <typename T,
2101 enable_if_t<!std::is_convertible<T, std::string>::value && !std::is_constructible<std::string, T>::value &&
2102 !is_ostreamable<T>::value && is_tuple_like<T>::value && type_count_base<T>::value >= 2,
2103 detail::enabler>>
2104inline std::string to_string(T &&value) {
2105 auto tname = std::string(1, '[') + tuple_value_string<T, 0>(value);
2106 tname.push_back(']');
2107 return tname;
2108}
2109
2111template <typename T, std::size_t I>
2112inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_value_string(T && /*value*/) {
2113 return std::string{};
2114}
2115
2117template <typename T, std::size_t I>
2118inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_value_string(T &&value) {
2119 auto str = std::string{to_string(std::get<I>(value))} + ',' + tuple_value_string<T, I + 1>(value);
2120 if(str.back() == ',')
2121 str.pop_back();
2122 return str;
2123}
2124
2126template <typename T1,
2127 typename T2,
2128 typename T,
2129 enable_if_t<std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
2130auto checked_to_string(T &&value) -> decltype(to_string(std::forward<T>(value))) {
2131 return to_string(std::forward<T>(value));
2132}
2133
2135template <typename T1,
2136 typename T2,
2137 typename T,
2138 enable_if_t<!std::is_same<T1, T2>::value, detail::enabler> = detail::dummy>
2139std::string checked_to_string(T &&) {
2140 return std::string{};
2141}
2143template <typename T, enable_if_t<std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
2144std::string value_string(const T &value) {
2145 return std::to_string(value);
2146}
2148template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
2149std::string value_string(const T &value) {
2150 return std::to_string(static_cast<typename std::underlying_type<T>::type>(value));
2151}
2153template <typename T,
2154 enable_if_t<!std::is_enum<T>::value && !std::is_arithmetic<T>::value, detail::enabler> = detail::dummy>
2155auto value_string(const T &value) -> decltype(to_string(value)) {
2156 return to_string(value);
2157}
2158
2160template <typename T, typename def, typename Enable = void> struct wrapped_type {
2161 using type = def;
2162};
2163
2165template <typename T, typename def> struct wrapped_type<T, def, typename std::enable_if<is_wrapper<T>::value>::type> {
2166 using type = typename T::value_type;
2167};
2168
2170
2172template <typename T> struct subtype_count;
2173
2175template <typename T> struct subtype_count_min;
2176
2178template <typename T, typename Enable = void> struct type_count {
2179 static const int value{0};
2180};
2181
2183template <typename T>
2184struct type_count<T,
2185 typename std::enable_if<!is_wrapper<T>::value && !is_tuple_like<T>::value && !is_complex<T>::value &&
2186 !std::is_void<T>::value>::type> {
2187 static constexpr int value{1};
2188};
2189
2191template <typename T> struct type_count<T, typename std::enable_if<is_complex<T>::value>::type> {
2192 static constexpr int value{2};
2193};
2194
2196template <typename T> struct type_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2197 static constexpr int value{subtype_count<typename T::value_type>::value};
2198};
2199
2201template <typename T>
2202struct type_count<T,
2203 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value &&
2204 !is_mutable_container<T>::value>::type> {
2205 static constexpr int value{type_count<typename T::value_type>::value};
2206};
2207
2209template <typename T, std::size_t I>
2210constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size() {
2211 return 0;
2212}
2213
2215template <typename T, std::size_t I>
2216 constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size() {
2217 return subtype_count<typename std::tuple_element<I, T>::type>::value + tuple_type_size<T, I + 1>();
2218}
2219
2221template <typename T>
2222struct type_count<T, typename std::enable_if<is_tuple_like<T>::value && !is_complex<T>::value>::type> {
2223 static constexpr int value{tuple_type_size<T, 0>()};
2224};
2225
2227template <typename T> struct subtype_count {
2228 static constexpr int value{is_mutable_container<T>::value ? expected_max_vector_size : type_count<T>::value};
2229};
2230
2232template <typename T, typename Enable = void> struct type_count_min {
2233 static const int value{0};
2234};
2235
2237template <typename T>
2238struct type_count_min<
2239 T,
2240 typename std::enable_if<!is_mutable_container<T>::value && !is_tuple_like<T>::value && !is_wrapper<T>::value &&
2241 !is_complex<T>::value && !std::is_void<T>::value>::type> {
2242 static constexpr int value{type_count<T>::value};
2243};
2244
2246template <typename T> struct type_count_min<T, typename std::enable_if<is_complex<T>::value>::type> {
2247 static constexpr int value{1};
2248};
2249
2251template <typename T>
2252struct type_count_min<
2253 T,
2254 typename std::enable_if<is_wrapper<T>::value && !is_complex<T>::value && !is_tuple_like<T>::value>::type> {
2255 static constexpr int value{subtype_count_min<typename T::value_type>::value};
2256};
2257
2259template <typename T, std::size_t I>
2260constexpr typename std::enable_if<I == type_count_base<T>::value, int>::type tuple_type_size_min() {
2261 return 0;
2262}
2263
2265template <typename T, std::size_t I>
2266 constexpr typename std::enable_if < I<type_count_base<T>::value, int>::type tuple_type_size_min() {
2267 return subtype_count_min<typename std::tuple_element<I, T>::type>::value + tuple_type_size_min<T, I + 1>();
2268}
2269
2271template <typename T>
2272struct type_count_min<T, typename std::enable_if<is_tuple_like<T>::value && !is_complex<T>::value>::type> {
2273 static constexpr int value{tuple_type_size_min<T, 0>()};
2274};
2275
2277template <typename T> struct subtype_count_min {
2278 static constexpr int value{is_mutable_container<T>::value
2279 ? ((type_count<T>::value < expected_max_vector_size) ? type_count<T>::value : 0)
2280 : type_count_min<T>::value};
2281};
2282
2284template <typename T, typename Enable = void> struct expected_count {
2285 static const int value{0};
2286};
2287
2289template <typename T>
2290struct expected_count<T,
2291 typename std::enable_if<!is_mutable_container<T>::value && !is_wrapper<T>::value &&
2292 !std::is_void<T>::value>::type> {
2293 static constexpr int value{1};
2294};
2296template <typename T> struct expected_count<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2297 static constexpr int value{expected_max_vector_size};
2298};
2299
2301template <typename T>
2302struct expected_count<T, typename std::enable_if<!is_mutable_container<T>::value && is_wrapper<T>::value>::type> {
2303 static constexpr int value{expected_count<typename T::value_type>::value};
2304};
2305
2306// Enumeration of the different supported categorizations of objects
2307enum class object_category : std::uint8_t {
2308 char_value = 1,
2309 integral_value = 2,
2310 unsigned_integral = 4,
2311 enumeration = 6,
2312 boolean_value = 8,
2313 floating_point = 10,
2314 number_constructible = 12,
2315 double_constructible = 14,
2316 integer_constructible = 16,
2317 // string like types
2318 string_assignable = 23,
2319 string_constructible = 24,
2320 wstring_assignable = 25,
2321 wstring_constructible = 26,
2322 other = 45,
2323 // special wrapper or container types
2324 wrapper_value = 50,
2325 complex_number = 60,
2326 tuple_value = 70,
2327 container_value = 80,
2328
2329};
2330
2332
2334template <typename T, typename Enable = void> struct classify_object {
2335 static constexpr object_category value{object_category::other};
2336};
2337
2339template <typename T>
2340struct classify_object<
2341 T,
2342 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && std::is_signed<T>::value &&
2343 !is_bool<T>::value && !std::is_enum<T>::value>::type> {
2344 static constexpr object_category value{object_category::integral_value};
2345};
2346
2348template <typename T>
2349struct classify_object<T,
2350 typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value &&
2351 !std::is_same<T, char>::value && !is_bool<T>::value>::type> {
2352 static constexpr object_category value{object_category::unsigned_integral};
2353};
2354
2356template <typename T>
2357struct classify_object<T, typename std::enable_if<std::is_same<T, char>::value && !std::is_enum<T>::value>::type> {
2358 static constexpr object_category value{object_category::char_value};
2359};
2360
2362template <typename T> struct classify_object<T, typename std::enable_if<is_bool<T>::value>::type> {
2363 static constexpr object_category value{object_category::boolean_value};
2364};
2365
2367template <typename T> struct classify_object<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
2368 static constexpr object_category value{object_category::floating_point};
2369};
2370#if defined _MSC_VER
2371// in MSVC wstring should take precedence if available this isn't as useful on other compilers due to the broader use of
2372// utf-8 encoding
2373#define WIDE_STRING_CHECK \
2374 !std::is_assignable<T &, std::wstring>::value && !std::is_constructible<T, std::wstring>::value
2375#define STRING_CHECK true
2376#else
2377#define WIDE_STRING_CHECK true
2378#define STRING_CHECK !std::is_assignable<T &, std::string>::value && !std::is_constructible<T, std::string>::value
2379#endif
2380
2382template <typename T>
2383struct classify_object<
2384 T,
2385 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value && WIDE_STRING_CHECK &&
2386 std::is_assignable<T &, std::string>::value>::type> {
2387 static constexpr object_category value{object_category::string_assignable};
2388};
2389
2391template <typename T>
2392struct classify_object<
2393 T,
2394 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2395 !std::is_assignable<T &, std::string>::value && (type_count<T>::value == 1) &&
2396 WIDE_STRING_CHECK && std::is_constructible<T, std::string>::value>::type> {
2397 static constexpr object_category value{object_category::string_constructible};
2398};
2399
2401template <typename T>
2402struct classify_object<T,
2403 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2404 STRING_CHECK && std::is_assignable<T &, std::wstring>::value>::type> {
2405 static constexpr object_category value{object_category::wstring_assignable};
2406};
2407
2408template <typename T>
2409struct classify_object<
2410 T,
2411 typename std::enable_if<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2412 !std::is_assignable<T &, std::wstring>::value && (type_count<T>::value == 1) &&
2413 STRING_CHECK && std::is_constructible<T, std::wstring>::value>::type> {
2414 static constexpr object_category value{object_category::wstring_constructible};
2415};
2416
2418template <typename T> struct classify_object<T, typename std::enable_if<std::is_enum<T>::value>::type> {
2419 static constexpr object_category value{object_category::enumeration};
2420};
2421
2422template <typename T> struct classify_object<T, typename std::enable_if<is_complex<T>::value>::type> {
2423 static constexpr object_category value{object_category::complex_number};
2424};
2425
2428template <typename T> struct uncommon_type {
2429 using type = typename std::conditional<
2430 !std::is_floating_point<T>::value && !std::is_integral<T>::value &&
2431 !std::is_assignable<T &, std::string>::value && !std::is_constructible<T, std::string>::value &&
2432 !std::is_assignable<T &, std::wstring>::value && !std::is_constructible<T, std::wstring>::value &&
2433 !is_complex<T>::value && !is_mutable_container<T>::value && !std::is_enum<T>::value,
2434 std::true_type,
2435 std::false_type>::type;
2436 static constexpr bool value = type::value;
2437};
2438
2440template <typename T>
2441struct classify_object<T,
2442 typename std::enable_if<(!is_mutable_container<T>::value && is_wrapper<T>::value &&
2443 !is_tuple_like<T>::value && uncommon_type<T>::value)>::type> {
2444 static constexpr object_category value{object_category::wrapper_value};
2445};
2446
2448template <typename T>
2449struct classify_object<T,
2450 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2451 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
2452 is_direct_constructible<T, int>::value>::type> {
2453 static constexpr object_category value{object_category::number_constructible};
2454};
2455
2457template <typename T>
2458struct classify_object<T,
2459 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2460 !is_wrapper<T>::value && !is_direct_constructible<T, double>::value &&
2461 is_direct_constructible<T, int>::value>::type> {
2462 static constexpr object_category value{object_category::integer_constructible};
2463};
2464
2466template <typename T>
2467struct classify_object<T,
2468 typename std::enable_if<uncommon_type<T>::value && type_count<T>::value == 1 &&
2469 !is_wrapper<T>::value && is_direct_constructible<T, double>::value &&
2470 !is_direct_constructible<T, int>::value>::type> {
2471 static constexpr object_category value{object_category::double_constructible};
2472};
2473
2475template <typename T>
2476struct classify_object<
2477 T,
2478 typename std::enable_if<is_tuple_like<T>::value &&
2479 ((type_count<T>::value >= 2 && !is_wrapper<T>::value) ||
2480 (uncommon_type<T>::value && !is_direct_constructible<T, double>::value &&
2481 !is_direct_constructible<T, int>::value) ||
2482 (uncommon_type<T>::value && type_count<T>::value >= 2))>::type> {
2483 static constexpr object_category value{object_category::tuple_value};
2484 // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be
2485 // constructed from just the first element so tuples of <string, int,int> can be constructed from a string, which
2486 // could lead to issues so there are two variants of the condition, the first isolates things with a type size >=2
2487 // mainly to get tuples on Xcode with the exception of wrappers, the second is the main one and just separating out
2488 // those cases that are caught by other object classifications
2489};
2490
2492template <typename T> struct classify_object<T, typename std::enable_if<is_mutable_container<T>::value>::type> {
2493 static constexpr object_category value{object_category::container_value};
2494};
2495
2496// Type name print
2497
2501
2502template <typename T,
2503 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
2504constexpr const char *type_name() {
2505 return "CHAR";
2506}
2507
2508template <typename T,
2509 enable_if_t<classify_object<T>::value == object_category::integral_value ||
2510 classify_object<T>::value == object_category::integer_constructible,
2511 detail::enabler> = detail::dummy>
2512constexpr const char *type_name() {
2513 return "INT";
2514}
2515
2516template <typename T,
2517 enable_if_t<classify_object<T>::value == object_category::unsigned_integral, detail::enabler> = detail::dummy>
2518constexpr const char *type_name() {
2519 return "UINT";
2520}
2521
2522template <typename T,
2523 enable_if_t<classify_object<T>::value == object_category::floating_point ||
2524 classify_object<T>::value == object_category::number_constructible ||
2525 classify_object<T>::value == object_category::double_constructible,
2526 detail::enabler> = detail::dummy>
2527constexpr const char *type_name() {
2528 return "FLOAT";
2529}
2530
2532template <typename T,
2533 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
2534constexpr const char *type_name() {
2535 return "ENUM";
2536}
2537
2539template <typename T,
2540 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
2541constexpr const char *type_name() {
2542 return "BOOLEAN";
2543}
2544
2546template <typename T,
2547 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
2548constexpr const char *type_name() {
2549 return "COMPLEX";
2550}
2551
2553template <typename T,
2554 enable_if_t<classify_object<T>::value >= object_category::string_assignable &&
2555 classify_object<T>::value <= object_category::other,
2556 detail::enabler> = detail::dummy>
2557constexpr const char *type_name() {
2558 return "TEXT";
2559}
2561template <typename T,
2562 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
2563 detail::enabler> = detail::dummy>
2564std::string type_name(); // forward declaration
2565
2567template <typename T,
2568 enable_if_t<classify_object<T>::value == object_category::container_value ||
2569 classify_object<T>::value == object_category::wrapper_value,
2570 detail::enabler> = detail::dummy>
2571std::string type_name(); // forward declaration
2572
2574template <typename T,
2575 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value == 1,
2576 detail::enabler> = detail::dummy>
2577inline std::string type_name() {
2578 return type_name<typename std::decay<typename std::tuple_element<0, T>::type>::type>();
2579}
2580
2582template <typename T, std::size_t I>
2583inline typename std::enable_if<I == type_count_base<T>::value, std::string>::type tuple_name() {
2584 return std::string{};
2585}
2586
2588template <typename T, std::size_t I>
2589inline typename std::enable_if<(I < type_count_base<T>::value), std::string>::type tuple_name() {
2590 auto str = std::string{type_name<typename std::decay<typename std::tuple_element<I, T>::type>::type>()} + ',' +
2591 tuple_name<T, I + 1>();
2592 if(str.back() == ',')
2593 str.pop_back();
2594 return str;
2595}
2596
2598template <typename T,
2599 enable_if_t<classify_object<T>::value == object_category::tuple_value && type_count_base<T>::value >= 2,
2600 detail::enabler>>
2601inline std::string type_name() {
2602 auto tname = std::string(1, '[') + tuple_name<T, 0>();
2603 tname.push_back(']');
2604 return tname;
2605}
2606
2608template <typename T,
2609 enable_if_t<classify_object<T>::value == object_category::container_value ||
2610 classify_object<T>::value == object_category::wrapper_value,
2611 detail::enabler>>
2612inline std::string type_name() {
2613 return type_name<typename T::value_type>();
2614}
2615
2616// Lexical cast
2617
2619template <typename T, enable_if_t<std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
2620bool integral_conversion(const std::string &input, T &output) noexcept {
2621 if(input.empty() || input.front() == '-') {
2622 return false;
2623 }
2624 char *val{nullptr};
2625 errno = 0;
2626 std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0);
2627 if(errno == ERANGE) {
2628 return false;
2629 }
2630 output = static_cast<T>(output_ll);
2631 if(val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll) {
2632 return true;
2633 }
2634 val = nullptr;
2635 std::int64_t output_sll = std::strtoll(input.c_str(), &val, 0);
2636 if(val == (input.c_str() + input.size())) {
2637 output = (output_sll < 0) ? static_cast<T>(0) : static_cast<T>(output_sll);
2638 return (static_cast<std::int64_t>(output) == output_sll);
2639 }
2640 // remove separators if present
2641 auto group_separators = get_group_separators();
2642 if(input.find_first_of(group_separators) != std::string::npos) {
2643 std::string nstring = input;
2644 for(auto &separator : group_separators) {
2645 if(input.find_first_of(separator) != std::string::npos) {
2646 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2647 }
2648 }
2649 return integral_conversion(nstring, output);
2650 }
2651
2652 if(std::isspace(static_cast<unsigned char>(input.back()))) {
2653 return integral_conversion(trim_copy(input), output);
2654 }
2655 if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) {
2656 val = nullptr;
2657 errno = 0;
2658 output_ll = std::strtoull(input.c_str() + 2, &val, 8);
2659 if(errno == ERANGE) {
2660 return false;
2661 }
2662 output = static_cast<T>(output_ll);
2663 return (val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll);
2664 }
2665 if(input.compare(0, 2, "0b") == 0 || input.compare(0, 2, "0B") == 0) {
2666 // LCOV_EXCL_START
2667 // In some new compilers including the coverage testing one binary strings are handled properly in strtoull
2668 // automatically so this coverage is missing but is well tested in other compilers
2669 val = nullptr;
2670 errno = 0;
2671 output_ll = std::strtoull(input.c_str() + 2, &val, 2);
2672 if(errno == ERANGE) {
2673 return false;
2674 }
2675 output = static_cast<T>(output_ll);
2676 return (val == (input.c_str() + input.size()) && static_cast<std::uint64_t>(output) == output_ll);
2677 // LCOV_EXCL_STOP
2678 }
2679 return false;
2680}
2681
2683template <typename T, enable_if_t<std::is_signed<T>::value, detail::enabler> = detail::dummy>
2684bool integral_conversion(const std::string &input, T &output) noexcept {
2685 if(input.empty()) {
2686 return false;
2687 }
2688 char *val = nullptr;
2689 errno = 0;
2690 std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0);
2691 if(errno == ERANGE) {
2692 return false;
2693 }
2694 output = static_cast<T>(output_ll);
2695 if(val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll) {
2696 return true;
2697 }
2698 if(input == "true") {
2699 // this is to deal with a few oddities with flags and wrapper int types
2700 output = static_cast<T>(1);
2701 return true;
2702 }
2703 // remove separators if present
2704 auto group_separators = get_group_separators();
2705 if(input.find_first_of(group_separators) != std::string::npos) {
2706 for(auto &separator : group_separators) {
2707 if(input.find_first_of(separator) != std::string::npos) {
2708 std::string nstring = input;
2709 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2710 return integral_conversion(nstring, output);
2711 }
2712 }
2713 }
2714 if(std::isspace(static_cast<unsigned char>(input.back()))) {
2715 return integral_conversion(trim_copy(input), output);
2716 }
2717 if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) {
2718 val = nullptr;
2719 errno = 0;
2720 output_ll = std::strtoll(input.c_str() + 2, &val, 8);
2721 if(errno == ERANGE) {
2722 return false;
2723 }
2724 output = static_cast<T>(output_ll);
2725 return (val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll);
2726 }
2727 if(input.compare(0, 2, "0b") == 0 || input.compare(0, 2, "0B") == 0) {
2728 // LCOV_EXCL_START
2729 // In some new compilers including the coverage testing one binary strings are handled properly in strtoll
2730 // automatically so this coverage is missing but is well tested in other compilers
2731 val = nullptr;
2732 errno = 0;
2733 output_ll = std::strtoll(input.c_str() + 2, &val, 2);
2734 if(errno == ERANGE) {
2735 return false;
2736 }
2737 output = static_cast<T>(output_ll);
2738 return (val == (input.c_str() + input.size()) && static_cast<std::int64_t>(output) == output_ll);
2739 // LCOV_EXCL_STOP
2740 }
2741 return false;
2742}
2743
2745inline std::int64_t to_flag_value(std::string val) noexcept {
2746 static const std::string trueString("true");
2747 static const std::string falseString("false");
2748 if(val == trueString) {
2749 return 1;
2750 }
2751 if(val == falseString) {
2752 return -1;
2753 }
2754 val = detail::to_lower(val);
2755 std::int64_t ret = 0;
2756 if(val.size() == 1) {
2757 if(val[0] >= '1' && val[0] <= '9') {
2758 return (static_cast<std::int64_t>(val[0]) - '0');
2759 }
2760 switch(val[0]) {
2761 case '0':
2762 case 'f':
2763 case 'n':
2764 case '-':
2765 ret = -1;
2766 break;
2767 case 't':
2768 case 'y':
2769 case '+':
2770 ret = 1;
2771 break;
2772 default:
2773 errno = EINVAL;
2774 return -1;
2775 }
2776 return ret;
2777 }
2778 if(val == trueString || val == "on" || val == "yes" || val == "enable") {
2779 ret = 1;
2780 } else if(val == falseString || val == "off" || val == "no" || val == "disable") {
2781 ret = -1;
2782 } else {
2783 char *loc_ptr{nullptr};
2784 ret = std::strtoll(val.c_str(), &loc_ptr, 0);
2785 if(loc_ptr != (val.c_str() + val.size()) && errno == 0) {
2786 errno = EINVAL;
2787 }
2788 }
2789 return ret;
2790}
2791
2793template <typename T,
2794 enable_if_t<classify_object<T>::value == object_category::integral_value ||
2795 classify_object<T>::value == object_category::unsigned_integral,
2796 detail::enabler> = detail::dummy>
2797bool lexical_cast(const std::string &input, T &output) {
2798 return integral_conversion(input, output);
2799}
2800
2802template <typename T,
2803 enable_if_t<classify_object<T>::value == object_category::char_value, detail::enabler> = detail::dummy>
2804bool lexical_cast(const std::string &input, T &output) {
2805 if(input.size() == 1) {
2806 output = static_cast<T>(input[0]);
2807 return true;
2808 }
2809 std::int8_t res{0};
2810 // we do it this way as some systems have char as signed and not, this ensures consistency in the way things are
2811 // handled
2812 bool result = integral_conversion(input, res);
2813 if(result) {
2814 output = static_cast<T>(res);
2815 }
2816 return result;
2817}
2818
2820template <typename T,
2821 enable_if_t<classify_object<T>::value == object_category::boolean_value, detail::enabler> = detail::dummy>
2822bool lexical_cast(const std::string &input, T &output) {
2823 errno = 0;
2824 auto out = to_flag_value(input);
2825 if(errno == 0) {
2826 output = (out > 0);
2827 } else if(errno == ERANGE) {
2828 output = (input[0] != '-');
2829 } else {
2830 return false;
2831 }
2832 return true;
2833}
2834
2836template <typename T,
2837 enable_if_t<classify_object<T>::value == object_category::floating_point, detail::enabler> = detail::dummy>
2838bool lexical_cast(const std::string &input, T &output) {
2839 if(input.empty()) {
2840 return false;
2841 }
2842 char *val = nullptr;
2843 auto output_ld = std::strtold(input.c_str(), &val);
2844 output = static_cast<T>(output_ld);
2845 if(val == (input.c_str() + input.size())) {
2846 return true;
2847 }
2848 while(std::isspace(static_cast<unsigned char>(*val))) {
2849 ++val;
2850 if(val == (input.c_str() + input.size())) {
2851 return true;
2852 }
2853 }
2854
2855 // remove separators if present
2856 auto group_separators = get_group_separators();
2857 if(input.find_first_of(group_separators) != std::string::npos) {
2858 for(auto &separator : group_separators) {
2859 if(input.find_first_of(separator) != std::string::npos) {
2860 std::string nstring = input;
2861 nstring.erase(std::remove(nstring.begin(), nstring.end(), separator), nstring.end());
2862 return lexical_cast(nstring, output);
2863 }
2864 }
2865 }
2866 return false;
2867}
2868
2870template <typename T,
2871 enable_if_t<classify_object<T>::value == object_category::complex_number, detail::enabler> = detail::dummy>
2872bool lexical_cast(const std::string &input, T &output) {
2873 using XC = typename wrapped_type<T, double>::type;
2874 XC x{0.0}, y{0.0};
2875 auto str1 = input;
2876 bool worked = false;
2877 auto nloc = str1.find_last_of("+-");
2878 if(nloc != std::string::npos && nloc > 0) {
2879 worked = lexical_cast(str1.substr(0, nloc), x);
2880 str1 = str1.substr(nloc);
2881 if(str1.back() == 'i' || str1.back() == 'j')
2882 str1.pop_back();
2883 worked = worked && lexical_cast(str1, y);
2884 } else {
2885 if(str1.back() == 'i' || str1.back() == 'j') {
2886 str1.pop_back();
2887 worked = lexical_cast(str1, y);
2888 x = XC{0};
2889 } else {
2890 worked = lexical_cast(str1, x);
2891 y = XC{0};
2892 }
2893 }
2894 if(worked) {
2895 output = T{x, y};
2896 return worked;
2897 }
2898 return from_stream(input, output);
2899}
2900
2902template <typename T,
2903 enable_if_t<classify_object<T>::value == object_category::string_assignable, detail::enabler> = detail::dummy>
2904bool lexical_cast(const std::string &input, T &output) {
2905 output = input;
2906 return true;
2907}
2908
2910template <
2911 typename T,
2912 enable_if_t<classify_object<T>::value == object_category::string_constructible, detail::enabler> = detail::dummy>
2913bool lexical_cast(const std::string &input, T &output) {
2914 output = T(input);
2915 return true;
2916}
2917
2919template <
2920 typename T,
2921 enable_if_t<classify_object<T>::value == object_category::wstring_assignable, detail::enabler> = detail::dummy>
2922bool lexical_cast(const std::string &input, T &output) {
2923 output = widen(input);
2924 return true;
2925}
2926
2927template <
2928 typename T,
2929 enable_if_t<classify_object<T>::value == object_category::wstring_constructible, detail::enabler> = detail::dummy>
2930bool lexical_cast(const std::string &input, T &output) {
2931 output = T{widen(input)};
2932 return true;
2933}
2934
2936template <typename T,
2937 enable_if_t<classify_object<T>::value == object_category::enumeration, detail::enabler> = detail::dummy>
2938bool lexical_cast(const std::string &input, T &output) {
2939 typename std::underlying_type<T>::type val;
2940 if(!integral_conversion(input, val)) {
2941 return false;
2942 }
2943 output = static_cast<T>(val);
2944 return true;
2945}
2946
2948template <typename T,
2949 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
2950 std::is_assignable<T &, typename T::value_type>::value,
2951 detail::enabler> = detail::dummy>
2952bool lexical_cast(const std::string &input, T &output) {
2953 typename T::value_type val;
2954 if(lexical_cast(input, val)) {
2955 output = val;
2956 return true;
2957 }
2958 return from_stream(input, output);
2959}
2960
2961template <typename T,
2962 enable_if_t<classify_object<T>::value == object_category::wrapper_value &&
2963 !std::is_assignable<T &, typename T::value_type>::value && std::is_assignable<T &, T>::value,
2964 detail::enabler> = detail::dummy>
2965bool lexical_cast(const std::string &input, T &output) {
2966 typename T::value_type val;
2967 if(lexical_cast(input, val)) {
2968 output = T{val};
2969 return true;
2970 }
2971 return from_stream(input, output);
2972}
2973
2975template <
2976 typename T,
2977 enable_if_t<classify_object<T>::value == object_category::number_constructible, detail::enabler> = detail::dummy>
2978bool lexical_cast(const std::string &input, T &output) {
2979 int val = 0;
2980 if(integral_conversion(input, val)) {
2981 output = T(val);
2982 return true;
2983 }
2984
2985 double dval = 0.0;
2986 if(lexical_cast(input, dval)) {
2987 output = T{dval};
2988 return true;
2989 }
2990
2991 return from_stream(input, output);
2992}
2993
2995template <
2996 typename T,
2997 enable_if_t<classify_object<T>::value == object_category::integer_constructible, detail::enabler> = detail::dummy>
2998bool lexical_cast(const std::string &input, T &output) {
2999 int val = 0;
3000 if(integral_conversion(input, val)) {
3001 output = T(val);
3002 return true;
3003 }
3004 return from_stream(input, output);
3005}
3006
3008template <
3009 typename T,
3010 enable_if_t<classify_object<T>::value == object_category::double_constructible, detail::enabler> = detail::dummy>
3011bool lexical_cast(const std::string &input, T &output) {
3012 double val = 0.0;
3013 if(lexical_cast(input, val)) {
3014 output = T{val};
3015 return true;
3016 }
3017 return from_stream(input, output);
3018}
3019
3021template <typename T,
3022 enable_if_t<classify_object<T>::value == object_category::other && std::is_assignable<T &, int>::value,
3023 detail::enabler> = detail::dummy>
3024bool lexical_cast(const std::string &input, T &output) {
3025 int val = 0;
3026 if(integral_conversion(input, val)) {
3027#ifdef _MSC_VER
3028#pragma warning(push)
3029#pragma warning(disable : 4800)
3030#endif
3031 // with Atomic<XX> this could produce a warning due to the conversion but if atomic gets here it is an old style
3032 // so will most likely still work
3033 output = val;
3034#ifdef _MSC_VER
3035#pragma warning(pop)
3036#endif
3037 return true;
3038 }
3039 // LCOV_EXCL_START
3040 // This version of cast is only used for odd cases in an older compilers the fail over
3041 // from_stream is tested elsewhere an not relevant for coverage here
3042 return from_stream(input, output);
3043 // LCOV_EXCL_STOP
3044}
3045
3047template <typename T,
3048 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value &&
3049 is_istreamable<T>::value,
3050 detail::enabler> = detail::dummy>
3051bool lexical_cast(const std::string &input, T &output) {
3052 return from_stream(input, output);
3053}
3054
3057template <typename T,
3058 enable_if_t<classify_object<T>::value == object_category::other && !std::is_assignable<T &, int>::value &&
3059 !is_istreamable<T>::value && !adl_detail::is_lexical_castable<T>::value,
3060 detail::enabler> = detail::dummy>
3061bool lexical_cast(const std::string & /*input*/, T & /*output*/) {
3062 static_assert(!std::is_same<T, T>::value, // Can't just write false here.
3063 "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it "
3064 "is convertible from another type use the add_option<T, XC>(...) with XC being the known type");
3065 return false;
3066}
3067
3070template <typename AssignTo,
3071 typename ConvertTo,
3072 enable_if_t<std::is_same<AssignTo, ConvertTo>::value &&
3073 (classify_object<AssignTo>::value == object_category::string_assignable ||
3074 classify_object<AssignTo>::value == object_category::string_constructible ||
3075 classify_object<AssignTo>::value == object_category::wstring_assignable ||
3076 classify_object<AssignTo>::value == object_category::wstring_constructible),
3077 detail::enabler> = detail::dummy>
3078bool lexical_assign(const std::string &input, AssignTo &output) {
3079 return lexical_cast(input, output);
3080}
3081
3083template <typename AssignTo,
3084 typename ConvertTo,
3085 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, AssignTo>::value &&
3086 classify_object<AssignTo>::value != object_category::string_assignable &&
3087 classify_object<AssignTo>::value != object_category::string_constructible &&
3088 classify_object<AssignTo>::value != object_category::wstring_assignable &&
3089 classify_object<AssignTo>::value != object_category::wstring_constructible,
3090 detail::enabler> = detail::dummy>
3091bool lexical_assign(const std::string &input, AssignTo &output) {
3092 if(input.empty()) {
3093 output = AssignTo{};
3094 return true;
3095 }
3096
3097 return lexical_cast(input, output);
3098} // LCOV_EXCL_LINE
3099
3101template <typename AssignTo,
3102 typename ConvertTo,
3103 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
3104 classify_object<AssignTo>::value == object_category::wrapper_value,
3105 detail::enabler> = detail::dummy>
3106bool lexical_assign(const std::string &input, AssignTo &output) {
3107 if(input.empty()) {
3108 typename AssignTo::value_type emptyVal{};
3109 output = emptyVal;
3110 return true;
3111 }
3112 return lexical_cast(input, output);
3113}
3114
3117template <typename AssignTo,
3118 typename ConvertTo,
3119 enable_if_t<std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, AssignTo>::value &&
3120 classify_object<AssignTo>::value != object_category::wrapper_value &&
3121 std::is_assignable<AssignTo &, int>::value,
3122 detail::enabler> = detail::dummy>
3123bool lexical_assign(const std::string &input, AssignTo &output) {
3124 if(input.empty()) {
3125 output = 0;
3126 return true;
3127 }
3128 int val{0};
3129 if(lexical_cast(input, val)) {
3130#if defined(__clang__)
3131/* on some older clang compilers */
3132#pragma clang diagnostic push
3133#pragma clang diagnostic ignored "-Wsign-conversion"
3134#endif
3135 output = val;
3136#if defined(__clang__)
3137#pragma clang diagnostic pop
3138#endif
3139 return true;
3140 }
3141 return false;
3142}
3143
3145template <typename AssignTo,
3146 typename ConvertTo,
3147 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && std::is_assignable<AssignTo &, ConvertTo &>::value,
3148 detail::enabler> = detail::dummy>
3149bool lexical_assign(const std::string &input, AssignTo &output) {
3150 ConvertTo val{};
3151 bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true;
3152 if(parse_result) {
3153 output = val;
3154 }
3155 return parse_result;
3156}
3157
3159template <
3160 typename AssignTo,
3161 typename ConvertTo,
3162 enable_if_t<!std::is_same<AssignTo, ConvertTo>::value && !std::is_assignable<AssignTo &, ConvertTo &>::value &&
3163 std::is_move_assignable<AssignTo>::value,
3164 detail::enabler> = detail::dummy>
3165bool lexical_assign(const std::string &input, AssignTo &output) {
3166 ConvertTo val{};
3167 bool parse_result = input.empty() ? true : lexical_cast(input, val);
3168 if(parse_result) {
3169 output = AssignTo(val); // use () form of constructor to allow some implicit conversions
3170 }
3171 return parse_result;
3172}
3173
3175template <typename AssignTo,
3176 typename ConvertTo,
3177 enable_if_t<classify_object<ConvertTo>::value <= object_category::other &&
3178 classify_object<AssignTo>::value <= object_category::wrapper_value,
3179 detail::enabler> = detail::dummy>
3180bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3181 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3182}
3183
3186template <typename AssignTo,
3187 typename ConvertTo,
3188 enable_if_t<(type_count<AssignTo>::value <= 2) && expected_count<AssignTo>::value == 1 &&
3189 is_tuple_like<ConvertTo>::value && type_count_base<ConvertTo>::value == 2,
3190 detail::enabler> = detail::dummy>
3191bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3192 // the remove const is to handle pair types coming from a container
3193 using FirstType = typename std::remove_const<typename std::tuple_element<0, ConvertTo>::type>::type;
3194 using SecondType = typename std::tuple_element<1, ConvertTo>::type;
3195 FirstType v1;
3196 SecondType v2{};
3197 bool retval = lexical_assign<FirstType, FirstType>(strings[0], v1);
3198 retval = retval && lexical_assign<SecondType, SecondType>((strings.size() > 1) ? strings[1] : std::string{}, v2);
3199 if(retval) {
3200 output = AssignTo{v1, v2};
3201 }
3202 return retval;
3203}
3204
3206template <class AssignTo,
3207 class ConvertTo,
3208 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3209 type_count<ConvertTo>::value == 1,
3210 detail::enabler> = detail::dummy>
3211bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3212 output.erase(output.begin(), output.end());
3213 if(strings.empty()) {
3214 return true;
3215 }
3216 if(strings.size() == 1 && strings[0] == "{}") {
3217 return true;
3218 }
3219 bool skip_remaining = false;
3220 if(strings.size() == 2 && strings[0] == "{}" && is_separator(strings[1])) {
3221 skip_remaining = true;
3222 }
3223 for(const auto &elem : strings) {
3224 typename AssignTo::value_type out;
3225 bool retval = lexical_assign<typename AssignTo::value_type, typename ConvertTo::value_type>(elem, out);
3226 if(!retval) {
3227 return false;
3228 }
3229 output.insert(output.end(), std::move(out));
3230 if(skip_remaining) {
3231 break;
3232 }
3233 }
3234 return (!output.empty());
3235}
3236
3238template <class AssignTo, class ConvertTo, enable_if_t<is_complex<ConvertTo>::value, detail::enabler> = detail::dummy>
3239bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
3240
3241 if(strings.size() >= 2 && !strings[1].empty()) {
3242 using XC2 = typename wrapped_type<ConvertTo, double>::type;
3243 XC2 x{0.0}, y{0.0};
3244 auto str1 = strings[1];
3245 if(str1.back() == 'i' || str1.back() == 'j') {
3246 str1.pop_back();
3247 }
3248 auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y);
3249 if(worked) {
3250 output = ConvertTo{x, y};
3251 }
3252 return worked;
3253 }
3254 return lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3255}
3256
3258template <class AssignTo,
3259 class ConvertTo,
3260 enable_if_t<is_mutable_container<AssignTo>::value && (expected_count<ConvertTo>::value == 1) &&
3261 (type_count<ConvertTo>::value == 1),
3262 detail::enabler> = detail::dummy>
3263bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3264 bool retval = true;
3265 output.clear();
3266 output.reserve(strings.size());
3267 for(const auto &elem : strings) {
3268
3269 output.emplace_back();
3270 retval = retval && lexical_assign<typename AssignTo::value_type, ConvertTo>(elem, output.back());
3271 }
3272 return (!output.empty()) && retval;
3273}
3274
3275// forward declaration
3276
3278template <class AssignTo,
3279 class ConvertTo,
3280 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3281 type_count_base<ConvertTo>::value == 2,
3282 detail::enabler> = detail::dummy>
3283bool lexical_conversion(std::vector<std::string> strings, AssignTo &output);
3284
3286template <class AssignTo,
3287 class ConvertTo,
3288 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3289 type_count_base<ConvertTo>::value != 2 &&
3290 ((type_count<ConvertTo>::value > 2) ||
3291 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
3292 detail::enabler> = detail::dummy>
3293bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output);
3294
3296template <class AssignTo,
3297 class ConvertTo,
3298 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
3299 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
3300 type_count<ConvertTo>::value > 2),
3301 detail::enabler> = detail::dummy>
3302bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output); // forward declaration
3303
3306template <typename AssignTo,
3307 typename ConvertTo,
3308 enable_if_t<!is_tuple_like<AssignTo>::value && !is_mutable_container<AssignTo>::value &&
3309 classify_object<ConvertTo>::value != object_category::wrapper_value &&
3310 (is_mutable_container<ConvertTo>::value || type_count<ConvertTo>::value > 2),
3311 detail::enabler> = detail::dummy>
3312bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3313
3314 if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) {
3315 ConvertTo val;
3316 auto retval = lexical_conversion<ConvertTo, ConvertTo>(strings, val);
3317 output = AssignTo{val};
3318 return retval;
3319 }
3320 output = AssignTo{};
3321 return true;
3322}
3323
3325template <class AssignTo, class ConvertTo, std::size_t I>
3326inline typename std::enable_if<(I >= type_count_base<AssignTo>::value), bool>::type
3327tuple_conversion(const std::vector<std::string> &, AssignTo &) {
3328 return true;
3329}
3330
3332template <class AssignTo, class ConvertTo>
3333inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && type_count<ConvertTo>::value == 1, bool>::type
3334tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3335 auto retval = lexical_assign<AssignTo, ConvertTo>(strings[0], output);
3336 strings.erase(strings.begin());
3337 return retval;
3338}
3339
3341template <class AssignTo, class ConvertTo>
3342inline typename std::enable_if<!is_mutable_container<ConvertTo>::value && (type_count<ConvertTo>::value > 1) &&
3343 type_count<ConvertTo>::value == type_count_min<ConvertTo>::value,
3344 bool>::type
3345tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3346 auto retval = lexical_conversion<AssignTo, ConvertTo>(strings, output);
3347 strings.erase(strings.begin(), strings.begin() + type_count<ConvertTo>::value);
3348 return retval;
3349}
3350
3352template <class AssignTo, class ConvertTo>
3353inline typename std::enable_if<is_mutable_container<ConvertTo>::value ||
3354 type_count<ConvertTo>::value != type_count_min<ConvertTo>::value,
3355 bool>::type
3356tuple_type_conversion(std::vector<std::string> &strings, AssignTo &output) {
3357
3358 std::size_t index{subtype_count_min<ConvertTo>::value};
3359 const std::size_t mx_count{subtype_count<ConvertTo>::value};
3360 const std::size_t mx{(std::min)(mx_count, strings.size() - 1)};
3361
3362 while(index < mx) {
3363 if(is_separator(strings[index])) {
3364 break;
3365 }
3366 ++index;
3367 }
3368 bool retval = lexical_conversion<AssignTo, ConvertTo>(
3369 std::vector<std::string>(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index)), output);
3370 if(strings.size() > index) {
3371 strings.erase(strings.begin(), strings.begin() + static_cast<std::ptrdiff_t>(index) + 1);
3372 } else {
3373 strings.clear();
3374 }
3375 return retval;
3376}
3377
3379template <class AssignTo, class ConvertTo, std::size_t I>
3380inline typename std::enable_if<(I < type_count_base<AssignTo>::value), bool>::type
3381tuple_conversion(std::vector<std::string> strings, AssignTo &output) {
3382 bool retval = true;
3383 using ConvertToElement = typename std::
3384 conditional<is_tuple_like<ConvertTo>::value, typename std::tuple_element<I, ConvertTo>::type, ConvertTo>::type;
3385 if(!strings.empty()) {
3386 retval = retval && tuple_type_conversion<typename std::tuple_element<I, AssignTo>::type, ConvertToElement>(
3387 strings, std::get<I>(output));
3388 }
3389 retval = retval && tuple_conversion<AssignTo, ConvertTo, I + 1>(std::move(strings), output);
3390 return retval;
3391}
3392
3394template <class AssignTo,
3395 class ConvertTo,
3396 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3397 type_count_base<ConvertTo>::value == 2,
3398 detail::enabler>>
3399bool lexical_conversion(std::vector<std::string> strings, AssignTo &output) {
3400 output.clear();
3401 while(!strings.empty()) {
3402
3403 typename std::remove_const<typename std::tuple_element<0, typename ConvertTo::value_type>::type>::type v1;
3404 typename std::tuple_element<1, typename ConvertTo::value_type>::type v2;
3405 bool retval = tuple_type_conversion<decltype(v1), decltype(v1)>(strings, v1);
3406 if(!strings.empty()) {
3407 retval = retval && tuple_type_conversion<decltype(v2), decltype(v2)>(strings, v2);
3408 }
3409 if(retval) {
3410 output.insert(output.end(), typename AssignTo::value_type{v1, v2});
3411 } else {
3412 return false;
3413 }
3414 }
3415 return (!output.empty());
3416}
3417
3419template <class AssignTo,
3420 class ConvertTo,
3421 enable_if_t<is_tuple_like<AssignTo>::value && is_tuple_like<ConvertTo>::value &&
3422 (type_count_base<ConvertTo>::value != type_count<ConvertTo>::value ||
3423 type_count<ConvertTo>::value > 2),
3424 detail::enabler>>
3425bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3426 static_assert(
3427 !is_tuple_like<ConvertTo>::value || type_count_base<AssignTo>::value == type_count_base<ConvertTo>::value,
3428 "if the conversion type is defined as a tuple it must be the same size as the type you are converting to");
3429 return tuple_conversion<AssignTo, ConvertTo, 0>(strings, output);
3430}
3431
3433template <class AssignTo,
3434 class ConvertTo,
3435 enable_if_t<is_mutable_container<AssignTo>::value && is_mutable_container<ConvertTo>::value &&
3436 type_count_base<ConvertTo>::value != 2 &&
3437 ((type_count<ConvertTo>::value > 2) ||
3438 (type_count<ConvertTo>::value > type_count_base<ConvertTo>::value)),
3439 detail::enabler>>
3440bool lexical_conversion(const std::vector<std ::string> &strings, AssignTo &output) {
3441 bool retval = true;
3442 output.clear();
3443 std::vector<std::string> temp;
3444 std::size_t ii{0};
3445 std::size_t icount{0};
3446 std::size_t xcm{type_count<ConvertTo>::value};
3447 auto ii_max = strings.size();
3448 while(ii < ii_max) {
3449 temp.push_back(strings[ii]);
3450 ++ii;
3451 ++icount;
3452 if(icount == xcm || is_separator(temp.back()) || ii == ii_max) {
3453 if(static_cast<int>(xcm) > type_count_min<ConvertTo>::value && is_separator(temp.back())) {
3454 temp.pop_back();
3455 }
3456 typename AssignTo::value_type temp_out;
3457 retval = retval &&
3458 lexical_conversion<typename AssignTo::value_type, typename ConvertTo::value_type>(temp, temp_out);
3459 temp.clear();
3460 if(!retval) {
3461 return false;
3462 }
3463 output.insert(output.end(), std::move(temp_out));
3464 icount = 0;
3465 }
3466 }
3467 return retval;
3468}
3469
3471template <typename AssignTo,
3472 class ConvertTo,
3473 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
3474 std::is_assignable<ConvertTo &, ConvertTo>::value,
3475 detail::enabler> = detail::dummy>
3476bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
3477 if(strings.empty() || strings.front().empty()) {
3478 output = ConvertTo{};
3479 return true;
3480 }
3481 typename ConvertTo::value_type val;
3482 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
3483 output = ConvertTo{val};
3484 return true;
3485 }
3486 return false;
3487}
3488
3490template <typename AssignTo,
3491 class ConvertTo,
3492 enable_if_t<classify_object<ConvertTo>::value == object_category::wrapper_value &&
3493 !std::is_assignable<AssignTo &, ConvertTo>::value,
3494 detail::enabler> = detail::dummy>
3495bool lexical_conversion(const std::vector<std::string> &strings, AssignTo &output) {
3496 using ConvertType = typename ConvertTo::value_type;
3497 if(strings.empty() || strings.front().empty()) {
3498 output = ConvertType{};
3499 return true;
3500 }
3501 ConvertType val;
3502 if(lexical_conversion<typename ConvertTo::value_type, typename ConvertTo::value_type>(strings, val)) {
3503 output = val;
3504 return true;
3505 }
3506 return false;
3507}
3508
3510inline std::string sum_string_vector(const std::vector<std::string> &values) {
3511 double val{0.0};
3512 bool fail{false};
3513 std::string output;
3514 for(const auto &arg : values) {
3515 double tv{0.0};
3516 auto comp = lexical_cast(arg, tv);
3517 if(!comp) {
3518 errno = 0;
3519 auto fv = detail::to_flag_value(arg);
3520 fail = (errno != 0);
3521 if(fail) {
3522 break;
3523 }
3524 tv = static_cast<double>(fv);
3525 }
3526 val += tv;
3527 }
3528 if(fail) {
3529 for(const auto &arg : values) {
3530 output.append(arg);
3531 }
3532 } else {
3533 std::ostringstream out;
3534 out.precision(16);
3535 out << val;
3536 output = out.str();
3537 }
3538 return output;
3539}
3540
3541} // namespace detail
3542
3543
3544
3545namespace detail {
3546
3547// Returns false if not a short option. Otherwise, sets opt name and rest and returns true
3548CLI11_INLINE bool split_short(const std::string &current, std::string &name, std::string &rest);
3549
3550// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true
3551CLI11_INLINE bool split_long(const std::string &current, std::string &name, std::string &value);
3552
3553// Returns false if not a windows style option. Otherwise, sets opt name and value and returns true
3554CLI11_INLINE bool split_windows_style(const std::string &current, std::string &name, std::string &value);
3555
3556// Splits a string into multiple long and short names
3557CLI11_INLINE std::vector<std::string> split_names(std::string current);
3558
3560CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(const std::string &str);
3561
3563CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
3564get_names(const std::vector<std::string> &input, bool allow_non_standard = false);
3565
3566} // namespace detail
3567
3568
3569
3570namespace detail {
3571
3572CLI11_INLINE bool split_short(const std::string &current, std::string &name, std::string &rest) {
3573 if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) {
3574 name = current.substr(1, 1);
3575 rest = current.substr(2);
3576 return true;
3577 }
3578 return false;
3579}
3580
3581CLI11_INLINE bool split_long(const std::string &current, std::string &name, std::string &value) {
3582 if(current.size() > 2 && current.compare(0, 2, "--") == 0 && valid_first_char(current[2])) {
3583 auto loc = current.find_first_of('=');
3584 if(loc != std::string::npos) {
3585 name = current.substr(2, loc - 2);
3586 value = current.substr(loc + 1);
3587 } else {
3588 name = current.substr(2);
3589 value = "";
3590 }
3591 return true;
3592 }
3593 return false;
3594}
3595
3596CLI11_INLINE bool split_windows_style(const std::string &current, std::string &name, std::string &value) {
3597 if(current.size() > 1 && current[0] == '/' && valid_first_char(current[1])) {
3598 auto loc = current.find_first_of(':');
3599 if(loc != std::string::npos) {
3600 name = current.substr(1, loc - 1);
3601 value = current.substr(loc + 1);
3602 } else {
3603 name = current.substr(1);
3604 value = "";
3605 }
3606 return true;
3607 }
3608 return false;
3609}
3610
3611CLI11_INLINE std::vector<std::string> split_names(std::string current) {
3612 std::vector<std::string> output;
3613 std::size_t val = 0;
3614 while((val = current.find(',')) != std::string::npos) {
3615 output.push_back(trim_copy(current.substr(0, val)));
3616 current = current.substr(val + 1);
3617 }
3618 output.push_back(trim_copy(current));
3619 return output;
3620}
3621
3622CLI11_INLINE std::vector<std::pair<std::string, std::string>> get_default_flag_values(const std::string &str) {
3623 std::vector<std::string> flags = split_names(str);
3624 flags.erase(std::remove_if(flags.begin(),
3625 flags.end(),
3626 [](const std::string &name) {
3627 return ((name.empty()) || (!(((name.find_first_of('{') != std::string::npos) &&
3628 (name.back() == '}')) ||
3629 (name[0] == '!'))));
3630 }),
3631 flags.end());
3632 std::vector<std::pair<std::string, std::string>> output;
3633 output.reserve(flags.size());
3634 for(auto &flag : flags) {
3635 auto def_start = flag.find_first_of('{');
3636 std::string defval = "false";
3637 if((def_start != std::string::npos) && (flag.back() == '}')) {
3638 defval = flag.substr(def_start + 1);
3639 defval.pop_back();
3640 flag.erase(def_start, std::string::npos); // NOLINT(readability-suspicious-call-argument)
3641 }
3642 flag.erase(0, flag.find_first_not_of("-!"));
3643 output.emplace_back(flag, defval);
3644 }
3645 return output;
3646}
3647
3648CLI11_INLINE std::tuple<std::vector<std::string>, std::vector<std::string>, std::string>
3649get_names(const std::vector<std::string> &input, bool allow_non_standard) {
3650
3651 std::vector<std::string> short_names;
3652 std::vector<std::string> long_names;
3653 std::string pos_name;
3654 for(std::string name : input) {
3655 if(name.empty()) {
3656 continue;
3657 }
3658 if(name.length() > 1 && name[0] == '-' && name[1] != '-') {
3659 if(name.length() == 2 && valid_first_char(name[1])) {
3660 short_names.emplace_back(1, name[1]);
3661 } else if(name.length() > 2) {
3662 if(allow_non_standard) {
3663 name = name.substr(1);
3664 if(valid_name_string(name)) {
3665 short_names.push_back(name);
3666 } else {
3667 throw BadNameString::BadLongName(name);
3668 }
3669 } else {
3670 throw BadNameString::MissingDash(name);
3671 }
3672 } else {
3673 throw BadNameString::OneCharName(name);
3674 }
3675 } else if(name.length() > 2 && name.substr(0, 2) == "--") {
3676 name = name.substr(2);
3677 if(valid_name_string(name)) {
3678 long_names.push_back(name);
3679 } else {
3680 throw BadNameString::BadLongName(name);
3681 }
3682 } else if(name == "-" || name == "--" || name == "++") {
3683 throw BadNameString::ReservedName(name);
3684 } else {
3685 if(!pos_name.empty()) {
3686 throw BadNameString::MultiPositionalNames(name);
3687 }
3688 if(valid_name_string(name)) {
3689 pos_name = name;
3690 } else {
3691 throw BadNameString::BadPositionalName(name);
3692 }
3693 }
3694 }
3695 return std::make_tuple(short_names, long_names, pos_name);
3696}
3697
3698} // namespace detail
3699
3700
3701
3702class App;
3703
3707 std::vector<std::string> parents{};
3708
3710 std::string name{};
3712 std::vector<std::string> inputs{};
3714 bool multiline{false};
3716 CLI11_NODISCARD std::string fullname() const {
3717 std::vector<std::string> tmp = parents;
3718 tmp.emplace_back(name);
3719 return detail::join(tmp, ".");
3720 (void)multiline; // suppression for cppcheck false positive
3721 }
3722};
3723
3725class Config {
3726 protected:
3727 std::vector<ConfigItem> items{};
3728
3729 public:
3731 virtual std::string to_config(const App *, bool, bool, std::string) const = 0;
3732
3734 virtual std::vector<ConfigItem> from_config(std::istream &) const = 0;
3735
3737 CLI11_NODISCARD virtual std::string to_flag(const ConfigItem &item) const {
3738 if(item.inputs.size() == 1) {
3739 return item.inputs.at(0);
3740 }
3741 if(item.inputs.empty()) {
3742 return "{}";
3743 }
3744 throw ConversionError::TooManyInputsFlag(item.fullname()); // LCOV_EXCL_LINE
3745 }
3746
3748 CLI11_NODISCARD std::vector<ConfigItem> from_file(const std::string &name) const {
3749#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
3750 std::ifstream input{to_path(name)};
3751#else
3752 std::ifstream input{name};
3753#endif
3754
3755 if(!input.good())
3756 throw FileError::Missing(name);
3757
3758 return from_config(input);
3759 }
3760
3762 virtual ~Config() = default;
3763};
3764
3766class ConfigBase : public Config {
3767 protected:
3769 char commentChar = '#';
3771 char arrayStart = '[';
3773 char arrayEnd = ']';
3775 char arraySeparator = ',';
3777 char valueDelimiter = '=';
3779 char stringQuote = '"';
3781 char literalQuote = '\'';
3783 uint8_t maximumLayers{255};
3791 int16_t configIndex{-1};
3793 std::string configSection{};
3794
3795 public:
3796 std::string
3797 to_config(const App * /*app*/, bool default_also, bool write_description, std::string prefix) const override;
3798
3799 std::vector<ConfigItem> from_config(std::istream &input) const override;
3801 ConfigBase *comment(char cchar) {
3802 commentChar = cchar;
3803 return this;
3804 }
3805
3806 ConfigBase *arrayBounds(char aStart, char aEnd) {
3807 arrayStart = aStart;
3808 arrayEnd = aEnd;
3809 return this;
3810 }
3811
3813 arraySeparator = aSep;
3814 return this;
3815 }
3816
3818 valueDelimiter = vSep;
3819 return this;
3820 }
3821
3822 ConfigBase *quoteCharacter(char qString, char literalChar) {
3823 stringQuote = qString;
3824 literalQuote = literalChar;
3825 return this;
3826 }
3827
3828 ConfigBase *maxLayers(uint8_t layers) {
3829 maximumLayers = layers;
3830 return this;
3831 }
3832
3834 parentSeparatorChar = sep;
3835 return this;
3836 }
3837
3838 ConfigBase *commentDefaults(bool comDef = true) {
3839 commentDefaultsBool = comDef;
3840 return this;
3841 }
3842
3843 std::string &sectionRef() { return configSection; }
3845 CLI11_NODISCARD const std::string &section() const { return configSection; }
3847 ConfigBase *section(const std::string &sectionName) {
3848 configSection = sectionName;
3849 return this;
3850 }
3851
3853 int16_t &indexRef() { return configIndex; }
3855 CLI11_NODISCARD int16_t index() const { return configIndex; }
3857 ConfigBase *index(int16_t sectionIndex) {
3858 configIndex = sectionIndex;
3859 return this;
3860 }
3861
3862 ConfigBase *allowDuplicateFields(bool value = true) {
3864 return this;
3865 }
3866};
3867
3869using ConfigTOML = ConfigBase;
3870
3872class ConfigINI : public ConfigTOML {
3873
3874 public:
3875 ConfigINI() {
3876 commentChar = ';';
3877 arrayStart = '\0';
3878 arrayEnd = '\0';
3879 arraySeparator = ' ';
3880 valueDelimiter = '=';
3881 }
3882};
3883
3884
3885
3886class Option;
3887
3889
3896
3898class Validator {
3899 protected:
3901 std::function<std::string()> desc_function_{[]() { return std::string{}; }};
3902
3905 std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
3907 std::string name_{};
3911 bool active_{true};
3913 bool non_modifying_{false};
3914
3915 Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
3916 : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {}
3917
3918 public:
3919 Validator() = default;
3921 explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
3923 Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
3924 : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
3925 name_(std::move(validator_name)) {}
3926
3927 Validator &operation(std::function<std::string(std::string &)> op) {
3928 func_ = std::move(op);
3929 return *this;
3930 }
3931
3933 std::string operator()(std::string &str) const;
3934
3937 std::string operator()(const std::string &str) const {
3938 std::string value = str;
3939 return (active_) ? func_(value) : std::string{};
3940 }
3941
3943 Validator &description(std::string validator_desc) {
3944 desc_function_ = [validator_desc]() { return validator_desc; };
3945 return *this;
3946 }
3947
3948 CLI11_NODISCARD Validator description(std::string validator_desc) const;
3949
3951 CLI11_NODISCARD std::string get_description() const {
3952 if(active_) {
3953 return desc_function_();
3954 }
3955 return std::string{};
3956 }
3957
3958 Validator &name(std::string validator_name) {
3959 name_ = std::move(validator_name);
3960 return *this;
3961 }
3962
3963 CLI11_NODISCARD Validator name(std::string validator_name) const {
3964 Validator newval(*this);
3965 newval.name_ = std::move(validator_name);
3966 return newval;
3967 }
3968
3969 CLI11_NODISCARD const std::string &get_name() const { return name_; }
3971 Validator &active(bool active_val = true) {
3972 active_ = active_val;
3973 return *this;
3974 }
3975
3976 CLI11_NODISCARD Validator active(bool active_val = true) const {
3977 Validator newval(*this);
3978 newval.active_ = active_val;
3979 return newval;
3980 }
3981
3983 Validator &non_modifying(bool no_modify = true) {
3984 non_modifying_ = no_modify;
3985 return *this;
3986 }
3987
3988 Validator &application_index(int app_index) {
3989 application_index_ = app_index;
3990 return *this;
3991 }
3992
3993 CLI11_NODISCARD Validator application_index(int app_index) const {
3994 Validator newval(*this);
3995 newval.application_index_ = app_index;
3996 return newval;
3997 }
3998
3999 CLI11_NODISCARD int get_application_index() const { return application_index_; }
4001 CLI11_NODISCARD bool get_active() const { return active_; }
4002
4004 CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; }
4005
4008 Validator operator&(const Validator &other) const;
4009
4012 Validator operator|(const Validator &other) const;
4013
4015 Validator operator!() const;
4016
4017 private:
4018 void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger);
4019};
4020
4022using CustomValidator = Validator;
4023
4024// The implementation of the built in validators is using the Validator class;
4025// the user is only expected to use the const (static) versions (since there's no setup).
4026// Therefore, this is in detail.
4027namespace detail {
4028
4030enum class path_type : std::uint8_t { nonexistent, file, directory };
4031
4033CLI11_INLINE path_type check_path(const char *file) noexcept;
4034
4035// Static is not needed here, because global const implies static.
4036
4038class ExistingFileValidator : public Validator {
4039 public:
4040 ExistingFileValidator();
4041};
4042
4044class ExistingDirectoryValidator : public Validator {
4045 public:
4046 ExistingDirectoryValidator();
4047};
4048
4050class ExistingPathValidator : public Validator {
4051 public:
4052 ExistingPathValidator();
4053};
4054
4056class NonexistentPathValidator : public Validator {
4057 public:
4058 NonexistentPathValidator();
4059};
4060
4061class EscapedStringTransformer : public Validator {
4062 public:
4063 EscapedStringTransformer();
4064};
4065
4066} // namespace detail
4067
4069CLI11_MODULE_INLINE const detail::ExistingFileValidator ExistingFile;
4070
4072CLI11_MODULE_INLINE const detail::ExistingDirectoryValidator ExistingDirectory;
4073
4075CLI11_MODULE_INLINE const detail::ExistingPathValidator ExistingPath;
4076
4078CLI11_MODULE_INLINE const detail::NonexistentPathValidator NonexistentPath;
4079
4081CLI11_MODULE_INLINE const detail::EscapedStringTransformer EscapedString;
4082
4085class FileOnDefaultPath : public Validator {
4086 public:
4087 explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true);
4088};
4089
4091class Range : public Validator {
4092 public:
4097 template <typename T>
4098 Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) {
4099 if(validator_name.empty()) {
4100 std::stringstream out;
4101 out << detail::type_name<T>() << " in [" << min_val << " - " << max_val << "]";
4102 description(out.str());
4103 }
4104
4105 func_ = [min_val, max_val](std::string &input) {
4106 using CLI::detail::lexical_cast;
4107 T val;
4108 bool converted = lexical_cast(input, val);
4109 if((!converted) || (val < min_val || val > max_val)) {
4110 std::stringstream out;
4111 out << "Value " << input << " not in range [";
4112 out << min_val << " - " << max_val << "]";
4113 return out.str();
4114 }
4115 return std::string{};
4116 };
4117 }
4118
4120 template <typename T>
4121 explicit Range(T max_val, const std::string &validator_name = std::string{})
4122 : Range(static_cast<T>(0), max_val, validator_name) {}
4123};
4124
4126CLI11_MODULE_INLINE const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
4127
4129CLI11_MODULE_INLINE const
4130 Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
4131
4132namespace detail {
4133// the following suggestion was made by Nikita Ofitserov(@himikof)
4134// done in templates to prevent compiler warnings on negation of unsigned numbers
4135
4137template <typename T>
4138inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
4139 if((a > 0) == (b > 0)) {
4140 return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
4141 }
4142 return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
4143}
4145template <typename T>
4146inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
4147 return ((std::numeric_limits<T>::max)() / a < b);
4148}
4149
4151template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
4152 if(a == 0 || b == 0 || a == 1 || b == 1) {
4153 a *= b;
4154 return true;
4155 }
4156 if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
4157 return false;
4158 }
4159 if(overflowCheck(a, b)) {
4160 return false;
4161 }
4162 a *= b;
4163 return true;
4164}
4165
4167template <typename T>
4168typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
4169 T c = a * b;
4170 if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
4171 return false;
4172 }
4173 a = c;
4174 return true;
4175}
4180CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
4181
4182} // namespace detail
4184
4185
4186
4187
4188CLI11_INLINE std::string Validator::operator()(std::string &str) const {
4189 std::string retstring;
4190 if(active_) {
4191 if(non_modifying_) {
4192 std::string value = str;
4193 retstring = func_(value);
4194 } else {
4195 retstring = func_(str);
4196 }
4197 }
4198 return retstring;
4199}
4200
4201CLI11_NODISCARD CLI11_INLINE Validator Validator::description(std::string validator_desc) const {
4202 Validator newval(*this);
4203 newval.desc_function_ = [validator_desc]() { return validator_desc; };
4204 return newval;
4205}
4206
4207CLI11_INLINE Validator Validator::operator&(const Validator &other) const {
4208 Validator newval;
4209
4210 newval._merge_description(*this, other, " AND ");
4211
4212 // Give references (will make a copy in lambda function)
4213 const std::function<std::string(std::string & filename)> &f1 = func_;
4214 const std::function<std::string(std::string & filename)> &f2 = other.func_;
4215
4216 newval.func_ = [f1, f2](std::string &input) {
4217 std::string s1 = f1(input);
4218 std::string s2 = f2(input);
4219 if(!s1.empty() && !s2.empty())
4220 return std::string("(") + s1 + ") AND (" + s2 + ")";
4221 return s1 + s2;
4222 };
4223
4224 newval.active_ = active_ && other.active_;
4226 return newval;
4227}
4228
4229CLI11_INLINE Validator Validator::operator|(const Validator &other) const {
4230 Validator newval;
4231
4232 newval._merge_description(*this, other, " OR ");
4233
4234 // Give references (will make a copy in lambda function)
4235 const std::function<std::string(std::string &)> &f1 = func_;
4236 const std::function<std::string(std::string &)> &f2 = other.func_;
4237
4238 newval.func_ = [f1, f2](std::string &input) {
4239 std::string s1 = f1(input);
4240 std::string s2 = f2(input);
4241 if(s1.empty() || s2.empty())
4242 return std::string();
4243
4244 return std::string("(") + s1 + ") OR (" + s2 + ")";
4245 };
4246 newval.active_ = active_ && other.active_;
4248 return newval;
4249}
4250
4251CLI11_INLINE Validator Validator::operator!() const {
4252 Validator newval;
4253 const std::function<std::string()> &dfunc1 = desc_function_;
4254 newval.desc_function_ = [dfunc1]() {
4255 auto str = dfunc1();
4256 return (!str.empty()) ? std::string("NOT ") + str : std::string{};
4257 };
4258 // Give references (will make a copy in lambda function)
4259 const std::function<std::string(std::string & res)> &f1 = func_;
4260
4261 newval.func_ = [f1, dfunc1](std::string &test) -> std::string {
4262 std::string s1 = f1(test);
4263 if(s1.empty()) {
4264 return std::string("check ") + dfunc1() + " succeeded improperly";
4265 }
4266 return std::string{};
4267 };
4268 newval.active_ = active_;
4270 return newval;
4271}
4272
4273CLI11_INLINE void
4274Validator::_merge_description(const Validator &val1, const Validator &val2, const std::string &merger) {
4275
4276 const std::function<std::string()> &dfunc1 = val1.desc_function_;
4277 const std::function<std::string()> &dfunc2 = val2.desc_function_;
4278
4279 desc_function_ = [=]() {
4280 std::string f1 = dfunc1();
4281 std::string f2 = dfunc2();
4282 if((f1.empty()) || (f2.empty())) {
4283 return f1 + f2;
4284 }
4285 return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
4286 };
4287}
4288
4289namespace detail {
4290
4291#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
4292CLI11_INLINE path_type check_path(const char *file) noexcept {
4293 std::error_code ec;
4294 auto stat = std::filesystem::status(to_path(file), ec);
4295 if(ec) {
4296 return path_type::nonexistent;
4297 }
4298 switch(stat.type()) {
4299 case std::filesystem::file_type::none: // LCOV_EXCL_LINE
4300 case std::filesystem::file_type::not_found:
4301 return path_type::nonexistent; // LCOV_EXCL_LINE
4302 case std::filesystem::file_type::directory:
4303 return path_type::directory;
4304 case std::filesystem::file_type::symlink:
4305 case std::filesystem::file_type::block:
4306 case std::filesystem::file_type::character:
4307 case std::filesystem::file_type::fifo:
4308 case std::filesystem::file_type::socket:
4309 case std::filesystem::file_type::regular:
4310 case std::filesystem::file_type::unknown:
4311 default:
4312 return path_type::file;
4313 }
4314}
4315#else
4316CLI11_INLINE path_type check_path(const char *file) noexcept {
4317#if defined(_MSC_VER)
4318 struct __stat64 buffer;
4319 if(_stat64(file, &buffer) == 0) {
4320 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
4321 }
4322#else
4323 struct stat buffer;
4324 if(stat(file, &buffer) == 0) {
4325 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
4326 }
4327#endif
4328 return path_type::nonexistent;
4329}
4330#endif
4331
4332CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator("FILE") {
4333 func_ = [](std::string &filename) {
4334 auto path_result = check_path(filename.c_str());
4335 if(path_result == path_type::nonexistent) {
4336 return "File does not exist: " + filename;
4337 }
4338 if(path_result == path_type::directory) {
4339 return "File is actually a directory: " + filename;
4340 }
4341 return std::string();
4342 };
4343}
4344
4345CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator("DIR") {
4346 func_ = [](std::string &filename) {
4347 auto path_result = check_path(filename.c_str());
4348 if(path_result == path_type::nonexistent) {
4349 return "Directory does not exist: " + filename;
4350 }
4351 if(path_result == path_type::file) {
4352 return "Directory is actually a file: " + filename;
4353 }
4354 return std::string();
4355 };
4356}
4357
4358CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator("PATH(existing)") {
4359 func_ = [](std::string &filename) {
4360 auto path_result = check_path(filename.c_str());
4361 if(path_result == path_type::nonexistent) {
4362 return "Path does not exist: " + filename;
4363 }
4364 return std::string();
4365 };
4366}
4367
4368CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator("PATH(non-existing)") {
4369 func_ = [](std::string &filename) {
4370 auto path_result = check_path(filename.c_str());
4371 if(path_result != path_type::nonexistent) {
4372 return "Path already exists: " + filename;
4373 }
4374 return std::string();
4375 };
4376}
4377
4378CLI11_INLINE EscapedStringTransformer::EscapedStringTransformer() {
4379 func_ = [](std::string &str) {
4380 try {
4381 if(str.size() > 1 && (str.front() == '\"' || str.front() == '\'' || str.front() == '`') &&
4382 str.front() == str.back()) {
4383 process_quoted_string(str);
4384 } else if(str.find_first_of('\\') != std::string::npos) {
4385 if(detail::is_binary_escaped_string(str)) {
4386 str = detail::extract_binary_string(str);
4387 } else {
4388 str = remove_escaped_characters(str);
4389 }
4390 }
4391 return std::string{};
4392 } catch(const std::invalid_argument &ia) {
4393 return std::string(ia.what());
4394 }
4395 };
4396}
4397} // namespace detail
4398
4399CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path, bool enableErrorReturn)
4400 : Validator("FILE") {
4401 func_ = [default_path, enableErrorReturn](std::string &filename) {
4402 auto path_result = detail::check_path(filename.c_str());
4403 if(path_result == detail::path_type::nonexistent) {
4404 std::string test_file_path = default_path;
4405 if(default_path.back() != '/' && default_path.back() != '\\') {
4406 // Add folder separator
4407 test_file_path += '/';
4408 }
4409 test_file_path.append(filename);
4410 path_result = detail::check_path(test_file_path.c_str());
4411 if(path_result == detail::path_type::file) {
4412 filename = test_file_path;
4413 } else {
4414 if(enableErrorReturn) {
4415 return "File does not exist: " + filename;
4416 }
4417 }
4418 }
4419 return std::string{};
4420 };
4421}
4422
4423namespace detail {
4424
4425CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline) {
4426 // try to determine the programName
4427 std::pair<std::string, std::string> vals;
4428 trim(commandline);
4429 auto esp = commandline.find_first_of(' ', 1);
4430 while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
4431 esp = commandline.find_first_of(' ', esp + 1);
4432 if(esp == std::string::npos) {
4433 // if we have reached the end and haven't found a valid file just assume the first argument is the
4434 // program name
4435 if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') {
4436 bool embeddedQuote = false;
4437 auto keyChar = commandline[0];
4438 auto end = commandline.find_first_of(keyChar, 1);
4439 while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes
4440 end = commandline.find_first_of(keyChar, end + 1);
4441 embeddedQuote = true;
4442 }
4443 if(end != std::string::npos) {
4444 vals.first = commandline.substr(1, end - 1);
4445 esp = end + 1;
4446 if(embeddedQuote) {
4447 vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar));
4448 }
4449 } else {
4450 esp = commandline.find_first_of(' ', 1);
4451 }
4452 } else {
4453 esp = commandline.find_first_of(' ', 1);
4454 }
4455
4456 break;
4457 }
4458 }
4459 if(vals.first.empty()) {
4460 vals.first = commandline.substr(0, esp);
4461 rtrim(vals.first);
4462 }
4463
4464 // strip the program name
4465 vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{};
4466 ltrim(vals.second);
4467 return vals;
4468}
4469
4470} // namespace detail
4472
4473
4474
4475
4476// The implementation of the extra validators is using the Validator class;
4477// the user is only expected to use the const (static) versions (since there's no setup).
4478// Therefore, this is in detail.
4479namespace detail {
4480
4482class IPV4Validator : public Validator {
4483 public:
4484 IPV4Validator();
4485};
4486
4487} // namespace detail
4488
4490template <typename DesiredType> class TypeValidator : public Validator {
4491 public:
4492 explicit TypeValidator(const std::string &validator_name)
4493 : Validator(validator_name, [](std::string &input_string) {
4494 using CLI::detail::lexical_cast;
4495 auto val = DesiredType();
4496 if(!lexical_cast(input_string, val)) {
4497 return std::string("Failed parsing ") + input_string + " as a " + detail::type_name<DesiredType>();
4498 }
4499 return std::string{};
4500 }) {}
4501 TypeValidator() : TypeValidator(detail::type_name<DesiredType>()) {}
4502};
4503
4505const TypeValidator<double> Number("NUMBER");
4506
4508class Bound : public Validator {
4509 public:
4514 template <typename T> Bound(T min_val, T max_val) {
4515 std::stringstream out;
4516 out << detail::type_name<T>() << " bounded to [" << min_val << " - " << max_val << "]";
4517 description(out.str());
4518
4519 func_ = [min_val, max_val](std::string &input) {
4520 using CLI::detail::lexical_cast;
4521 T val;
4522 bool converted = lexical_cast(input, val);
4523 if(!converted) {
4524 return std::string("Value ") + input + " could not be converted";
4525 }
4526 if(val < min_val)
4527 input = detail::to_string(min_val);
4528 else if(val > max_val)
4529 input = detail::to_string(max_val);
4530
4531 return std::string{};
4532 };
4533 }
4534
4536 template <typename T> explicit Bound(T max_val) : Bound(static_cast<T>(0), max_val) {}
4537};
4538
4539// Static is not needed here, because global const implies static.
4540
4542CLI11_MODULE_INLINE const detail::IPV4Validator ValidIPV4;
4543
4544namespace detail {
4545template <typename T,
4546 enable_if_t<is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
4547auto smart_deref(T value) -> decltype(*value) {
4548 return *value;
4549}
4550
4551template <
4552 typename T,
4553 enable_if_t<!is_copyable_ptr<typename std::remove_reference<T>::type>::value, detail::enabler> = detail::dummy>
4554typename std::remove_reference<T>::type &smart_deref(T &value) {
4555 // NOLINTNEXTLINE
4556 return value;
4557}
4559template <typename T> std::string generate_set(const T &set) {
4560 using element_t = typename detail::element_type<T>::type;
4561 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
4562 std::string out(1, '{');
4563 out.append(detail::join(
4564 detail::smart_deref(set),
4565 [](const iteration_type_t &v) { return detail::pair_adaptor<element_t>::first(v); },
4566 ","));
4567 out.push_back('}');
4568 return out;
4569}
4570
4572template <typename T> std::string generate_map(const T &map, bool key_only = false) {
4573 using element_t = typename detail::element_type<T>::type;
4574 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
4575 std::string out(1, '{');
4576 out.append(detail::join(
4577 detail::smart_deref(map),
4578 [key_only](const iteration_type_t &v) {
4579 std::string res{detail::to_string(detail::pair_adaptor<element_t>::first(v))};
4580
4581 if(!key_only) {
4582 res.append("->");
4583 res += detail::to_string(detail::pair_adaptor<element_t>::second(v));
4584 }
4585 return res;
4586 },
4587 ","));
4588 out.push_back('}');
4589 return out;
4590}
4591
4592template <typename C, typename V> struct has_find {
4593 template <typename CC, typename VV>
4594 static auto test(int) -> decltype(std::declval<CC>().find(std::declval<VV>()), std::true_type());
4595 template <typename, typename> static auto test(...) -> decltype(std::false_type());
4596
4597 static const auto value = decltype(test<C, V>(0))::value;
4598 using type = std::integral_constant<bool, value>;
4599};
4600
4602template <typename T, typename V, enable_if_t<!has_find<T, V>::value, detail::enabler> = detail::dummy>
4603auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
4604 using element_t = typename detail::element_type<T>::type;
4605 auto &setref = detail::smart_deref(set);
4606 auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) {
4607 return (detail::pair_adaptor<element_t>::first(v) == val);
4608 });
4609 return {(it != std::end(setref)), it};
4610}
4611
4613template <typename T, typename V, enable_if_t<has_find<T, V>::value, detail::enabler> = detail::dummy>
4614auto search(const T &set, const V &val) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
4615 auto &setref = detail::smart_deref(set);
4616 auto it = setref.find(val);
4617 return {(it != std::end(setref)), it};
4618}
4619
4621template <typename T, typename V>
4622auto search(const T &set, const V &val, const std::function<V(V)> &filter_function)
4623 -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))> {
4624 using element_t = typename detail::element_type<T>::type;
4625 // do the potentially faster first search
4626 auto res = search(set, val);
4627 if((res.first) || (!(filter_function))) {
4628 return res;
4629 }
4630 // if we haven't found it do the longer linear search with all the element translations
4631 auto &setref = detail::smart_deref(set);
4632 auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) {
4634 a = filter_function(a);
4635 return (a == val);
4636 });
4637 return {(it != std::end(setref)), it};
4638}
4639
4640} // namespace detail
4642class IsMember : public Validator {
4643 public:
4644 using filter_fn_t = std::function<std::string(std::string)>;
4645
4647 template <typename T, typename... Args>
4648 IsMember(std::initializer_list<T> values, Args &&...args)
4649 : IsMember(std::vector<T>(values), std::forward<Args>(args)...) {}
4650
4652 template <typename T> explicit IsMember(T &&set) : IsMember(std::forward<T>(set), nullptr) {}
4653
4656 template <typename T, typename F> explicit IsMember(T set, F filter_function) {
4657
4658 // Get the type of the contained item - requires a container have ::value_type
4659 // if the type does not have first_type and second_type, these are both value_type
4660 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
4661 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
4662
4663 using local_item_t = typename IsMemberType<item_t>::type; // This will convert bad types to good ones
4664 // (const char * to std::string)
4665
4666 // Make a local copy of the filter function, using a std::function if not one already
4667 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4668
4669 // This is the type name for help, it will take the current version of the set contents
4670 desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); };
4671
4672 // This is the function that validates
4673 // It stores a copy of the set pointer-like, so shared_ptr will stay alive
4674 func_ = [set, filter_fn](std::string &input) {
4675 using CLI::detail::lexical_cast;
4676 local_item_t b;
4677 if(!lexical_cast(input, b)) {
4678 throw ValidationError(input); // name is added later
4679 }
4680 if(filter_fn) {
4681 b = filter_fn(b);
4682 }
4683 auto res = detail::search(set, b, filter_fn);
4684 if(res.first) {
4685 // Make sure the version in the input string is identical to the one in the set
4686 if(filter_fn) {
4687 input = detail::value_string(detail::pair_adaptor<element_t>::first(*(res.second)));
4688 }
4689
4690 // Return empty error string (success)
4691 return std::string{};
4692 }
4693
4694 // If you reach this point, the result was not found
4695 return input + " not in " + detail::generate_set(detail::smart_deref(set));
4696 };
4697 }
4698
4700 template <typename T, typename... Args>
4701 IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
4702 : IsMember(
4703 std::forward<T>(set),
4704 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
4705 other...) {}
4706};
4707
4709template <typename T> using TransformPairs = std::vector<std::pair<std::string, T>>;
4710
4712class Transformer : public Validator {
4713 public:
4714 using filter_fn_t = std::function<std::string(std::string)>;
4715
4717 template <typename... Args>
4718 Transformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
4719 : Transformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
4720
4722 template <typename T> explicit Transformer(T &&mapping) : Transformer(std::forward<T>(mapping), nullptr) {}
4723
4726 template <typename T, typename F> explicit Transformer(T mapping, F filter_function) {
4727
4729 "mapping must produce value pairs");
4730 // Get the type of the contained item - requires a container have ::value_type
4731 // if the type does not have first_type and second_type, these are both value_type
4732 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
4733 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
4734 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
4735 // (const char * to std::string)
4736
4737 // Make a local copy of the filter function, using a std::function if not one already
4738 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4739
4740 // This is the type name for help, it will take the current version of the set contents
4741 desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); };
4742
4743 func_ = [mapping, filter_fn](std::string &input) {
4744 using CLI::detail::lexical_cast;
4745 local_item_t b;
4746 if(!lexical_cast(input, b)) {
4747 return std::string();
4748 // there is no possible way we can match anything in the mapping if we can't convert so just return
4749 }
4750 if(filter_fn) {
4751 b = filter_fn(b);
4752 }
4753 auto res = detail::search(mapping, b, filter_fn);
4754 if(res.first) {
4755 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
4756 }
4757 return std::string{};
4758 };
4759 }
4760
4762 template <typename T, typename... Args>
4763 Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
4764 : Transformer(
4765 std::forward<T>(mapping),
4766 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
4767 other...) {}
4768};
4769
4771class CheckedTransformer : public Validator {
4772 public:
4773 using filter_fn_t = std::function<std::string(std::string)>;
4774
4776 template <typename... Args>
4777 CheckedTransformer(std::initializer_list<std::pair<std::string, std::string>> values, Args &&...args)
4778 : CheckedTransformer(TransformPairs<std::string>(values), std::forward<Args>(args)...) {}
4779
4781 template <typename T> explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {}
4782
4785 template <typename T, typename F> explicit CheckedTransformer(T mapping, F filter_function) {
4786
4788 "mapping must produce value pairs");
4789 // Get the type of the contained item - requires a container have ::value_type
4790 // if the type does not have first_type and second_type, these are both value_type
4791 using element_t = typename detail::element_type<T>::type; // Removes (smart) pointers if needed
4792 using item_t = typename detail::pair_adaptor<element_t>::first_type; // Is value_type if not a map
4793 using local_item_t = typename IsMemberType<item_t>::type; // Will convert bad types to good ones
4794 // (const char * to std::string)
4795 using iteration_type_t = typename detail::pair_adaptor<element_t>::value_type; // the type of the object pair
4796
4797 // Make a local copy of the filter function, using a std::function if not one already
4798 std::function<local_item_t(local_item_t)> filter_fn = filter_function;
4799
4800 auto tfunc = [mapping]() {
4801 std::string out("value in ");
4802 out += detail::generate_map(detail::smart_deref(mapping)) + " OR {";
4803 out += detail::join(
4804 detail::smart_deref(mapping),
4805 [](const iteration_type_t &v) {
4806 return detail::value_string(detail::pair_adaptor<element_t>::second(v));
4807 },
4808 ",");
4809 out.push_back('}');
4810 return out;
4811 };
4812
4813 desc_function_ = tfunc;
4814
4815 func_ = [mapping, tfunc, filter_fn](std::string &input) {
4816 using CLI::detail::lexical_cast;
4817 local_item_t b;
4818 bool converted = lexical_cast(input, b);
4819 if(converted) {
4820 if(filter_fn) {
4821 b = filter_fn(b);
4822 }
4823 auto res = detail::search(mapping, b, filter_fn);
4824 if(res.first) {
4825 input = detail::value_string(detail::pair_adaptor<element_t>::second(*res.second));
4826 return std::string{};
4827 }
4828 }
4829 for(const auto &v : detail::smart_deref(mapping)) {
4830 auto output_string = detail::value_string(detail::pair_adaptor<element_t>::second(v));
4831 if(output_string == input) {
4832 return std::string();
4833 }
4834 }
4835
4836 return "Check " + input + " " + tfunc() + " FAILED";
4837 };
4838 }
4839
4841 template <typename T, typename... Args>
4842 CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
4844 std::forward<T>(mapping),
4845 [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); },
4846 other...) {}
4847};
4848
4850inline std::string ignore_case(std::string item) { return detail::to_lower(item); }
4851
4853inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); }
4854
4856inline std::string ignore_space(std::string item) {
4857 item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item));
4858 item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item));
4859 return item;
4860}
4861
4873class AsNumberWithUnit : public Validator {
4874 public:
4879 enum Options : std::uint8_t {
4880 CASE_SENSITIVE = 0,
4881 CASE_INSENSITIVE = 1,
4882 UNIT_OPTIONAL = 0,
4883 UNIT_REQUIRED = 2,
4884 DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL
4885 };
4886
4887 template <typename Number>
4888 explicit AsNumberWithUnit(std::map<std::string, Number> mapping,
4889 Options opts = DEFAULT,
4890 const std::string &unit_name = "UNIT") {
4891 description(generate_description<Number>(unit_name, opts));
4892 validate_mapping(mapping, opts);
4893
4894 // transform function
4895 func_ = [mapping, opts](std::string &input) -> std::string {
4896 Number num{};
4897
4898 detail::rtrim(input);
4899 if(input.empty()) {
4900 throw ValidationError("Input is empty");
4901 }
4902
4903 // Find split position between number and prefix
4904 auto unit_begin = input.end();
4905 while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) {
4906 --unit_begin;
4907 }
4908
4909 std::string unit{unit_begin, input.end()};
4910 input.resize(static_cast<std::size_t>(std::distance(input.begin(), unit_begin)));
4911 detail::trim(input);
4912
4913 if(opts & UNIT_REQUIRED && unit.empty()) {
4914 throw ValidationError("Missing mandatory unit");
4915 }
4916 if(opts & CASE_INSENSITIVE) {
4917 unit = detail::to_lower(unit);
4918 }
4919 if(unit.empty()) {
4920 using CLI::detail::lexical_cast;
4921 if(!lexical_cast(input, num)) {
4922 throw ValidationError(std::string("Value ") + input + " could not be converted to " +
4923 detail::type_name<Number>());
4924 }
4925 // No need to modify input if no unit passed
4926 return {};
4927 }
4928
4929 // find corresponding factor
4930 auto it = mapping.find(unit);
4931 if(it == mapping.end()) {
4932 throw ValidationError(unit +
4933 " unit not recognized. "
4934 "Allowed values: " +
4935 detail::generate_map(mapping, true));
4936 }
4937
4938 if(!input.empty()) {
4939 using CLI::detail::lexical_cast;
4940 bool converted = lexical_cast(input, num);
4941 if(!converted) {
4942 throw ValidationError(std::string("Value ") + input + " could not be converted to " +
4943 detail::type_name<Number>());
4944 }
4945 // perform safe multiplication
4946 bool ok = detail::checked_multiply(num, it->second);
4947 if(!ok) {
4948 throw ValidationError(detail::to_string(num) + " multiplied by " + unit +
4949 " factor would cause number overflow. Use smaller value.");
4950 }
4951 } else {
4952 num = static_cast<Number>(it->second);
4953 }
4954
4955 input = detail::to_string(num);
4956
4957 return {};
4958 };
4959 }
4960
4961 private:
4964 template <typename Number> static void validate_mapping(std::map<std::string, Number> &mapping, Options opts) {
4965 for(auto &kv : mapping) {
4966 if(kv.first.empty()) {
4967 throw ValidationError("Unit must not be empty.");
4968 }
4969 if(!detail::isalpha(kv.first)) {
4970 throw ValidationError("Unit must contain only letters.");
4971 }
4972 }
4973
4974 // make all units lowercase if CASE_INSENSITIVE
4975 if(opts & CASE_INSENSITIVE) {
4976 std::map<std::string, Number> lower_mapping;
4977 for(auto &kv : mapping) {
4978 auto s = detail::to_lower(kv.first);
4979 if(lower_mapping.count(s)) {
4980 throw ValidationError(std::string("Several matching lowercase unit representations are found: ") +
4981 s);
4982 }
4983 lower_mapping[detail::to_lower(kv.first)] = kv.second;
4984 }
4985 mapping = std::move(lower_mapping);
4986 }
4987 }
4988
4990 template <typename Number> static std::string generate_description(const std::string &name, Options opts) {
4991 std::stringstream out;
4992 out << detail::type_name<Number>() << ' ';
4993 if(opts & UNIT_REQUIRED) {
4994 out << name;
4995 } else {
4996 out << '[' << name << ']';
4997 }
4998 return out.str();
4999 }
5000};
5001
5003 return static_cast<AsNumberWithUnit::Options>(static_cast<int>(a) | static_cast<int>(b));
5004}
5005
5017class AsSizeValue : public AsNumberWithUnit {
5018 public:
5019 using result_t = std::uint64_t;
5020
5028 explicit AsSizeValue(bool kb_is_1000);
5029
5030 private:
5032 static std::map<std::string, result_t> init_mapping(bool kb_is_1000);
5033
5035 static std::map<std::string, result_t> get_mapping(bool kb_is_1000);
5036};
5037
5038#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
5039// new extra validators
5040#if CLI11_HAS_FILESYSTEM
5041namespace detail {
5042enum class Permission : std::uint8_t { none = 0, read = 1, write = 2, exec = 4 };
5043class PermissionValidator : public Validator {
5044 public:
5045 explicit PermissionValidator(Permission permission);
5046};
5047} // namespace detail
5048
5050const detail::PermissionValidator ReadPermissions(detail::Permission::read);
5051
5053const detail::PermissionValidator WritePermissions(detail::Permission::write);
5054
5056const detail::PermissionValidator ExecPermissions(detail::Permission::exec);
5057#endif
5058
5059#endif
5060
5061
5062
5063namespace detail {
5064
5065CLI11_INLINE IPV4Validator::IPV4Validator() : Validator("IPV4") {
5066 func_ = [](std::string &ip_addr) {
5067 auto cdot = std::count(ip_addr.begin(), ip_addr.end(), '.');
5068 if(cdot != 3u) {
5069 return std::string("Invalid IPV4 address: must have 3 separators");
5070 }
5071 auto result = CLI::detail::split(ip_addr, '.');
5072 if(result.size() != 4) {
5073 return std::string("Invalid IPV4 address: must have four parts (") + ip_addr + ')';
5074 }
5075 int num = 0;
5076 for(const auto &var : result) {
5077 using CLI::detail::lexical_cast;
5078 bool retval = lexical_cast(var, num);
5079 if(!retval) {
5080 return std::string("Failed parsing number (") + var + ')';
5081 }
5082 if(num < 0 || num > 255) {
5083 return std::string("Each IP number must be between 0 and 255 ") + var;
5084 }
5085 }
5086 return std::string{};
5087 };
5088}
5089
5090} // namespace detail
5091
5092CLI11_INLINE AsSizeValue::AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) {
5093 if(kb_is_1000) {
5094 description("SIZE [b, kb(=1000b), kib(=1024b), ...]");
5095 } else {
5096 description("SIZE [b, kb(=1024b), ...]");
5097 }
5098}
5099
5100CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::init_mapping(bool kb_is_1000) {
5101 std::map<std::string, result_t> m;
5102 result_t k_factor = kb_is_1000 ? 1000 : 1024;
5103 result_t ki_factor = 1024;
5104 result_t k = 1;
5105 result_t ki = 1;
5106 m["b"] = 1;
5107 for(std::string p : {"k", "m", "g", "t", "p", "e"}) {
5108 k *= k_factor;
5109 ki *= ki_factor;
5110 m[p] = k;
5111 m[p + "b"] = k;
5112 m[p + "i"] = ki;
5113 m[p + "ib"] = ki;
5114 }
5115 return m;
5116}
5117
5118CLI11_INLINE std::map<std::string, AsSizeValue::result_t> AsSizeValue::get_mapping(bool kb_is_1000) {
5119 if(kb_is_1000) {
5120 static auto m = init_mapping(true);
5121 return m;
5122 }
5123 static auto m = init_mapping(false);
5124 return m;
5125}
5126
5127namespace detail {} // namespace detail
5129
5130#if defined(CLI11_ENABLE_EXTRA_VALIDATORS) && CLI11_ENABLE_EXTRA_VALIDATORS != 0
5131// new extra validators
5132namespace detail {
5133
5134#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
5135CLI11_INLINE PermissionValidator::PermissionValidator(Permission permission) {
5136 std::filesystem::perms permission_code = std::filesystem::perms::none;
5137 std::string permission_name;
5138 switch(permission) {
5139 case Permission::read:
5140 permission_code = std::filesystem::perms::owner_read | std::filesystem::perms::group_read |
5141 std::filesystem::perms::others_read;
5142 permission_name = "read";
5143 break;
5144 case Permission::write:
5145 permission_code = std::filesystem::perms::owner_write | std::filesystem::perms::group_write |
5146 std::filesystem::perms::others_write;
5147 permission_name = "write";
5148 break;
5149 case Permission::exec:
5150 permission_code = std::filesystem::perms::owner_exec | std::filesystem::perms::group_exec |
5151 std::filesystem::perms::others_exec;
5152 permission_name = "exec";
5153 break;
5154 case Permission::none:
5155 default:
5156 permission_code = std::filesystem::perms::none;
5157 break;
5158 }
5159 func_ = [permission_code](std::string &path) {
5160 std::error_code ec;
5161 auto p = std::filesystem::path(path);
5162 if(!std::filesystem::exists(p, ec)) {
5163 return std::string("Path does not exist: ") + path;
5164 }
5165 if(ec) {
5166 return std::string("Error checking path: ") + ec.message(); // LCOV_EXCL_LINE
5167 }
5168 if(permission_code == std::filesystem::perms::none) {
5169 return std::string{};
5170 }
5171 auto perms = std::filesystem::status(p, ec).permissions();
5172 if(ec) {
5173 return std::string("Error checking path status: ") + ec.message(); // LCOV_EXCL_LINE
5174 }
5175 if((perms & permission_code) == std::filesystem::perms::none) {
5176 return std::string("Path does not have required permissions: ") + path;
5177 }
5178 return std::string{};
5179 };
5180 description("Path with " + permission_name + " permission");
5181}
5182#endif
5183
5184} // namespace detail
5185#endif
5186
5187
5188
5189class Option;
5190class App;
5191
5196
5197enum class AppFormatMode : std::uint8_t {
5198 Normal,
5199 All,
5200 Sub,
5201};
5202
5207class FormatterBase {
5208 protected:
5211
5213 std::size_t column_width_{30};
5214
5217
5219 std::size_t right_column_width_{65};
5220
5223
5226
5229 bool enable_footer_formatting_{true};
5230
5233 bool enable_option_type_names_{true};
5234 bool enable_default_flag_values_{true};
5237 std::map<std::string, std::string> labels_{};
5238
5242
5243 public:
5244 FormatterBase() = default;
5245 FormatterBase(const FormatterBase &) = default;
5246 FormatterBase(FormatterBase &&) = default;
5247 FormatterBase &operator=(const FormatterBase &) = default;
5248 FormatterBase &operator=(FormatterBase &&) = default;
5249
5251 virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default)
5252
5254 virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0;
5255
5259
5261 void label(std::string key, std::string val) { labels_[key] = val; }
5262
5264 void column_width(std::size_t val) { column_width_ = val; }
5265
5270 (ratio >= 0.0f) ? ((ratio <= 1.0f) ? ratio : 1.0f / ratio) : ((ratio < -1.0f) ? 1.0f / (-ratio) : -ratio);
5271 }
5272
5274 void right_column_width(std::size_t val) { right_column_width_ = val; }
5275
5278
5280 void footer_paragraph_width(std::size_t val) { footer_paragraph_width_ = val; }
5284 void enable_footer_formatting(bool value = true) { enable_footer_formatting_ = value; }
5285
5287 void enable_option_defaults(bool value = true) { enable_option_defaults_ = value; }
5289 void enable_option_type_names(bool value = true) { enable_option_type_names_ = value; }
5291 void enable_default_flag_values(bool value = true) { enable_default_flag_values_ = value; }
5295
5297 CLI11_NODISCARD std::string get_label(std::string key) const {
5298 if(labels_.find(key) == labels_.end())
5299 return key;
5300 return labels_.at(key);
5301 }
5302
5304 CLI11_NODISCARD std::size_t get_column_width() const { return column_width_; }
5305
5307 CLI11_NODISCARD std::size_t get_right_column_width() const { return right_column_width_; }
5308
5310 CLI11_NODISCARD std::size_t get_description_paragraph_width() const { return description_paragraph_width_; }
5311
5313 CLI11_NODISCARD std::size_t get_footer_paragraph_width() const { return footer_paragraph_width_; }
5314
5317 CLI11_NODISCARD float get_long_option_alignment_ratio() const { return long_option_alignment_ratio_; }
5318
5321
5323 CLI11_NODISCARD bool is_footer_paragraph_formatting_enabled() const { return enable_footer_formatting_; }
5324
5326 CLI11_NODISCARD bool is_option_defaults_enabled() const { return enable_option_defaults_; }
5327
5329 CLI11_NODISCARD bool is_option_type_names_enabled() const { return enable_option_type_names_; }
5330
5332 CLI11_NODISCARD bool is_default_flag_values_enabled() const { return enable_default_flag_values_; }
5333
5335};
5336
5338class FormatterLambda final : public FormatterBase {
5339 using funct_t = std::function<std::string(const App *, std::string, AppFormatMode)>;
5340
5342 funct_t lambda_;
5343
5344 public:
5346 explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {}
5347
5349 ~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default)
5350
5352 std::string make_help(const App *app, std::string name, AppFormatMode mode) const override {
5353 return lambda_(app, name, mode);
5354 }
5355};
5356
5359class Formatter : public FormatterBase {
5360 public:
5361 Formatter() = default;
5362 Formatter(const Formatter &) = default;
5363 Formatter(Formatter &&) = default;
5364 Formatter &operator=(const Formatter &) = default;
5365 Formatter &operator=(Formatter &&) = default;
5366
5369
5372 CLI11_NODISCARD virtual std::string
5373 make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const;
5374
5376 virtual std::string make_positionals(const App *app) const;
5377
5379 std::string make_groups(const App *app, AppFormatMode mode) const;
5380
5382 virtual std::string make_subcommands(const App *app, AppFormatMode mode) const;
5383
5385 virtual std::string make_subcommand(const App *sub) const;
5386
5388 virtual std::string make_expanded(const App *sub, AppFormatMode mode) const;
5389
5391 virtual std::string make_footer(const App *app) const;
5392
5394 virtual std::string make_description(const App *app) const;
5395
5397 virtual std::string make_usage(const App *app, std::string name) const;
5398
5400 std::string make_help(const App *app, std::string, AppFormatMode mode) const override;
5401
5405
5407 virtual std::string make_option(const Option *, bool) const;
5408
5410 virtual std::string make_option_name(const Option *, bool) const;
5411
5413 virtual std::string make_option_opts(const Option *) const;
5414
5416 virtual std::string make_option_desc(const Option *) const;
5417
5419 virtual std::string make_option_usage(const Option *opt) const;
5420
5422};
5423
5424
5425
5426
5427using results_t = std::vector<std::string>;
5429using callback_t = std::function<bool(const results_t &)>;
5430
5431class Option;
5432class App;
5433class ConfigBase;
5434
5435using Option_p = std::unique_ptr<Option>;
5436using Validator_p = std::shared_ptr<Validator>;
5437
5439enum class MultiOptionPolicy : char {
5440 Throw,
5441 TakeLast,
5442 TakeFirst,
5443 Join,
5444 TakeAll,
5445 Sum,
5446 Reverse,
5447};
5448
5450enum class CallbackPriority : std::uint8_t {
5451 FirstPreHelp = 0,
5452 First = 1,
5453 PreRequirementsCheckPreHelp = 2,
5454 PreRequirementsCheck = 3,
5455 NormalPreHelp = 4,
5456 Normal = 5,
5457 LastPreHelp = 6,
5458 Last = 7
5459}; // namespace CLI
5460
5463template <typename CRTP> class OptionBase {
5464 friend App;
5465 friend ConfigBase;
5466
5467 protected:
5469 std::string group_ = std::string("OPTIONS");
5470
5472 bool required_{false};
5473
5475 bool ignore_case_{false};
5476
5479
5481 bool configurable_{true};
5482
5485
5487 char delimiter_{'\0'};
5488
5491
5493 MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw};
5494
5496 CallbackPriority callback_priority_{CallbackPriority::Normal};
5497
5499 template <typename T> void copy_to(T *other) const;
5500
5501 public:
5502 // setters
5503
5505 CRTP *group(const std::string &name) {
5506 if(!detail::valid_alias_name_string(name)) {
5507 throw IncorrectConstruction("Group names may not contain newlines or null characters");
5508 }
5509 group_ = name;
5510 return static_cast<CRTP *>(this);
5511 }
5512
5514 CRTP *required(bool value = true) {
5515 required_ = value;
5516 return static_cast<CRTP *>(this);
5517 }
5518
5520 CRTP *mandatory(bool value = true) { return required(value); }
5521
5522 CRTP *always_capture_default(bool value = true) {
5524 return static_cast<CRTP *>(this);
5525 }
5526
5527 // Getters
5528
5530 CLI11_NODISCARD const std::string &get_group() const { return group_; }
5531
5533 CLI11_NODISCARD bool get_required() const { return required_; }
5534
5536 CLI11_NODISCARD bool get_ignore_case() const { return ignore_case_; }
5537
5539 CLI11_NODISCARD bool get_ignore_underscore() const { return ignore_underscore_; }
5540
5542 CLI11_NODISCARD bool get_configurable() const { return configurable_; }
5543
5545 CLI11_NODISCARD bool get_disable_flag_override() const { return disable_flag_override_; }
5546
5548 CLI11_NODISCARD char get_delimiter() const { return delimiter_; }
5549
5551 CLI11_NODISCARD bool get_always_capture_default() const { return always_capture_default_; }
5552
5554 CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; }
5555
5557 CLI11_NODISCARD CallbackPriority get_callback_priority() const { return callback_priority_; }
5558
5559 // Shortcuts for multi option policy
5560
5562 CRTP *take_last() {
5563 auto *self = static_cast<CRTP *>(this);
5564 self->multi_option_policy(MultiOptionPolicy::TakeLast);
5565 return self;
5566 }
5567
5569 CRTP *take_first() {
5570 auto *self = static_cast<CRTP *>(this);
5571 self->multi_option_policy(MultiOptionPolicy::TakeFirst);
5572 return self;
5573 }
5574
5576 CRTP *take_all() {
5577 auto self = static_cast<CRTP *>(this);
5578 self->multi_option_policy(MultiOptionPolicy::TakeAll);
5579 return self;
5580 }
5581
5583 CRTP *join() {
5584 auto *self = static_cast<CRTP *>(this);
5585 self->multi_option_policy(MultiOptionPolicy::Join);
5586 return self;
5587 }
5588
5590 CRTP *join(char delim) {
5591 auto self = static_cast<CRTP *>(this);
5592 self->delimiter_ = delim;
5593 self->multi_option_policy(MultiOptionPolicy::Join);
5594 return self;
5595 }
5596
5598 CRTP *configurable(bool value = true) {
5599 configurable_ = value;
5600 return static_cast<CRTP *>(this);
5601 }
5602
5604 CRTP *delimiter(char value = '\0') {
5605 delimiter_ = value;
5606 return static_cast<CRTP *>(this);
5607 }
5608};
5609
5612class OptionDefaults : public OptionBase<OptionDefaults> {
5613 public:
5614 OptionDefaults() = default;
5615
5616 // Methods here need a different implementation if they are Option vs. OptionDefault
5617
5619 OptionDefaults *callback_priority(CallbackPriority value = CallbackPriority::Normal) {
5620 callback_priority_ = value;
5621 return this;
5622 }
5623
5625 OptionDefaults *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
5626 multi_option_policy_ = value;
5627 return this;
5628 }
5629
5631 OptionDefaults *ignore_case(bool value = true) {
5632 ignore_case_ = value;
5633 return this;
5634 }
5635
5637 OptionDefaults *ignore_underscore(bool value = true) {
5638 ignore_underscore_ = value;
5639 return this;
5640 }
5641
5643 OptionDefaults *disable_flag_override(bool value = true) {
5644 disable_flag_override_ = value;
5645 return this;
5646 }
5647
5649 OptionDefaults *delimiter(char value = '\0') {
5650 delimiter_ = value;
5651 return this;
5652 }
5653};
5654
5655class Option : public OptionBase<Option> {
5656 friend App;
5657 friend ConfigBase;
5658
5659 protected:
5662
5664 std::vector<std::string> snames_{};
5665
5667 std::vector<std::string> lnames_{};
5668
5671 std::vector<std::pair<std::string, std::string>> default_flag_values_{};
5672
5674 std::vector<std::string> fnames_{};
5675
5677 std::string pname_{};
5678
5680 std::string envname_{};
5681
5685
5687 std::string description_{};
5688
5690 std::string default_str_{};
5691
5693 std::string option_text_{};
5694
5698 std::function<std::string()> type_name_{[]() { return std::string(); }};
5699
5701 std::function<std::string()> default_function_{};
5702
5706
5712
5717
5719 std::vector<Validator_p> validators_{};
5720
5722 std::set<Option *> needs_{};
5723
5725 std::set<Option *> excludes_{};
5726
5730
5732 App *parent_{nullptr};
5733
5735 callback_t callback_{};
5736
5740
5742 results_t results_{};
5744 mutable results_t proc_results_{};
5746 enum class option_state : char {
5751 };
5752
5757 bool flag_like_{false};
5765 bool force_callback_{false};
5766
5768 Option(std::string option_name,
5769 std::string option_description,
5770 callback_t callback,
5771 App *parent,
5772 bool allow_non_standard = false)
5773 : description_(std::move(option_description)), parent_(parent), callback_(std::move(callback)) {
5774 std::tie(snames_, lnames_, pname_) = detail::get_names(detail::split_names(option_name), allow_non_standard);
5775 }
5776
5777 public:
5780
5781 Option(const Option &) = delete;
5782 Option &operator=(const Option &) = delete;
5783
5785 CLI11_NODISCARD std::size_t count() const { return results_.size(); }
5786
5788 CLI11_NODISCARD bool empty() const { return results_.empty(); }
5789
5791 explicit operator bool() const { return !empty() || force_callback_; }
5792
5794 void clear() {
5795 results_.clear();
5797 }
5798
5802
5804 Option *expected(int value);
5805
5807 Option *expected(int value_min, int value_max);
5808
5811 Option *allow_extra_args(bool value = true) {
5812 allow_extra_args_ = value;
5813 return this;
5814 }
5815
5816 CLI11_NODISCARD bool get_allow_extra_args() const { return allow_extra_args_; }
5818 Option *trigger_on_parse(bool value = true) {
5819 trigger_on_result_ = value;
5820 return this;
5821 }
5822
5823 CLI11_NODISCARD bool get_trigger_on_parse() const { return trigger_on_result_; }
5824
5826 Option *force_callback(bool value = true) {
5827 force_callback_ = value;
5828 return this;
5829 }
5830
5831 CLI11_NODISCARD bool get_force_callback() const { return force_callback_; }
5832
5835 Option *run_callback_for_default(bool value = true) {
5837 return this;
5838 }
5839
5840 CLI11_NODISCARD bool get_run_callback_for_default() const { return run_callback_for_default_; }
5841
5844 Option *callback_priority(CallbackPriority value = CallbackPriority::Normal) {
5845 callback_priority_ = value;
5846 return this;
5847 }
5848
5850 Option *check(Validator_p validator);
5851
5853 Option *check(Validator validator, const std::string &validator_name = "");
5854
5856 Option *check(std::function<std::string(const std::string &)> validator_func,
5857 std::string validator_description = "",
5858 std::string validator_name = "");
5859
5861 Option *transform(Validator_p validator);
5862
5864 Option *transform(Validator validator, const std::string &transform_name = "");
5865
5867 Option *transform(const std::function<std::string(std::string)> &transform_func,
5868 std::string transform_description = "",
5869 std::string transform_name = "");
5870
5872 Option *each(const std::function<void(std::string)> &func);
5873
5875 Validator *get_validator(const std::string &validator_name = "");
5876
5878 Validator *get_validator(int index);
5879
5882 if(opt != this) {
5883 needs_.insert(opt);
5884 }
5885 return this;
5886 }
5887
5889 template <typename T = App> Option *needs(std::string opt_name) {
5890 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
5891 if(opt == nullptr) {
5892 throw IncorrectConstruction::MissingOption(opt_name);
5893 }
5894 return needs(opt);
5895 }
5896
5898 template <typename A, typename B, typename... ARG> Option *needs(A opt, B opt1, ARG... args) {
5899 needs(opt);
5900 return needs(opt1, args...); // NOLINT(readability-suspicious-call-argument)
5901 }
5902
5904 bool remove_needs(Option *opt);
5905
5907 Option *excludes(Option *opt);
5908
5910 template <typename T = App> Option *excludes(std::string opt_name) {
5911 auto opt = static_cast<T *>(parent_)->get_option_no_throw(opt_name);
5912 if(opt == nullptr) {
5913 throw IncorrectConstruction::MissingOption(opt_name);
5914 }
5915 return excludes(opt);
5916 }
5917
5919 template <typename A, typename B, typename... ARG> Option *excludes(A opt, B opt1, ARG... args) {
5920 excludes(opt);
5921 return excludes(opt1, args...);
5922 }
5923
5925 bool remove_excludes(Option *opt);
5926
5928 Option *envname(std::string name) {
5929 envname_ = std::move(name);
5930 return this;
5931 }
5932
5937 template <typename T = App> Option *ignore_case(bool value = true);
5938
5943 template <typename T = App> Option *ignore_underscore(bool value = true);
5944
5946 Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw);
5947
5949 Option *disable_flag_override(bool value = true) {
5950 disable_flag_override_ = value;
5951 return this;
5952 }
5953
5956
5958 CLI11_NODISCARD int get_type_size() const { return type_size_min_; }
5959
5961 CLI11_NODISCARD int get_type_size_min() const { return type_size_min_; }
5963 CLI11_NODISCARD int get_type_size_max() const { return type_size_max_; }
5964
5966 CLI11_NODISCARD bool get_inject_separator() const { return inject_separator_; }
5967
5969 CLI11_NODISCARD std::string get_envname() const { return envname_; }
5970
5972 CLI11_NODISCARD std::set<Option *> get_needs() const { return needs_; }
5973
5975 CLI11_NODISCARD std::set<Option *> get_excludes() const { return excludes_; }
5976
5978 CLI11_NODISCARD std::string get_default_str() const { return default_str_; }
5979
5981 CLI11_NODISCARD callback_t get_callback() const { return callback_; }
5982
5984 CLI11_NODISCARD const std::vector<std::string> &get_lnames() const { return lnames_; }
5985
5987 CLI11_NODISCARD const std::vector<std::string> &get_snames() const { return snames_; }
5988
5990 CLI11_NODISCARD const std::vector<std::string> &get_fnames() const { return fnames_; }
5992 CLI11_NODISCARD const std::string &get_single_name() const {
5993 if(!lnames_.empty()) {
5994 return lnames_[0];
5995 }
5996 if(!snames_.empty()) {
5997 return snames_[0];
5998 }
5999 if(!pname_.empty()) {
6000 return pname_;
6001 }
6002 return envname_;
6003 }
6004
6005 CLI11_NODISCARD int get_expected() const { return expected_min_; }
6006
6008 CLI11_NODISCARD int get_expected_min() const { return expected_min_; }
6010 CLI11_NODISCARD int get_expected_max() const { return expected_max_; }
6011
6013 CLI11_NODISCARD int get_items_expected_min() const { return type_size_min_ * expected_min_; }
6014
6016 CLI11_NODISCARD int get_items_expected_max() const {
6017 int t = type_size_max_;
6018 return detail::checked_multiply(t, expected_max_) ? t : detail::expected_max_vector_size;
6019 }
6020
6021 CLI11_NODISCARD int get_items_expected() const { return get_items_expected_min(); }
6022
6024 CLI11_NODISCARD bool get_positional() const { return !pname_.empty(); }
6025
6027 CLI11_NODISCARD bool nonpositional() const { return (!lnames_.empty() || !snames_.empty()); }
6028
6030 CLI11_NODISCARD bool has_description() const { return !description_.empty(); }
6031
6033 CLI11_NODISCARD const std::string &get_description() const { return description_; }
6034
6036 Option *description(std::string option_description) {
6037 description_ = std::move(option_description);
6038 return this;
6039 }
6040
6041 Option *option_text(std::string text) {
6042 option_text_ = std::move(text);
6043 return this;
6044 }
6045
6046 CLI11_NODISCARD const std::string &get_option_text() const { return option_text_; }
6047
6051
6057 CLI11_NODISCARD std::string get_name(bool positional = false,
6058 bool all_options = false,
6059 bool disable_default_flag_values = false
6060 ) const;
6061
6065
6067 void run_callback();
6068
6070 CLI11_NODISCARD const std::string &matching_name(const Option &other) const;
6071
6073 bool operator==(const Option &other) const { return !matching_name(other).empty(); }
6074
6076 CLI11_NODISCARD bool check_name(const std::string &name) const;
6077
6079 CLI11_NODISCARD bool check_sname(std::string name) const {
6080 return (detail::find_member(std::move(name), snames_, ignore_case_) >= 0);
6081 }
6082
6084 CLI11_NODISCARD bool check_lname(std::string name) const {
6085 return (detail::find_member(std::move(name), lnames_, ignore_case_, ignore_underscore_) >= 0);
6086 }
6087
6089 CLI11_NODISCARD bool check_fname(std::string name) const {
6090 if(fnames_.empty()) {
6091 return false;
6092 }
6093 return (detail::find_member(std::move(name), fnames_, ignore_case_, ignore_underscore_) >= 0);
6094 }
6095
6098 CLI11_NODISCARD std::string get_flag_value(const std::string &name, std::string input_value) const;
6099
6101 Option *add_result(std::string s);
6102
6104 Option *add_result(std::string s, int &results_added);
6105
6107 Option *add_result(std::vector<std::string> s);
6108
6110 CLI11_NODISCARD const results_t &results() const { return results_; }
6111
6113 CLI11_NODISCARD results_t reduced_results() const;
6114
6116 template <typename T> void results(T &output) const {
6117 bool retval = false;
6118 if(current_option_state_ >= option_state::reduced || (results_.size() == 1 && validators_.empty())) {
6119 const results_t &res = (proc_results_.empty()) ? results_ : proc_results_;
6120 if(!res.empty()) {
6121 retval = detail::lexical_conversion<T, T>(res, output);
6122 } else {
6123 results_t res2;
6124 res2.emplace_back();
6125 proc_results_ = std::move(res2);
6126 retval = detail::lexical_conversion<T, T>(proc_results_, output);
6127 }
6128
6129 } else {
6130 results_t res;
6131 if(results_.empty()) {
6132 if(!default_str_.empty()) {
6133 // _add_results takes an rvalue only
6134 _add_result(std::string(default_str_), res);
6135 _validate_results(res);
6136 results_t extra;
6137 _reduce_results(extra, res);
6138 if(!extra.empty()) {
6139 res = std::move(extra);
6140 }
6141 } else {
6142 res.emplace_back();
6143 }
6144 } else {
6145 res = reduced_results();
6146 }
6147 // store the results in a stable location if the output is a view
6148 proc_results_ = std::move(res);
6149 retval = detail::lexical_conversion<T, T>(proc_results_, output);
6150 }
6151 if(!retval) {
6153 }
6154 }
6155
6157 template <typename T> CLI11_NODISCARD T as() const {
6158 T output;
6159 results(output);
6160 return output;
6161 }
6162
6164 CLI11_NODISCARD bool get_callback_run() const { return (current_option_state_ == option_state::callback_run); }
6165
6169
6171 Option *type_name_fn(std::function<std::string()> typefun) {
6172 type_name_ = std::move(typefun);
6173 return this;
6174 }
6175
6177 Option *type_name(std::string typeval) {
6178 type_name_fn([typeval]() { return typeval; });
6179 return this;
6180 }
6181
6183 Option *type_size(int option_type_size);
6184
6186 Option *type_size(int option_type_size_min, int option_type_size_max);
6187
6189 void inject_separator(bool value = true) { inject_separator_ = value; }
6190
6192 Option *default_function(const std::function<std::string()> &func) {
6193 default_function_ = func;
6194 return this;
6195 }
6196
6199 if(default_function_) {
6201 }
6202 return this;
6203 }
6204
6206 Option *default_str(std::string val) {
6207 default_str_ = std::move(val);
6208 return this;
6209 }
6210
6213 template <typename X> Option *default_val(const X &val) {
6214 std::string val_str = detail::value_string(val);
6215 auto old_option_state = current_option_state_;
6216 results_t old_results{std::move(results_)};
6217 results_.clear();
6218 try {
6219 add_result(val_str);
6220 // if trigger_on_result_ is set the callback already ran
6222 run_callback(); // run callback sets the state, we need to reset it again
6224 } else {
6225 _validate_results(results_);
6226 current_option_state_ = old_option_state;
6227 }
6228 } catch(const ConversionError &err) {
6229 // this should be done
6230 results_ = std::move(old_results);
6231 current_option_state_ = old_option_state;
6232
6233 throw ConversionError(
6234 get_name(), std::string("given default value(\"") + val_str + "\") produces an error : " + err.what());
6235 } catch(const CLI::Error &) {
6236 results_ = std::move(old_results);
6237 current_option_state_ = old_option_state;
6238 throw;
6239 }
6240 results_ = std::move(old_results);
6241 default_str_ = std::move(val_str);
6242 return this;
6243 }
6244
6246 CLI11_NODISCARD std::string get_type_name() const;
6247
6248 private:
6250 void _validate_results(results_t &res) const;
6251
6255 void _reduce_results(results_t &out, const results_t &original) const;
6256
6257 // Run a result through the Validators
6258 std::string _validate(std::string &result, int index) const;
6259
6261 int _add_result(std::string &&result, std::vector<std::string> &res) const;
6262};
6263
6264
6265
6266
6267template <typename CRTP> template <typename T> void OptionBase<CRTP>::copy_to(T *other) const {
6268 other->group(group_);
6269 other->required(required_);
6270 other->ignore_case(ignore_case_);
6271 other->ignore_underscore(ignore_underscore_);
6272 other->configurable(configurable_);
6273 other->disable_flag_override(disable_flag_override_);
6274 other->delimiter(delimiter_);
6275 other->always_capture_default(always_capture_default_);
6276 other->multi_option_policy(multi_option_policy_);
6277 other->callback_priority(callback_priority_);
6278}
6279
6280CLI11_INLINE Option *Option::expected(int value) {
6281 if(value < 0) {
6282 expected_min_ = -value;
6285 }
6286 allow_extra_args_ = true;
6287 flag_like_ = false;
6288 } else if(value == detail::expected_max_vector_size) {
6289 expected_min_ = 1;
6290 expected_max_ = detail::expected_max_vector_size;
6291 allow_extra_args_ = true;
6292 flag_like_ = false;
6293 } else {
6294 expected_min_ = value;
6295 expected_max_ = value;
6296 flag_like_ = (expected_min_ == 0);
6297 }
6298 return this;
6299}
6300
6301CLI11_INLINE Option *Option::expected(int value_min, int value_max) {
6302 if(value_min < 0) {
6303 value_min = -value_min;
6304 }
6305
6306 if(value_max < 0) {
6307 value_max = detail::expected_max_vector_size;
6308 }
6309 if(value_max < value_min) {
6310 expected_min_ = value_max;
6311 expected_max_ = value_min;
6312 } else {
6313 expected_max_ = value_max;
6314 expected_min_ = value_min;
6315 }
6316
6317 return this;
6318}
6319
6320CLI11_INLINE Option *Option::check(Validator_p validator) {
6321 validator->non_modifying();
6322 validators_.push_back(std::move(validator));
6323
6324 return this;
6325}
6326
6327CLI11_INLINE Option *Option::check(Validator validator, const std::string &validator_name) {
6328 validator.non_modifying();
6329 auto vp = std::make_shared<Validator>(std::move(validator));
6330 if(!validator_name.empty()) {
6331 vp->name(validator_name);
6332 }
6333 validators_.push_back(std::move(vp));
6334
6335 return this;
6336}
6337
6338CLI11_INLINE Option *Option::check(std::function<std::string(const std::string &)> validator_func,
6339 std::string validator_description,
6340 std::string validator_name) {
6341
6342 auto vp = std::make_shared<Validator>(
6343 std::move(validator_func), std::move(validator_description), std::move(validator_name));
6344 vp->non_modifying();
6345 validators_.push_back(std::move(vp));
6346 return this;
6347}
6348
6349CLI11_INLINE Option *Option::transform(Validator_p validator) {
6350 validators_.insert(validators_.begin(), std::move(validator));
6351
6352 return this;
6353}
6354
6355CLI11_INLINE Option *Option::transform(Validator validator, const std::string &transform_name) {
6356 auto vp = std::make_shared<Validator>(std::move(validator));
6357 if(!transform_name.empty()) {
6358 vp->name(transform_name);
6359 }
6360 validators_.insert(validators_.begin(), std::move(vp));
6361 return this;
6362}
6363
6364CLI11_INLINE Option *Option::transform(const std::function<std::string(std::string)> &transform_func,
6365 std::string transform_description,
6366 std::string transform_name) {
6367 auto vp = std::make_shared<Validator>(
6368 [transform_func](std::string &val) {
6369 val = transform_func(val);
6370 return std::string{};
6371 },
6372 std::move(transform_description),
6373 std::move(transform_name));
6374 validators_.insert(validators_.begin(), std::move(vp));
6375
6376 return this;
6377}
6378
6379CLI11_INLINE Option *Option::each(const std::function<void(std::string)> &func) {
6380 auto vp = std::make_shared<Validator>(
6381 [func](std::string &inout) {
6382 func(inout);
6383 return std::string{};
6384 },
6385 std::string{});
6386 validators_.push_back(std::move(vp));
6387 return this;
6388}
6389
6390CLI11_INLINE Validator *Option::get_validator(const std::string &validator_name) {
6391 for(auto &validator : validators_) {
6392 if(validator_name == validator->get_name()) {
6393 return validator.get();
6394 }
6395 }
6396 if((validator_name.empty()) && (!validators_.empty())) {
6397 return validators_.front().get();
6398 }
6399 throw OptionNotFound(std::string{"Validator "} + validator_name + " Not Found");
6400}
6401
6402CLI11_INLINE Validator *Option::get_validator(int index) {
6403 // This is a signed int so that it is not equivalent to a pointer.
6404 if(index >= 0 && index < static_cast<int>(validators_.size())) {
6405 return validators_[static_cast<decltype(validators_)::size_type>(index)].get();
6406 }
6407 throw OptionNotFound("Validator index is not valid");
6408}
6409
6410CLI11_INLINE bool Option::remove_needs(Option *opt) {
6411 auto iterator = std::find(std::begin(needs_), std::end(needs_), opt);
6412
6413 if(iterator == std::end(needs_)) {
6414 return false;
6415 }
6416 needs_.erase(iterator);
6417 return true;
6418}
6419
6420CLI11_INLINE Option *Option::excludes(Option *opt) {
6421 if(opt == this) {
6422 throw(IncorrectConstruction("and option cannot exclude itself"));
6423 }
6424 excludes_.insert(opt);
6425
6426 // Help text should be symmetric - excluding a should exclude b
6427 opt->excludes_.insert(this);
6428
6429 // Ignoring the insert return value, excluding twice is now allowed.
6430 // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
6431
6432 return this;
6433}
6434
6435CLI11_INLINE bool Option::remove_excludes(Option *opt) {
6436 auto iterator = std::find(std::begin(excludes_), std::end(excludes_), opt);
6437
6438 if(iterator == std::end(excludes_)) {
6439 return false;
6440 }
6441 excludes_.erase(iterator);
6442 return true;
6443}
6444
6445template <typename T> Option *Option::ignore_case(bool value) {
6446 if(!ignore_case_ && value) {
6447 ignore_case_ = value;
6448 auto *parent = static_cast<T *>(parent_);
6449 for(const Option_p &opt : parent->options_) {
6450 if(opt.get() == this) {
6451 continue;
6452 }
6453 const auto &omatch = opt->matching_name(*this);
6454 if(!omatch.empty()) {
6455 ignore_case_ = false;
6456 throw OptionAlreadyAdded("adding ignore case caused a name conflict with " + omatch);
6457 }
6458 }
6459 } else {
6460 ignore_case_ = value;
6461 }
6462 return this;
6463}
6464
6465template <typename T> Option *Option::ignore_underscore(bool value) {
6466
6467 if(!ignore_underscore_ && value) {
6468 ignore_underscore_ = value;
6469 auto *parent = static_cast<T *>(parent_);
6470 for(const Option_p &opt : parent->options_) {
6471 if(opt.get() == this) {
6472 continue;
6473 }
6474 const auto &omatch = opt->matching_name(*this);
6475 if(!omatch.empty()) {
6476 ignore_underscore_ = false;
6477 throw OptionAlreadyAdded("adding ignore underscore caused a name conflict with " + omatch);
6478 }
6479 }
6480 } else {
6481 ignore_underscore_ = value;
6482 }
6483 return this;
6484}
6485
6486CLI11_INLINE Option *Option::multi_option_policy(MultiOptionPolicy value) {
6487 if(value != multi_option_policy_) {
6488 if(multi_option_policy_ == MultiOptionPolicy::Throw && expected_max_ == detail::expected_max_vector_size &&
6489 expected_min_ > 1) { // this bizarre condition is to maintain backwards compatibility
6490 // with the previous behavior of expected_ with vectors
6492 }
6493 multi_option_policy_ = value;
6495 }
6496 return this;
6497}
6498
6499CLI11_NODISCARD CLI11_INLINE std::string
6500Option::get_name(bool positional, bool all_options, bool disable_default_flag_values) const {
6501 if(get_group().empty())
6502 return {}; // Hidden
6503
6504 if(all_options) {
6505
6506 std::vector<std::string> name_list;
6507
6509 if((positional && (!pname_.empty())) || (snames_.empty() && lnames_.empty())) {
6510 name_list.push_back(pname_);
6511 }
6512 if((get_items_expected() == 0) && (!fnames_.empty())) {
6513 for(const std::string &sname : snames_) {
6514 name_list.push_back("-" + sname);
6515 if(!disable_default_flag_values && check_fname(sname)) {
6516 name_list.back() += "{" + get_flag_value(sname, "") + "}";
6517 }
6518 }
6519
6520 for(const std::string &lname : lnames_) {
6521 name_list.push_back("--" + lname);
6522 if(!disable_default_flag_values && check_fname(lname)) {
6523 name_list.back() += "{" + get_flag_value(lname, "") + "}";
6524 }
6525 }
6526 } else {
6527 for(const std::string &sname : snames_)
6528 name_list.push_back("-" + sname);
6529
6530 for(const std::string &lname : lnames_)
6531 name_list.push_back("--" + lname);
6532 }
6533
6534 return detail::join(name_list);
6535 }
6536
6537 // This returns the positional name no matter what
6538 if(positional)
6539 return pname_;
6540
6541 // Prefer long name
6542 if(!lnames_.empty())
6543 return std::string(2, '-') + lnames_[0];
6544
6545 // Or short name if no long name
6546 if(!snames_.empty())
6547 return std::string(1, '-') + snames_[0];
6548
6549 // If positional is the only name, it's okay to use that
6550 return pname_;
6551}
6552
6553CLI11_INLINE void Option::run_callback() {
6554 bool used_default_str = false;
6555 if(force_callback_ && results_.empty()) {
6556 used_default_str = true;
6558 }
6560 _validate_results(results_);
6562 }
6563
6565 _reduce_results(proc_results_, results_);
6566 }
6567
6569 if(callback_) {
6570 const results_t &send_results = proc_results_.empty() ? results_ : proc_results_;
6571 if(send_results.empty()) {
6572 return;
6573 }
6574 bool local_result = callback_(send_results);
6575 if(used_default_str) {
6576 // we only clear the results if the callback was actually used
6577 // otherwise the callback is the storage of the default
6578 results_.clear();
6579 proc_results_.clear();
6580 }
6581 if(!local_result)
6583 }
6584}
6585
6586CLI11_NODISCARD CLI11_INLINE const std::string &Option::matching_name(const Option &other) const {
6587 static const std::string estring;
6588 bool bothConfigurable = configurable_ && other.configurable_;
6589 for(const std::string &sname : snames_) {
6590 if(other.check_sname(sname))
6591 return sname;
6592 if(bothConfigurable && other.check_lname(sname))
6593 return sname;
6594 }
6595 for(const std::string &lname : lnames_) {
6596 if(other.check_lname(lname))
6597 return lname;
6598 if(lname.size() == 1 && bothConfigurable) {
6599 if(other.check_sname(lname)) {
6600 return lname;
6601 }
6602 }
6603 }
6604 if(bothConfigurable && snames_.empty() && lnames_.empty() && !pname_.empty()) {
6605 if(other.check_sname(pname_) || other.check_lname(pname_) || pname_ == other.pname_)
6606 return pname_;
6607 }
6608 if(bothConfigurable && other.snames_.empty() && other.fnames_.empty() && !other.pname_.empty()) {
6609 if(check_sname(other.pname_) || check_lname(other.pname_) || (pname_ == other.pname_))
6610 return other.pname_;
6611 }
6612 if(ignore_case_ ||
6613 ignore_underscore_) { // We need to do the inverse, in case we are ignore_case or ignore underscore
6614 for(const std::string &sname : other.snames_)
6615 if(check_sname(sname))
6616 return sname;
6617 for(const std::string &lname : other.lnames_)
6618 if(check_lname(lname))
6619 return lname;
6620 }
6621 return estring;
6622}
6623
6624CLI11_NODISCARD CLI11_INLINE bool Option::check_name(const std::string &name) const {
6625
6626 if(name.length() > 2 && name[0] == '-' && name[1] == '-')
6627 return check_lname(name.substr(2));
6628 if(name.length() > 1 && name.front() == '-')
6629 return check_sname(name.substr(1));
6630 if(!pname_.empty()) {
6631 std::string local_pname = pname_;
6632 std::string local_name = name;
6633 if(ignore_underscore_) {
6634 local_pname = detail::remove_underscore(local_pname);
6635 local_name = detail::remove_underscore(local_name);
6636 }
6637 if(ignore_case_) {
6638 local_pname = detail::to_lower(local_pname);
6639 local_name = detail::to_lower(local_name);
6640 }
6641 if(local_name == local_pname) {
6642 return true;
6643 }
6644 }
6645
6646 if(!envname_.empty()) {
6647 // this needs to be the original since envname_ shouldn't match on case insensitivity
6648 return (name == envname_);
6649 }
6650 return false;
6651}
6652
6653CLI11_NODISCARD CLI11_INLINE std::string Option::get_flag_value(const std::string &name,
6654 std::string input_value) const {
6655 static const std::string trueString{"true"};
6656 static const std::string falseString{"false"};
6657 static const std::string emptyString{"{}"};
6658 // check for disable flag override_
6660 if(!((input_value.empty()) || (input_value == emptyString))) {
6661 auto default_ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
6662 if(default_ind >= 0) {
6663 // We can static cast this to std::size_t because it is more than 0 in this block
6664 if(default_flag_values_[static_cast<std::size_t>(default_ind)].second != input_value) {
6665 if(input_value == default_str_ && force_callback_) {
6666 return input_value;
6667 }
6668 throw(ArgumentMismatch::FlagOverride(name));
6669 }
6670 } else {
6671 if(input_value != trueString) {
6672 throw(ArgumentMismatch::FlagOverride(name));
6673 }
6674 }
6675 }
6676 }
6677 auto ind = detail::find_member(name, fnames_, ignore_case_, ignore_underscore_);
6678 if((input_value.empty()) || (input_value == emptyString)) {
6679 if(flag_like_) {
6680 return (ind < 0) ? trueString : default_flag_values_[static_cast<std::size_t>(ind)].second;
6681 }
6682 return (ind < 0) ? default_str_ : default_flag_values_[static_cast<std::size_t>(ind)].second;
6683 }
6684 if(ind < 0) {
6685 return input_value;
6686 }
6687 if(default_flag_values_[static_cast<std::size_t>(ind)].second == falseString) {
6688 errno = 0;
6689 auto val = detail::to_flag_value(input_value);
6690 if(errno != 0) {
6691 errno = 0;
6692 return input_value;
6693 }
6694 return (val == 1) ? falseString : (val == (-1) ? trueString : std::to_string(-val));
6695 }
6696 return input_value;
6697}
6698
6699CLI11_INLINE Option *Option::add_result(std::string s) {
6700 _add_result(std::move(s), results_);
6702 return this;
6703}
6704
6705CLI11_INLINE Option *Option::add_result(std::string s, int &results_added) {
6706 results_added = _add_result(std::move(s), results_);
6708 return this;
6709}
6710
6711CLI11_INLINE Option *Option::add_result(std::vector<std::string> s) {
6713 for(auto &str : s) {
6714 _add_result(std::move(str), results_);
6715 }
6716 return this;
6717}
6718
6719CLI11_NODISCARD CLI11_INLINE results_t Option::reduced_results() const {
6720 results_t res = proc_results_.empty() ? results_ : proc_results_;
6723 res = results_;
6724 _validate_results(res);
6725 }
6726 if(!res.empty()) {
6727 results_t extra;
6728 _reduce_results(extra, res);
6729 if(!extra.empty()) {
6730 res = std::move(extra);
6731 }
6732 }
6733 }
6734 return res;
6735}
6736
6737CLI11_INLINE Option *Option::type_size(int option_type_size) {
6738 if(option_type_size < 0) {
6739 // this section is included for backwards compatibility
6740 type_size_max_ = -option_type_size;
6741 type_size_min_ = -option_type_size;
6742 expected_max_ = detail::expected_max_vector_size;
6743 } else {
6744 type_size_max_ = option_type_size;
6745 if(type_size_max_ < detail::expected_max_vector_size) {
6746 type_size_min_ = option_type_size;
6747 } else {
6748 inject_separator_ = true;
6749 }
6750 if(type_size_max_ == 0)
6751 required_ = false;
6752 }
6753 return this;
6754}
6755
6756CLI11_INLINE Option *Option::type_size(int option_type_size_min, int option_type_size_max) {
6757 if(option_type_size_min < 0 || option_type_size_max < 0) {
6758 // this section is included for backwards compatibility
6759 expected_max_ = detail::expected_max_vector_size;
6760 option_type_size_min = (std::abs)(option_type_size_min);
6761 option_type_size_max = (std::abs)(option_type_size_max);
6762 }
6763
6764 if(option_type_size_min > option_type_size_max) {
6765 type_size_max_ = option_type_size_min;
6766 type_size_min_ = option_type_size_max;
6767 } else {
6768 type_size_min_ = option_type_size_min;
6769 type_size_max_ = option_type_size_max;
6770 }
6771 if(type_size_max_ == 0) {
6772 required_ = false;
6773 }
6774 if(type_size_max_ >= detail::expected_max_vector_size) {
6775 inject_separator_ = true;
6776 }
6777 return this;
6778}
6779
6780CLI11_NODISCARD CLI11_INLINE std::string Option::get_type_name() const {
6781 std::string full_type_name = type_name_();
6782 if(!validators_.empty()) {
6783 for(const auto &validator : validators_) {
6784 std::string vtype = validator->get_description();
6785 if(!vtype.empty()) {
6786 full_type_name += ":" + vtype;
6787 }
6788 }
6789 }
6790 return full_type_name;
6791}
6792
6793CLI11_INLINE void Option::_validate_results(results_t &res) const {
6794 // Run the Validators (can change the string)
6795 if(!validators_.empty()) {
6796 if(type_size_max_ > 1) { // in this context index refers to the index in the type
6797 int index = 0;
6798 if(get_items_expected_max() < static_cast<int>(res.size()) &&
6799 (multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast ||
6800 multi_option_policy_ == CLI::MultiOptionPolicy::Reverse)) {
6801 // create a negative index for the earliest ones
6802 index = get_items_expected_max() - static_cast<int>(res.size());
6803 }
6804
6805 for(std::string &result : res) {
6806 if(detail::is_separator(result) && type_size_max_ != type_size_min_ && index >= 0) {
6807 index = 0; // reset index for variable size chunks
6808 continue;
6809 }
6810 auto err_msg = _validate(result, (index >= 0) ? (index % type_size_max_) : index);
6811 if(!err_msg.empty())
6812 throw ValidationError(get_name(), err_msg);
6813 ++index;
6814 }
6815 } else {
6816 int index = 0;
6817 if(expected_max_ < static_cast<int>(res.size()) &&
6818 (multi_option_policy_ == CLI::MultiOptionPolicy::TakeLast ||
6819 multi_option_policy_ == CLI::MultiOptionPolicy::Reverse)) {
6820 // create a negative index for the earliest ones
6821 index = expected_max_ - static_cast<int>(res.size());
6822 }
6823 for(std::string &result : res) {
6824 auto err_msg = _validate(result, index);
6825 ++index;
6826 if(!err_msg.empty())
6827 throw ValidationError(get_name(), err_msg);
6828 }
6829 }
6830 }
6831}
6832
6833CLI11_INLINE void Option::_reduce_results(results_t &out, const results_t &original) const {
6834
6835 // max num items expected or length of vector, always at least 1
6836 // Only valid for a trimming policy
6837
6838 out.clear();
6839 // Operation depends on the policy setting
6840 switch(multi_option_policy_) {
6841 case MultiOptionPolicy::TakeAll:
6842 break;
6843 case MultiOptionPolicy::TakeLast: {
6844 // Allow multi-option sizes (including 0)
6845 std::size_t trim_size = std::min<std::size_t>(
6846 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
6847 if(original.size() != trim_size) {
6848 out.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
6849 }
6850 } break;
6851 case MultiOptionPolicy::Reverse: {
6852 // Allow multi-option sizes (including 0)
6853 std::size_t trim_size = std::min<std::size_t>(
6854 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
6855 if(original.size() != trim_size || trim_size > 1) {
6856 out.assign(original.end() - static_cast<results_t::difference_type>(trim_size), original.end());
6857 }
6858 std::reverse(out.begin(), out.end());
6859 } break;
6860 case MultiOptionPolicy::TakeFirst: {
6861 std::size_t trim_size = std::min<std::size_t>(
6862 static_cast<std::size_t>(std::max<int>(get_items_expected_max(), 1)), original.size());
6863 if(original.size() != trim_size) {
6864 out.assign(original.begin(), original.begin() + static_cast<results_t::difference_type>(trim_size));
6865 }
6866 } break;
6867 case MultiOptionPolicy::Join:
6868 if(results_.size() > 1) {
6869 out.push_back(detail::join(original, std::string(1, (delimiter_ == '\0') ? '\n' : delimiter_)));
6870 }
6871 break;
6872 case MultiOptionPolicy::Sum:
6873 out.push_back(detail::sum_string_vector(original));
6874 break;
6875 case MultiOptionPolicy::Throw:
6876 default: {
6877 auto num_min = static_cast<std::size_t>(get_items_expected_min());
6878 auto num_max = static_cast<std::size_t>(get_items_expected_max());
6879 if(num_min == 0) {
6880 num_min = 1;
6881 }
6882 if(num_max == 0) {
6883 num_max = 1;
6884 }
6885 if(original.size() < num_min) {
6886 throw ArgumentMismatch::AtLeast(get_name(), static_cast<int>(num_min), original.size());
6887 }
6888 if(original.size() > num_max) {
6889 if(original.size() == 2 && num_max == 1 && original[1] == "%%" && original[0] == "{}") {
6890 // this condition is a trap for the following empty indicator check on config files, it may not be used
6891 // anymore
6892 out = original; // LCOV_EXCL_LINE
6893 } else {
6894 throw ArgumentMismatch::AtMost(get_name(), static_cast<int>(num_max), original.size());
6895 }
6896 }
6897 break;
6898 }
6899 }
6900 // this check is to allow an empty vector in certain circumstances but not if expected is not zero.
6901 // {} is the indicator for an empty container
6902 if(out.empty()) {
6903 if(original.size() == 1 && original[0] == "{}" && get_items_expected_min() > 0) {
6904 out.emplace_back("{}");
6905 out.emplace_back("%%");
6906 }
6907 } else if(out.size() == 1 && out[0] == "{}" && get_items_expected_min() > 0) {
6908 out.emplace_back("%%");
6909 }
6910}
6911
6912CLI11_INLINE std::string Option::_validate(std::string &result, int index) const {
6913 std::string err_msg;
6914 if(result.empty() && expected_min_ == 0) {
6915 // an empty with nothing expected is allowed
6916 return err_msg;
6917 }
6918 for(const auto &vali : validators_) {
6919 auto v = vali->get_application_index();
6920 if(v == -1 || v == index) {
6921 try {
6922 err_msg = (*vali)(result);
6923 } catch(const ValidationError &err) {
6924 err_msg = err.what();
6925 }
6926 if(!err_msg.empty())
6927 break;
6928 }
6929 }
6930
6931 return err_msg;
6932}
6933
6934CLI11_INLINE int Option::_add_result(std::string &&result, std::vector<std::string> &res) const {
6935 int result_count = 0;
6936
6937 // Handle the vector escape possibility all characters duplicated and starting with [[ ending with ]]
6938 // this is always a single result
6939 if(result.size() >= 4 && result[0] == '[' && result[1] == '[' && result.back() == ']' &&
6940 (*(result.end() - 2) == ']')) {
6941 // this is an escape clause for odd strings
6942 std::string nstrs{'['};
6943 bool duplicated{true};
6944 for(std::size_t ii = 2; ii < result.size() - 2; ii += 2) {
6945 if(result[ii] == result[ii + 1]) {
6946 nstrs.push_back(result[ii]);
6947 } else {
6948 duplicated = false;
6949 break;
6950 }
6951 }
6952 if(duplicated) {
6953 nstrs.push_back(']');
6954 res.push_back(std::move(nstrs));
6955 ++result_count;
6956 return result_count;
6957 }
6958 }
6959
6960 if((allow_extra_args_ || get_expected_max() > 1 || get_type_size() > 1) && !result.empty() &&
6961 result.front() == '[' &&
6962 result.back() == ']') { // this is now a vector string likely from the default or user entry
6963
6964 result.pop_back();
6965 result.erase(result.begin());
6966 bool skipSection{false};
6967 for(auto &var : CLI::detail::split_up(result, ',')) {
6968 if(!var.empty()) {
6969 result_count += _add_result(std::move(var), res);
6970 }
6971 }
6972 if(!skipSection) {
6973 return result_count;
6974 }
6975 }
6976 if(delimiter_ == '\0') {
6977 res.push_back(std::move(result));
6978 ++result_count;
6979 } else {
6980 if((result.find_first_of(delimiter_) != std::string::npos)) {
6981 for(const auto &var : CLI::detail::split(result, delimiter_)) {
6982 if(!var.empty()) {
6983 res.push_back(var);
6984 ++result_count;
6985 }
6986 }
6987 } else {
6988 res.push_back(std::move(result));
6989 ++result_count;
6990 }
6991 }
6992 return result_count;
6993}
6994
6995
6996
6997#ifndef CLI11_PARSE
6998#define CLI11_PARSE(app, ...) \
6999 try { \
7000 (app).parse(__VA_ARGS__); \
7001 } catch(const CLI::ParseError &e) { \
7002 return (app).exit(e); \
7003 }
7004#endif
7005
7006namespace detail {
7007enum class Classifier : std::uint8_t {
7008 NONE,
7009 POSITIONAL_MARK,
7010 SHORT,
7011 LONG,
7012 WINDOWS_STYLE,
7013 SUBCOMMAND,
7014 SUBCOMMAND_TERMINATOR
7015};
7016struct AppFriend;
7017} // namespace detail
7018
7019namespace FailureMessage {
7021CLI11_INLINE std::string simple(const App *app, const Error &e);
7022
7024CLI11_INLINE std::string help(const App *app, const Error &e);
7025} // namespace FailureMessage
7026
7028enum class ExtrasMode : std::uint8_t {
7029 Error = 0,
7030 ErrorImmediately,
7031 Ignore,
7032 AssumeSingleArgument,
7033 AssumeMultipleArguments,
7034 Capture
7035};
7036
7038enum class ConfigExtrasMode : std::uint8_t { Error = 0, Ignore, IgnoreAll, Capture };
7039
7041enum class config_extras_mode : std::uint8_t { error = 0, ignore, ignore_all, capture };
7042
7046enum class PrefixCommandMode : std::uint8_t { Off = 0, SeparatorOnly = 1, On = 2 };
7047
7048class App;
7049
7050using App_p = std::shared_ptr<App>;
7051
7052namespace detail {
7054
7055template <typename T, enable_if_t<!std::is_integral<T>::value || (sizeof(T) <= 1U), detail::enabler> = detail::dummy>
7056Option *default_flag_modifiers(Option *opt) {
7057 return opt->always_capture_default();
7058}
7059
7061template <typename T, enable_if_t<std::is_integral<T>::value && (sizeof(T) > 1U), detail::enabler> = detail::dummy>
7062Option *default_flag_modifiers(Option *opt) {
7063 return opt->multi_option_policy(MultiOptionPolicy::Sum)->default_str("0")->force_callback();
7064}
7065
7066} // namespace detail
7067
7068class Option_group;
7070
7073class App {
7074 friend Option;
7075 friend detail::AppFriend;
7076
7077 protected:
7078 // This library follows the Google style guide for member names ending in underscores
7079
7082
7084 std::string name_{};
7085
7087 std::string description_{};
7088
7090 ExtrasMode allow_extras_{ExtrasMode::Error};
7091
7094 ConfigExtrasMode allow_config_extras_{ConfigExtrasMode::Ignore};
7095
7097 PrefixCommandMode prefix_command_{PrefixCommandMode::Off};
7098
7101
7103 bool required_{false};
7104
7106 bool disabled_{false};
7107
7110
7114
7116 std::function<void(std::size_t)> pre_parse_callback_{};
7117
7119 std::function<void()> parse_complete_callback_{};
7120
7122 std::function<void()> final_callback_{};
7123
7127
7130
7132 std::vector<Option_p> options_{};
7133
7137
7139 std::string usage_{};
7140
7142 std::function<std::string()> usage_callback_{};
7143
7145 std::string footer_{};
7146
7148 std::function<std::string()> footer_callback_{};
7149
7151 Option *help_ptr_{nullptr};
7152
7154 Option *help_all_ptr_{nullptr};
7155
7157 Option *version_ptr_{nullptr};
7158
7160 std::shared_ptr<FormatterBase> formatter_{new Formatter()};
7161
7163 std::function<std::string(const App *, const Error &e)> failure_message_{FailureMessage::simple};
7164
7168
7169 using missing_t = std::vector<std::pair<detail::Classifier, std::string>>;
7170
7174 missing_t missing_{};
7175
7177 std::vector<Option *> parse_order_{};
7178
7180 std::vector<App *> parsed_subcommands_{};
7181
7183 std::set<App *> exclude_subcommands_{};
7184
7187 std::set<Option *> exclude_options_{};
7188
7191 std::set<App *> need_subcommands_{};
7192
7195 std::set<Option *> need_options_{};
7196
7200
7202 std::vector<App_p> subcommands_{};
7203
7205 bool ignore_case_{false};
7206
7209
7212 bool fallthrough_{false};
7213
7216
7219#ifdef _WIN32
7220 true
7221#else
7222 false
7223#endif
7224 };
7225
7227
7228 enum class startup_mode : std::uint8_t { stable, enabled, disabled };
7231 startup_mode default_startup{startup_mode::stable};
7232
7234 bool configurable_{false};
7235
7238
7241
7244 bool silent_{false};
7245
7248
7251
7253 std::uint32_t parsed_{0U};
7254
7257
7260
7262 std::size_t require_option_min_{0};
7263
7265 std::size_t require_option_max_{0};
7266
7268 App *parent_{nullptr};
7269
7271 std::string group_{"SUBCOMMANDS"};
7272
7274 std::vector<std::string> aliases_{};
7275
7279
7281 Option *config_ptr_{nullptr};
7282
7284 std::shared_ptr<Config> config_formatter_{new ConfigTOML()};
7285
7287
7288#ifdef _WIN32
7290 std::vector<std::string> normalized_argv_{};
7291
7293 std::vector<char *> normalized_argv_view_{};
7294#endif
7295
7297 App(std::string app_description, std::string app_name, App *parent);
7298
7299 public:
7302
7304 explicit App(std::string app_description = "", std::string app_name = "")
7305 : App(app_description, app_name, nullptr) {
7306 set_help_flag("-h,--help", "Print this help message and exit");
7307 }
7308
7309 App(const App &) = delete;
7310 App &operator=(const App &) = delete;
7311
7313 virtual ~App() = default;
7314
7316 CLI11_NODISCARD char **ensure_utf8(char **argv);
7317
7324 App *callback(std::function<void()> app_callback) {
7326 parse_complete_callback_ = std::move(app_callback);
7327 } else {
7328 final_callback_ = std::move(app_callback);
7329 }
7330 return this;
7331 }
7332
7335 App *final_callback(std::function<void()> app_callback) {
7336 final_callback_ = std::move(app_callback);
7337 return this;
7338 }
7339
7342 App *parse_complete_callback(std::function<void()> pc_callback) {
7343 parse_complete_callback_ = std::move(pc_callback);
7344 return this;
7345 }
7346
7349 App *preparse_callback(std::function<void(std::size_t)> pp_callback) {
7350 pre_parse_callback_ = std::move(pp_callback);
7351 return this;
7352 }
7353
7355 App *name(std::string app_name = "");
7356
7358 App *alias(std::string app_name);
7359
7361 App *allow_extras(bool allow = true) {
7362 allow_extras_ = allow ? ExtrasMode::Capture : ExtrasMode::Error;
7363 return this;
7364 }
7365
7367 App *allow_extras(ExtrasMode allow) {
7368 allow_extras_ = allow;
7369 return this;
7370 }
7371
7373 App *required(bool require = true) {
7374 required_ = require;
7375 return this;
7376 }
7377
7379 App *disabled(bool disable = true) {
7380 disabled_ = disable;
7381 return this;
7382 }
7383
7385 App *silent(bool silence = true) {
7386 silent_ = silence;
7387 return this;
7388 }
7389
7391 App *allow_non_standard_option_names(bool allowed = true) {
7393 return this;
7394 }
7395
7398 allow_prefix_matching_ = allowed;
7399 return this;
7400 }
7401
7402 App *disabled_by_default(bool disable = true) {
7403 if(disable) {
7404 default_startup = startup_mode::disabled;
7405 } else {
7406 default_startup = (default_startup == startup_mode::enabled) ? startup_mode::enabled : startup_mode::stable;
7407 }
7408 return this;
7409 }
7410
7413 App *enabled_by_default(bool enable = true) {
7414 if(enable) {
7415 default_startup = startup_mode::enabled;
7416 } else {
7418 (default_startup == startup_mode::disabled) ? startup_mode::disabled : startup_mode::stable;
7419 }
7420 return this;
7421 }
7422
7424 App *immediate_callback(bool immediate = true);
7425
7427 App *validate_positionals(bool validate = true) {
7428 validate_positionals_ = validate;
7429 return this;
7430 }
7431
7433 App *validate_optional_arguments(bool validate = true) {
7435 return this;
7436 }
7437
7439 App *allow_config_extras(bool allow = true) {
7440 if(allow) {
7441 allow_config_extras_ = ConfigExtrasMode::Capture;
7442 allow_extras_ = ExtrasMode::Capture;
7443 } else {
7444 allow_config_extras_ = ConfigExtrasMode::Error;
7445 }
7446 return this;
7447 }
7448
7450 App *allow_config_extras(config_extras_mode mode) {
7451 allow_config_extras_ = static_cast<ConfigExtrasMode>(mode);
7452 return this;
7453 }
7454
7456 App *allow_config_extras(ConfigExtrasMode mode) {
7457 allow_config_extras_ = mode;
7458 return this;
7459 }
7460
7463 App *prefix_command(bool is_prefix = true) {
7464 prefix_command_ = is_prefix ? PrefixCommandMode::On : PrefixCommandMode::Off;
7465 return this;
7466 }
7467
7470 App *prefix_command(PrefixCommandMode mode) {
7471 prefix_command_ = mode;
7472 return this;
7473 }
7474
7476 App *ignore_case(bool value = true);
7477
7480 App *allow_windows_style_options(bool value = true) {
7482 return this;
7483 }
7484
7486 App *positionals_at_end(bool value = true) {
7487 positionals_at_end_ = value;
7488 return this;
7489 }
7490
7492 App *configurable(bool value = true) {
7493 configurable_ = value;
7494 return this;
7495 }
7496
7498 App *ignore_underscore(bool value = true);
7499
7501 App *formatter(std::shared_ptr<FormatterBase> fmt) {
7502 formatter_ = fmt;
7503 return this;
7504 }
7505
7507 App *formatter_fn(std::function<std::string(const App *, std::string, AppFormatMode)> fmt) {
7508 formatter_ = std::make_shared<FormatterLambda>(fmt);
7509 return this;
7510 }
7511
7513 App *config_formatter(std::shared_ptr<Config> fmt) {
7514 config_formatter_ = fmt;
7515 return this;
7516 }
7517
7519 CLI11_NODISCARD bool parsed() const { return parsed_ > 0; }
7520
7523
7527
7542 Option *add_option(std::string option_name,
7543 callback_t option_callback,
7544 std::string option_description = "",
7545 bool defaulted = false,
7546 std::function<std::string()> func = {});
7547
7549 template <typename AssignTo,
7550 typename ConvertTo = AssignTo,
7551 enable_if_t<!std::is_const<ConvertTo>::value, detail::enabler> = detail::dummy>
7552 Option *add_option(std::string option_name,
7553 AssignTo &variable,
7554 std::string option_description = "") {
7555
7556 auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
7557 return detail::lexical_conversion<AssignTo, ConvertTo>(res, variable);
7558 };
7559
7560 Option *opt = add_option(option_name, fun, option_description, false, [&variable]() {
7561 return CLI::detail::checked_to_string<AssignTo, ConvertTo>(variable);
7562 });
7563 opt->type_name(detail::type_name<ConvertTo>());
7564 // these must be actual lvalues since (std::max) sometimes is defined in terms of references and references
7565 // to structs used in the evaluation can be temporary so that would cause issues.
7566 auto Tcount = detail::type_count<AssignTo>::value;
7567 auto XCcount = detail::type_count<ConvertTo>::value;
7568 opt->type_size(detail::type_count_min<ConvertTo>::value, (std::max)(Tcount, XCcount));
7569 opt->expected(detail::expected_count<ConvertTo>::value);
7571 return opt;
7572 }
7573
7575 template <typename AssignTo, enable_if_t<!std::is_const<AssignTo>::value, detail::enabler> = detail::dummy>
7576 Option *add_option_no_stream(std::string option_name,
7577 AssignTo &variable,
7578 std::string option_description = "") {
7579
7580 auto fun = [&variable](const CLI::results_t &res) { // comment for spacing
7581 return detail::lexical_conversion<AssignTo, AssignTo>(res, variable);
7582 };
7583
7584 Option *opt = add_option(option_name, fun, option_description, false, []() { return std::string{}; });
7585 opt->type_name(detail::type_name<AssignTo>());
7586 opt->type_size(detail::type_count_min<AssignTo>::value, detail::type_count<AssignTo>::value);
7587 opt->expected(detail::expected_count<AssignTo>::value);
7589 return opt;
7590 }
7591
7593 template <typename ArgType>
7594 Option *add_option_function(std::string option_name,
7595 const std::function<void(const ArgType &)> &func,
7596 std::string option_description = "") {
7597
7598 auto fun = [func](const CLI::results_t &res) {
7599 ArgType variable;
7600 bool result = detail::lexical_conversion<ArgType, ArgType>(res, variable);
7601 if(result) {
7602 func(variable);
7603 }
7604 return result;
7605 };
7606
7607 Option *opt = add_option(option_name, std::move(fun), option_description, false);
7608 opt->type_name(detail::type_name<ArgType>());
7609 opt->type_size(detail::type_count_min<ArgType>::value, detail::type_count<ArgType>::value);
7610 opt->expected(detail::expected_count<ArgType>::value);
7611 return opt;
7612 }
7613
7615 Option *add_option(std::string option_name) {
7616 return add_option(option_name, CLI::callback_t{}, std::string{}, false);
7617 }
7618
7620 template <typename T,
7621 enable_if_t<std::is_const<T>::value && std::is_constructible<std::string, T>::value, detail::enabler> =
7622 detail::dummy>
7623 Option *add_option(std::string option_name, T &option_description) {
7624 return add_option(option_name, CLI::callback_t(), option_description, false);
7625 }
7626
7628 Option *set_help_flag(std::string flag_name = "", const std::string &help_description = "");
7629
7631 Option *set_help_all_flag(std::string help_name = "", const std::string &help_description = "");
7632
7634 Option *set_version_flag(std::string flag_name = "",
7635 const std::string &versionString = "",
7636 const std::string &version_help = "Display program version information and exit");
7637
7639 Option *set_version_flag(std::string flag_name,
7640 std::function<std::string()> vfunc,
7641 const std::string &version_help = "Display program version information and exit");
7642
7643 private:
7645 Option *_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description);
7646
7647 public:
7649 Option *add_flag(std::string flag_name) { return _add_flag_internal(flag_name, CLI::callback_t(), std::string{}); }
7650
7654 template <typename T,
7655 enable_if_t<(std::is_const<typename std::remove_reference<T>::type>::value ||
7656 std::is_rvalue_reference<T &&>::value) &&
7657 std::is_constructible<std::string, typename std::remove_reference<T>::type>::value,
7658 detail::enabler> = detail::dummy>
7659 Option *add_flag(std::string flag_name, T &&flag_description) {
7660 return _add_flag_internal(flag_name, CLI::callback_t(), std::forward<T>(flag_description));
7661 }
7662
7665 template <typename T,
7666 enable_if_t<!detail::is_mutable_container<T>::value && !std::is_const<T>::value &&
7667 !std::is_constructible<std::function<void(int)>, T>::value,
7668 detail::enabler> = detail::dummy>
7669 Option *add_flag(std::string flag_name,
7670 T &flag_result,
7671 std::string flag_description = "") {
7672
7673 CLI::callback_t fun = [&flag_result](const CLI::results_t &res) {
7674 using CLI::detail::lexical_cast;
7675 return lexical_cast(res[0], flag_result);
7676 };
7677 auto *opt = _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
7678 return detail::default_flag_modifiers<T>(opt);
7679 }
7680
7682 template <typename T,
7683 enable_if_t<!std::is_assignable<std::function<void(std::int64_t)> &, T>::value, detail::enabler> =
7684 detail::dummy>
7685 Option *add_flag(std::string flag_name,
7686 std::vector<T> &flag_results,
7687 std::string flag_description = "") {
7688 CLI::callback_t fun = [&flag_results](const CLI::results_t &res) {
7689 bool retval = true;
7690 for(const auto &elem : res) {
7691 using CLI::detail::lexical_cast;
7692 flag_results.emplace_back();
7693 retval &= lexical_cast(elem, flag_results.back());
7694 }
7695 return retval;
7696 };
7697 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
7698 ->multi_option_policy(MultiOptionPolicy::TakeAll)
7700 }
7701
7703 Option *add_flag_callback(std::string flag_name,
7704 std::function<void(void)> function,
7705 std::string flag_description = "");
7706
7708 Option *add_flag_function(std::string flag_name,
7709 std::function<void(std::int64_t)> function,
7710 std::string flag_description = "");
7711
7712#ifdef CLI11_CPP14
7714 Option *add_flag(std::string flag_name,
7715 std::function<void(std::int64_t)> function,
7716 std::string flag_description = "") {
7717 return add_flag_function(std::move(flag_name), std::move(function), std::move(flag_description));
7718 }
7719#endif
7720
7722 Option *set_config(std::string option_name = "",
7723 std::string default_filename = "",
7724 const std::string &help_message = "Read an ini file",
7725 bool config_required = false);
7726
7728 bool remove_option(Option *opt);
7729
7731 template <typename T = Option_group>
7732 T *add_option_group(std::string group_name, std::string group_description = "") {
7733 if(!detail::valid_alias_name_string(group_name)) {
7734 throw IncorrectConstruction("option group names may not contain newlines or null characters");
7735 }
7736 auto option_group = std::make_shared<T>(std::move(group_description), group_name, this);
7737 auto *ptr = option_group.get();
7738 // move to App_p for overload resolution on older gcc versions
7739 App_p app_ptr = std::static_pointer_cast<App>(option_group);
7740 // don't inherit the footer in option groups and clear the help flag by default
7741 app_ptr->footer_ = "";
7742 app_ptr->set_help_flag();
7743 add_subcommand(std::move(app_ptr));
7744 return ptr;
7745 }
7746
7750
7752 App *add_subcommand(std::string subcommand_name = "", std::string subcommand_description = "");
7753
7755 App *add_subcommand(CLI::App_p subcom);
7756
7758 bool remove_subcommand(App *subcom);
7759
7762 App *get_subcommand(const App *subcom) const;
7763
7765 CLI11_NODISCARD App *get_subcommand(std::string subcom) const;
7766
7769 CLI11_NODISCARD App *get_subcommand_no_throw(std::string subcom) const noexcept;
7770
7772 CLI11_NODISCARD App *get_subcommand(int index = 0) const;
7773
7775 CLI::App_p get_subcommand_ptr(App *subcom) const;
7776
7778 CLI11_NODISCARD CLI::App_p get_subcommand_ptr(std::string subcom) const;
7779
7781 CLI11_NODISCARD CLI::App_p get_subcommand_ptr(int index = 0) const;
7782
7784 CLI11_NODISCARD App *get_option_group(std::string group_name) const;
7785
7789 CLI11_NODISCARD std::size_t count() const { return parsed_; }
7790
7793 CLI11_NODISCARD std::size_t count_all() const;
7794
7796 App *group(std::string group_name) {
7797 group_ = group_name;
7798 return this;
7799 }
7800
7805 return this;
7806 }
7807
7812 if(value < 0) {
7814 require_subcommand_max_ = static_cast<std::size_t>(-value);
7815 } else {
7816 require_subcommand_min_ = static_cast<std::size_t>(value);
7817 require_subcommand_max_ = static_cast<std::size_t>(value);
7818 }
7819 return this;
7820 }
7821
7824 App *require_subcommand(std::size_t min, std::size_t max) {
7827 return this;
7828 }
7829
7834 return this;
7835 }
7836
7840 App *require_option(int value) {
7841 if(value < 0) {
7843 require_option_max_ = static_cast<std::size_t>(-value);
7844 } else {
7845 require_option_min_ = static_cast<std::size_t>(value);
7846 require_option_max_ = static_cast<std::size_t>(value);
7847 }
7848 return this;
7849 }
7850
7853 App *require_option(std::size_t min, std::size_t max) {
7854 require_option_min_ = min;
7855 require_option_max_ = max;
7856 return this;
7857 }
7858
7861 App *fallthrough(bool value = true) {
7862 fallthrough_ = value;
7863 return this;
7864 }
7865
7867 App *subcommand_fallthrough(bool value = true) {
7869 return this;
7870 }
7871
7874 explicit operator bool() const { return parsed_ > 0; }
7875
7879
7883 virtual void pre_callback() {}
7884
7888 //
7890 void clear();
7891
7894 void parse(int argc, const char *const *argv);
7895 void parse(int argc, const wchar_t *const *argv);
7896
7897 private:
7898 template <class CharT> void parse_char_t(int argc, const CharT *const *argv);
7899
7900 public:
7905 void parse(std::string commandline, bool program_name_included = false);
7906 void parse(std::wstring commandline, bool program_name_included = false);
7907
7910 void parse(std::vector<std::string> &args);
7911
7913 void parse(std::vector<std::string> &&args);
7914
7915 void parse_from_stream(std::istream &input);
7916
7918 void failure_message(std::function<std::string(const App *, const Error &e)> function) {
7919 failure_message_ = function;
7920 }
7921
7923 int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const;
7924
7928
7930 CLI11_NODISCARD std::size_t count(std::string option_name) const { return get_option(option_name)->count(); }
7931
7934 CLI11_NODISCARD std::vector<App *> get_subcommands() const { return parsed_subcommands_; }
7935
7938 std::vector<const App *> get_subcommands(const std::function<bool(const App *)> &filter) const;
7939
7942 std::vector<App *> get_subcommands(const std::function<bool(App *)> &filter);
7943
7945 bool got_subcommand(const App *subcom) const {
7946 // get subcom needed to verify that this was a real subcommand
7947 return get_subcommand(subcom)->parsed_ > 0;
7948 }
7949
7951 CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const noexcept {
7952 App *sub = get_subcommand_no_throw(subcommand_name);
7953 return (sub != nullptr) ? (sub->parsed_ > 0) : false;
7954 }
7955
7957 App *excludes(Option *opt) {
7958 if(opt == nullptr) {
7959 throw OptionNotFound("nullptr passed");
7960 }
7961 exclude_options_.insert(opt);
7962 return this;
7963 }
7964
7967 if(app == nullptr) {
7968 throw OptionNotFound("nullptr passed");
7969 }
7970 if(app == this) {
7971 throw OptionNotFound("cannot self reference in needs");
7972 }
7973 auto res = exclude_subcommands_.insert(app);
7974 // subcommand exclusion should be symmetric
7975 if(res.second) {
7976 app->exclude_subcommands_.insert(this);
7977 }
7978 return this;
7979 }
7980
7981 App *needs(Option *opt) {
7982 if(opt == nullptr) {
7983 throw OptionNotFound("nullptr passed");
7984 }
7985 need_options_.insert(opt);
7986 return this;
7987 }
7988
7989 App *needs(App *app) {
7990 if(app == nullptr) {
7991 throw OptionNotFound("nullptr passed");
7992 }
7993 if(app == this) {
7994 throw OptionNotFound("cannot self reference in needs");
7995 }
7996 need_subcommands_.insert(app);
7997 return this;
7998 }
7999
8001 bool remove_excludes(Option *opt);
8002
8004 bool remove_excludes(App *app);
8005
8007 bool remove_needs(Option *opt);
8008
8010 bool remove_needs(App *app);
8014
8016 App *usage(std::string usage_string) {
8017 usage_ = std::move(usage_string);
8018 return this;
8019 }
8020
8021 App *usage(std::function<std::string()> usage_function) {
8022 usage_callback_ = std::move(usage_function);
8023 return this;
8024 }
8025
8026 App *footer(std::string footer_string) {
8027 footer_ = std::move(footer_string);
8028 return this;
8029 }
8030
8031 App *footer(std::function<std::string()> footer_function) {
8032 footer_callback_ = std::move(footer_function);
8033 return this;
8034 }
8035
8037 CLI11_NODISCARD std::string config_to_str(bool default_also = false, bool write_description = false) const {
8038 return config_formatter_->to_config(this, default_also, write_description, "");
8039 }
8040
8043 CLI11_NODISCARD std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const;
8044
8046 CLI11_NODISCARD std::string version() const;
8050
8052 CLI11_NODISCARD std::shared_ptr<FormatterBase> get_formatter() const { return formatter_; }
8053
8055 CLI11_NODISCARD std::shared_ptr<Config> get_config_formatter() const { return config_formatter_; }
8056
8058 CLI11_NODISCARD std::shared_ptr<ConfigBase> get_config_formatter_base() const {
8059 // This is safer as a dynamic_cast if we have RTTI, as Config -> ConfigBase
8060#if CLI11_USE_STATIC_RTTI == 0
8061 return std::dynamic_pointer_cast<ConfigBase>(config_formatter_);
8062#else
8063 return std::static_pointer_cast<ConfigBase>(config_formatter_);
8064#endif
8065 }
8066
8068 CLI11_NODISCARD std::string get_description() const { return description_; }
8069
8071 App *description(std::string app_description) {
8072 description_ = std::move(app_description);
8073 return this;
8074 }
8075
8077 std::vector<const Option *> get_options(const std::function<bool(const Option *)> filter = {}) const;
8078
8080 std::vector<Option *> get_options(const std::function<bool(Option *)> filter = {});
8081
8083 CLI11_NODISCARD Option *get_option_no_throw(std::string option_name) noexcept;
8084
8086 CLI11_NODISCARD const Option *get_option_no_throw(std::string option_name) const noexcept;
8087
8089 CLI11_NODISCARD const Option *get_option(std::string option_name) const {
8090 const auto *opt = get_option_no_throw(option_name);
8091 if(opt == nullptr) {
8092 throw OptionNotFound(option_name);
8093 }
8094 return opt;
8095 }
8096
8098 CLI11_NODISCARD Option *get_option(std::string option_name) {
8099 auto *opt = get_option_no_throw(option_name);
8100 if(opt == nullptr) {
8101 throw OptionNotFound(option_name);
8102 }
8103 return opt;
8104 }
8105
8107 const Option *operator[](const std::string &option_name) const { return get_option(option_name); }
8108
8110 const Option *operator[](const char *option_name) const { return get_option(option_name); }
8111
8113 CLI11_NODISCARD bool get_ignore_case() const { return ignore_case_; }
8114
8116 CLI11_NODISCARD bool get_ignore_underscore() const { return ignore_underscore_; }
8117
8119 CLI11_NODISCARD bool get_fallthrough() const { return fallthrough_; }
8120
8122 CLI11_NODISCARD bool get_subcommand_fallthrough() const { return subcommand_fallthrough_; }
8123
8125 CLI11_NODISCARD bool get_allow_windows_style_options() const { return allow_windows_style_options_; }
8126
8128 CLI11_NODISCARD bool get_positionals_at_end() const { return positionals_at_end_; }
8129
8131 CLI11_NODISCARD bool get_configurable() const { return configurable_; }
8132
8134 CLI11_NODISCARD const std::string &get_group() const { return group_; }
8135
8137 CLI11_NODISCARD std::string get_usage() const {
8138 return (usage_callback_) ? usage_callback_() + '\n' + usage_ : usage_;
8139 }
8140
8142 CLI11_NODISCARD std::string get_footer() const {
8143 return (footer_callback_) ? footer_callback_() + '\n' + footer_ : footer_;
8144 }
8145
8147 CLI11_NODISCARD std::size_t get_require_subcommand_min() const { return require_subcommand_min_; }
8148
8150 CLI11_NODISCARD std::size_t get_require_subcommand_max() const { return require_subcommand_max_; }
8151
8153 CLI11_NODISCARD std::size_t get_require_option_min() const { return require_option_min_; }
8154
8156 CLI11_NODISCARD std::size_t get_require_option_max() const { return require_option_max_; }
8157
8159 CLI11_NODISCARD bool get_prefix_command() const { return static_cast<bool>(prefix_command_); }
8160
8162 CLI11_NODISCARD PrefixCommandMode get_prefix_command_mode() const { return prefix_command_; }
8163
8165 CLI11_NODISCARD bool get_allow_extras() const { return allow_extras_ > ExtrasMode::Ignore; }
8166
8168 CLI11_NODISCARD ExtrasMode get_allow_extras_mode() const { return allow_extras_; }
8169
8171 CLI11_NODISCARD bool get_required() const { return required_; }
8172
8174 CLI11_NODISCARD bool get_disabled() const { return disabled_; }
8175
8177 CLI11_NODISCARD bool get_silent() const { return silent_; }
8178
8181
8183 CLI11_NODISCARD bool get_allow_subcommand_prefix_matching() const { return allow_prefix_matching_; }
8184
8186 CLI11_NODISCARD bool get_immediate_callback() const { return immediate_callback_; }
8187
8189 CLI11_NODISCARD bool get_disabled_by_default() const { return (default_startup == startup_mode::disabled); }
8190
8192 CLI11_NODISCARD bool get_enabled_by_default() const { return (default_startup == startup_mode::enabled); }
8194 CLI11_NODISCARD bool get_validate_positionals() const { return validate_positionals_; }
8196 CLI11_NODISCARD bool get_validate_optional_arguments() const { return validate_optional_arguments_; }
8197
8199 CLI11_NODISCARD config_extras_mode get_allow_config_extras() const {
8200 return static_cast<config_extras_mode>(allow_config_extras_);
8201 }
8202
8204 Option *get_help_ptr() { return help_ptr_; }
8205
8207 CLI11_NODISCARD const Option *get_help_ptr() const { return help_ptr_; }
8208
8210 CLI11_NODISCARD const Option *get_help_all_ptr() const { return help_all_ptr_; }
8211
8213 Option *get_config_ptr() { return config_ptr_; }
8214
8216 CLI11_NODISCARD const Option *get_config_ptr() const { return config_ptr_; }
8217
8219 Option *get_version_ptr() { return version_ptr_; }
8220
8222 CLI11_NODISCARD const Option *get_version_ptr() const { return version_ptr_; }
8223
8225 App *get_parent() { return parent_; }
8226
8228 CLI11_NODISCARD const App *get_parent() const { return parent_; }
8229
8231 CLI11_NODISCARD const std::string &get_name() const { return name_; }
8232
8234 CLI11_NODISCARD const std::vector<std::string> &get_aliases() const { return aliases_; }
8235
8238 aliases_.clear();
8239 return this;
8240 }
8241
8243 CLI11_NODISCARD std::string get_display_name(bool with_aliases = false) const;
8244
8247 CLI11_NODISCARD bool check_name(std::string name_to_check) const;
8248
8250 enum class NameMatch : std::uint8_t { none = 0, exact = 1, prefix = 2 };
8251
8255 CLI11_NODISCARD NameMatch check_name_detail(std::string name_to_check) const;
8256
8258 CLI11_NODISCARD std::vector<std::string> get_groups() const;
8259
8261 CLI11_NODISCARD const std::vector<Option *> &parse_order() const { return parse_order_; }
8262
8264 CLI11_NODISCARD std::vector<std::string> remaining(bool recurse = false) const;
8265
8267 CLI11_NODISCARD std::vector<std::string> remaining_for_passthrough(bool recurse = false) const;
8268
8270 CLI11_NODISCARD std::size_t remaining_size(bool recurse = false) const;
8271
8273
8274 protected:
8279 void _validate() const;
8280
8284 void _configure();
8285
8287 void run_callback(bool final_mode = false, bool suppress_final_callback = false);
8288
8290 CLI11_NODISCARD bool _valid_subcommand(const std::string &current, bool ignore_used = true) const;
8291
8293 CLI11_NODISCARD detail::Classifier _recognize(const std::string &current,
8294 bool ignore_used_subcommands = true) const;
8295
8296 // The parse function is now broken into several parts, and part of process
8297
8299 void _process_config_file();
8300
8302 bool _process_config_file(const std::string &config_file, bool throw_error);
8303
8305 void _process_env();
8306
8308 void _process_callbacks(CallbackPriority priority);
8309
8313 void _process_help_flags(CallbackPriority priority, bool trigger_help = false, bool trigger_all_help = false) const;
8314
8316 void _process_requirements();
8317
8319 void _process();
8320
8322 void _process_extras();
8323
8325 void increment_parsed();
8326
8328 void _parse(std::vector<std::string> &args);
8329
8331 void _parse(std::vector<std::string> &&args);
8332
8334 void _parse_stream(std::istream &input);
8335
8340 void _parse_config(const std::vector<ConfigItem> &args);
8341
8343 bool _parse_single_config(const ConfigItem &item, std::size_t level = 0);
8344
8346 bool _add_flag_like_result(Option *op, const ConfigItem &item, const std::vector<std::string> &inputs);
8347
8350 bool _parse_single(std::vector<std::string> &args, bool &positional_only);
8351
8353 CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only = false) const;
8354
8356 CLI11_NODISCARD bool _has_remaining_positionals() const;
8357
8361 bool _parse_positional(std::vector<std::string> &args, bool haltOnSubcommand);
8362
8365 CLI11_NODISCARD App *
8366 _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept;
8367
8372 bool _parse_subcommand(std::vector<std::string> &args);
8373
8377 bool _parse_arg(std::vector<std::string> &args, detail::Classifier current_type, bool local_processing_only);
8378
8380 void _trigger_pre_parse(std::size_t remaining_args);
8381
8383 CLI11_NODISCARD App *_get_fallthrough_parent() noexcept;
8384
8386 CLI11_NODISCARD const App *_get_fallthrough_parent() const noexcept;
8387
8389 CLI11_NODISCARD const std::string &_compare_subcommand_names(const App &subcom, const App &base) const;
8390
8392 void _move_to_missing(detail::Classifier val_type, const std::string &val);
8393
8394 public:
8396 void _move_option(Option *opt, App *app);
8397}; // namespace CLI
8398
8400class Option_group : public App {
8401 public:
8402 Option_group(std::string group_description, std::string group_name, App *parent)
8403 : App(std::move(group_description), "", parent) {
8404 group(group_name);
8405 // option groups should have automatic fallthrough
8406 if(group_name.empty() || group_name.front() == '+') {
8407 // help will not be used by default in these contexts
8408 set_help_flag("");
8410 }
8411 }
8412 using App::add_option;
8414 Option *add_option(Option *opt) {
8415 if(get_parent() == nullptr) {
8416 throw OptionNotFound("Unable to locate the specified option");
8417 }
8418 get_parent()->_move_option(opt, this);
8419 return opt;
8420 }
8421
8422 void add_options(Option *opt) { add_option(opt); }
8424 template <typename... Args> void add_options(Option *opt, Args... args) {
8425 add_option(opt);
8426 add_options(args...);
8427 }
8428 using App::add_subcommand;
8431 App_p subc = subcom->get_parent()->get_subcommand_ptr(subcom);
8432 subc->get_parent()->remove_subcommand(subcom);
8433 add_subcommand(std::move(subc));
8434 return subcom;
8435 }
8436};
8437
8439CLI11_INLINE void TriggerOn(App *trigger_app, App *app_to_enable);
8440
8442CLI11_INLINE void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable);
8443
8445CLI11_INLINE void TriggerOff(App *trigger_app, App *app_to_enable);
8446
8448CLI11_INLINE void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable);
8449
8451CLI11_INLINE void deprecate_option(Option *opt, const std::string &replacement = "");
8452
8454inline void deprecate_option(App *app, const std::string &option_name, const std::string &replacement = "") {
8455 auto *opt = app->get_option(option_name);
8456 deprecate_option(opt, replacement);
8457}
8458
8460inline void deprecate_option(App &app, const std::string &option_name, const std::string &replacement = "") {
8461 auto *opt = app.get_option(option_name);
8462 deprecate_option(opt, replacement);
8463}
8464
8466CLI11_INLINE void retire_option(App *app, Option *opt);
8467
8469CLI11_INLINE void retire_option(App &app, Option *opt);
8470
8472CLI11_INLINE void retire_option(App *app, const std::string &option_name);
8473
8475CLI11_INLINE void retire_option(App &app, const std::string &option_name);
8476
8477namespace detail {
8480#ifdef CLI11_CPP14
8481
8483 template <typename... Args> static decltype(auto) parse_arg(App *app, Args &&...args) {
8484 return app->_parse_arg(std::forward<Args>(args)...);
8485 }
8486
8488 template <typename... Args> static decltype(auto) parse_subcommand(App *app, Args &&...args) {
8489 return app->_parse_subcommand(std::forward<Args>(args)...);
8490 }
8491#else
8493 template <typename... Args>
8494 static auto parse_arg(App *app, Args &&...args) ->
8495 typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
8496 return app->_parse_arg(std::forward<Args>(args)...);
8497 }
8498
8500 template <typename... Args>
8501 static auto parse_subcommand(App *app, Args &&...args) ->
8502 typename std::result_of<decltype (&App::_parse_subcommand)(App, Args...)>::type {
8503 return app->_parse_subcommand(std::forward<Args>(args)...);
8504 }
8505#endif
8508
8510 static const App *get_fallthrough_parent(const App *app) { return app->_get_fallthrough_parent(); }
8511};
8512} // namespace detail
8513
8514
8515
8516
8517CLI11_INLINE App::App(std::string app_description, std::string app_name, App *parent)
8518 : name_(std::move(app_name)), description_(std::move(app_description)), parent_(parent) {
8519 // Inherit if not from a nullptr
8520 if(parent_ != nullptr) {
8521 if(parent_->help_ptr_ != nullptr)
8522 set_help_flag(parent_->help_ptr_->get_name(false, true), parent_->help_ptr_->get_description());
8523 if(parent_->help_all_ptr_ != nullptr)
8524 set_help_all_flag(parent_->help_all_ptr_->get_name(false, true), parent_->help_all_ptr_->get_description());
8525
8527 option_defaults_ = parent_->option_defaults_;
8528
8529 // INHERITABLE
8530 failure_message_ = parent_->failure_message_;
8531 allow_extras_ = parent_->allow_extras_;
8532 allow_config_extras_ = parent_->allow_config_extras_;
8533 prefix_command_ = parent_->prefix_command_;
8534 immediate_callback_ = parent_->immediate_callback_;
8535 ignore_case_ = parent_->ignore_case_;
8536 ignore_underscore_ = parent_->ignore_underscore_;
8537 fallthrough_ = parent_->fallthrough_;
8538 validate_positionals_ = parent_->validate_positionals_;
8539 validate_optional_arguments_ = parent_->validate_optional_arguments_;
8540 configurable_ = parent_->configurable_;
8541 allow_windows_style_options_ = parent_->allow_windows_style_options_;
8542 group_ = parent_->group_;
8543 usage_ = parent_->usage_;
8544 footer_ = parent_->footer_;
8545 formatter_ = parent_->formatter_;
8546 config_formatter_ = parent_->config_formatter_;
8547 require_subcommand_max_ = parent_->require_subcommand_max_;
8548 allow_prefix_matching_ = parent_->allow_prefix_matching_;
8549 }
8550}
8551
8552CLI11_NODISCARD CLI11_INLINE char **App::ensure_utf8(char **argv) {
8553#ifdef _WIN32
8554 (void)argv;
8555
8556 normalized_argv_ = detail::compute_win32_argv();
8557
8558 if(!normalized_argv_view_.empty()) {
8559 normalized_argv_view_.clear();
8560 }
8561
8562 normalized_argv_view_.reserve(normalized_argv_.size());
8563 for(auto &arg : normalized_argv_) {
8564 // using const_cast is well-defined, string is known to not be const.
8565 normalized_argv_view_.push_back(const_cast<char *>(arg.data()));
8566 }
8567
8568 return normalized_argv_view_.data();
8569#else
8570 return argv;
8571#endif
8572}
8573
8574CLI11_INLINE App *App::name(std::string app_name) {
8575
8576 if(parent_ != nullptr) {
8577 std::string oname = name_;
8578 name_ = app_name;
8579 const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
8580 if(!res.empty()) {
8581 name_ = oname;
8582 throw(OptionAlreadyAdded(app_name + " conflicts with existing subcommand names"));
8583 }
8584 } else {
8585 name_ = app_name;
8586 }
8587 has_automatic_name_ = false;
8588 return this;
8589}
8590
8591CLI11_INLINE App *App::alias(std::string app_name) {
8592 if(app_name.empty() || !detail::valid_alias_name_string(app_name)) {
8593 throw IncorrectConstruction("Aliases may not be empty or contain newlines or null characters");
8594 }
8595 if(parent_ != nullptr) {
8596 aliases_.push_back(app_name);
8597 const auto &res = _compare_subcommand_names(*this, *_get_fallthrough_parent());
8598 if(!res.empty()) {
8599 aliases_.pop_back();
8600 throw(OptionAlreadyAdded("alias already matches an existing subcommand: " + app_name));
8601 }
8602 } else {
8603 aliases_.push_back(app_name);
8604 }
8605
8606 return this;
8607}
8608
8609CLI11_INLINE App *App::immediate_callback(bool immediate) {
8610 immediate_callback_ = immediate;
8614 }
8615 } else if(!(final_callback_) && parse_complete_callback_) {
8617 }
8618 return this;
8619}
8620
8621CLI11_INLINE App *App::ignore_case(bool value) {
8622 if(value && !ignore_case_) {
8623 ignore_case_ = true;
8624 auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
8625 const auto &match = _compare_subcommand_names(*this, *p);
8626 if(!match.empty()) {
8627 ignore_case_ = false; // we are throwing so need to be exception invariant
8628 throw OptionAlreadyAdded("ignore case would cause subcommand name conflicts: " + match);
8629 }
8630 }
8631 ignore_case_ = value;
8632 return this;
8633}
8634
8635CLI11_INLINE App *App::ignore_underscore(bool value) {
8636 if(value && !ignore_underscore_) {
8637 ignore_underscore_ = true;
8638 auto *p = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
8639 const auto &match = _compare_subcommand_names(*this, *p);
8640 if(!match.empty()) {
8641 ignore_underscore_ = false;
8642 throw OptionAlreadyAdded("ignore underscore would cause subcommand name conflicts: " + match);
8643 }
8644 }
8645 ignore_underscore_ = value;
8646 return this;
8647}
8648
8649CLI11_INLINE Option *App::add_option(std::string option_name,
8650 callback_t option_callback,
8651 std::string option_description,
8652 bool defaulted,
8653 std::function<std::string()> func) {
8654 Option myopt{option_name, option_description, option_callback, this, allow_non_standard_options_};
8655
8656 // do a quick search in current subcommand for options
8657 auto res =
8658 std::find_if(std::begin(options_), std::end(options_), [&myopt](const Option_p &v) { return *v == myopt; });
8659 if(res != options_.end()) {
8660 const auto &matchname = (*res)->matching_name(myopt);
8661 throw(OptionAlreadyAdded("added option matched existing option name: " + matchname));
8662 }
8664 const App *top_level_parent = this;
8665 while(top_level_parent->name_.empty() && top_level_parent->parent_ != nullptr) {
8666 top_level_parent = top_level_parent->parent_;
8667 }
8668
8669 if(myopt.lnames_.empty() && myopt.snames_.empty()) {
8670 // if the option is positional only there is additional potential for ambiguities in config files and needs
8671 // to be checked
8672 std::string test_name = "--" + myopt.get_single_name();
8673 if(test_name.size() == 3) {
8674 test_name.erase(0, 1);
8675 }
8676 // if we are in option group
8677 const auto *op = top_level_parent->get_option_no_throw(test_name);
8678 if(op != nullptr && op->get_configurable()) {
8679 throw(OptionAlreadyAdded("added option positional name matches existing option: " + test_name));
8680 }
8681 // need to check if there is another positional with the same name that also doesn't have any long or
8682 // short names
8683 op = top_level_parent->get_option_no_throw(myopt.get_single_name());
8684 if(op != nullptr && op->lnames_.empty() && op->snames_.empty()) {
8685 throw(OptionAlreadyAdded("unable to disambiguate with existing option: " + test_name));
8686 }
8687 } else if(top_level_parent != this) {
8688 for(auto &ln : myopt.lnames_) {
8689 const auto *op = top_level_parent->get_option_no_throw(ln);
8690 if(op != nullptr && op->get_configurable()) {
8691 throw(OptionAlreadyAdded("added option matches existing positional option: " + ln));
8692 }
8693 op = top_level_parent->get_option_no_throw("--" + ln);
8694 if(op != nullptr && op->get_configurable()) {
8695 throw(OptionAlreadyAdded("added option matches existing option: --" + ln));
8696 }
8697 if(ln.size() == 1 || top_level_parent->get_allow_non_standard_option_names()) {
8698 op = top_level_parent->get_option_no_throw("-" + ln);
8699 if(op != nullptr && op->get_configurable()) {
8700 throw(OptionAlreadyAdded("added option matches existing option: -" + ln));
8701 }
8702 }
8703 }
8704 for(auto &sn : myopt.snames_) {
8705 const auto *op = top_level_parent->get_option_no_throw(sn);
8706 if(op != nullptr && op->get_configurable()) {
8707 throw(OptionAlreadyAdded("added option matches existing positional option: " + sn));
8708 }
8709 op = top_level_parent->get_option_no_throw("-" + sn);
8710 if(op != nullptr && op->get_configurable()) {
8711 throw(OptionAlreadyAdded("added option matches existing option: -" + sn));
8712 }
8713 op = top_level_parent->get_option_no_throw("--" + sn);
8714 if(op != nullptr && op->get_configurable()) {
8715 throw(OptionAlreadyAdded("added option matches existing option: --" + sn));
8716 }
8717 }
8718 }
8719 if(allow_non_standard_options_ && !myopt.snames_.empty()) {
8720
8721 for(auto &sname : myopt.snames_) {
8722 if(sname.length() > 1) {
8723 std::string test_name;
8724 test_name.push_back('-');
8725 test_name.push_back(sname.front());
8726 const auto *op = top_level_parent->get_option_no_throw(test_name);
8727 if(op != nullptr) {
8728 throw(OptionAlreadyAdded("added option interferes with existing short option: " + sname));
8729 }
8730 }
8731 }
8732 for(auto &opt : top_level_parent->get_options()) {
8733 for(const auto &osn : opt->snames_) {
8734 if(osn.size() > 1) {
8735 std::string test_name;
8736 test_name.push_back(osn.front());
8737 if(myopt.check_sname(test_name)) {
8738 throw(OptionAlreadyAdded("added option interferes with existing non standard option: " + osn));
8739 }
8740 }
8741 }
8742 }
8743 }
8744 options_.emplace_back();
8745 Option_p &option = options_.back();
8746 option.reset(new Option(option_name, option_description, option_callback, this, allow_non_standard_options_));
8747
8748 // Set the default string capture function
8749 option->default_function(func);
8750
8751 // For compatibility with CLI11 1.7 and before, capture the default string here
8752 if(defaulted)
8753 option->capture_default_str();
8754
8755 // Transfer defaults to the new option
8756 option_defaults_.copy_to(option.get());
8757
8758 // Don't bother to capture if we already did
8759 if(!defaulted && option->get_always_capture_default())
8760 option->capture_default_str();
8761
8762 return option.get();
8763}
8764
8765CLI11_INLINE Option *App::set_help_flag(std::string flag_name, const std::string &help_description) {
8766 // take flag_description by const reference otherwise add_flag tries to assign to help_description
8767 if(help_ptr_ != nullptr) {
8769 help_ptr_ = nullptr;
8770 }
8771
8772 // Empty name will simply remove the help flag
8773 if(!flag_name.empty()) {
8774 help_ptr_ = add_flag(flag_name, help_description);
8775 help_ptr_->configurable(false)->callback_priority(CallbackPriority::First);
8776 }
8777
8778 return help_ptr_;
8779}
8780
8781CLI11_INLINE Option *App::set_help_all_flag(std::string help_name, const std::string &help_description) {
8782 // take flag_description by const reference otherwise add_flag tries to assign to flag_description
8783 if(help_all_ptr_ != nullptr) {
8785 help_all_ptr_ = nullptr;
8786 }
8787
8788 // Empty name will simply remove the help all flag
8789 if(!help_name.empty()) {
8790 help_all_ptr_ = add_flag(help_name, help_description);
8791 help_all_ptr_->configurable(false)->callback_priority(CallbackPriority::First);
8792 }
8793
8794 return help_all_ptr_;
8795}
8796
8797CLI11_INLINE Option *
8798App::set_version_flag(std::string flag_name, const std::string &versionString, const std::string &version_help) {
8799 // take flag_description by const reference otherwise add_flag tries to assign to version_description
8800 if(version_ptr_ != nullptr) {
8802 version_ptr_ = nullptr;
8803 }
8804
8805 // Empty name will simply remove the version flag
8806 if(!flag_name.empty()) {
8808 flag_name, [versionString]() { throw(CLI::CallForVersion(versionString, 0)); }, version_help);
8809 version_ptr_->configurable(false)->callback_priority(CallbackPriority::First);
8810 }
8811
8812 return version_ptr_;
8813}
8814
8815CLI11_INLINE Option *
8816App::set_version_flag(std::string flag_name, std::function<std::string()> vfunc, const std::string &version_help) {
8817 if(version_ptr_ != nullptr) {
8819 version_ptr_ = nullptr;
8820 }
8821
8822 // Empty name will simply remove the version flag
8823 if(!flag_name.empty()) {
8824 version_ptr_ =
8825 add_flag_callback(flag_name, [vfunc]() { throw(CLI::CallForVersion(vfunc(), 0)); }, version_help);
8826 version_ptr_->configurable(false)->callback_priority(CallbackPriority::First);
8827 }
8828
8829 return version_ptr_;
8830}
8831
8832CLI11_INLINE Option *App::_add_flag_internal(std::string flag_name, CLI::callback_t fun, std::string flag_description) {
8833 Option *opt = nullptr;
8834 if(detail::has_default_flag_values(flag_name)) {
8835 // check for default values and if it has them
8836 auto flag_defaults = detail::get_default_flag_values(flag_name);
8837 detail::remove_default_flag_values(flag_name);
8838 opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
8839 for(const auto &fname : flag_defaults)
8840 opt->fnames_.push_back(fname.first);
8841 opt->default_flag_values_ = std::move(flag_defaults);
8842 } else {
8843 opt = add_option(std::move(flag_name), std::move(fun), std::move(flag_description), false);
8844 }
8845 // flags cannot have positional values
8846 if(opt->get_positional()) {
8847 auto pos_name = opt->get_name(true);
8848 remove_option(opt);
8849 throw IncorrectConstruction::PositionalFlag(pos_name);
8850 }
8851 opt->multi_option_policy(MultiOptionPolicy::TakeLast);
8852 opt->expected(0);
8853 opt->required(false);
8854 return opt;
8855}
8856
8857CLI11_INLINE Option *App::add_flag_callback(std::string flag_name,
8858 std::function<void(void)> function,
8859 std::string flag_description) {
8860
8861 CLI::callback_t fun = [function](const CLI::results_t &res) {
8862 using CLI::detail::lexical_cast;
8863 bool trigger{false};
8864 auto result = lexical_cast(res[0], trigger);
8865 if(result && trigger) {
8866 function();
8867 }
8868 return result;
8869 };
8870 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description));
8871}
8872
8873CLI11_INLINE Option *
8874App::add_flag_function(std::string flag_name,
8875 std::function<void(std::int64_t)> function,
8876 std::string flag_description) {
8877
8878 CLI::callback_t fun = [function](const CLI::results_t &res) {
8879 using CLI::detail::lexical_cast;
8880 std::int64_t flag_count{0};
8881 lexical_cast(res[0], flag_count);
8882 function(flag_count);
8883 return true;
8884 };
8885 return _add_flag_internal(flag_name, std::move(fun), std::move(flag_description))
8886 ->multi_option_policy(MultiOptionPolicy::Sum);
8887}
8888
8889CLI11_INLINE Option *App::set_config(std::string option_name,
8890 std::string default_filename,
8891 const std::string &help_message,
8892 bool config_required) {
8893
8894 // Remove existing config if present
8895 if(config_ptr_ != nullptr) {
8897 config_ptr_ = nullptr; // need to remove the config_ptr completely
8898 }
8899
8900 // Only add config if option passed
8901 if(!option_name.empty()) {
8902 config_ptr_ = add_option(option_name, help_message);
8903 if(config_required) {
8904 config_ptr_->required();
8905 }
8906 if(!default_filename.empty()) {
8907 config_ptr_->default_str(std::move(default_filename));
8908 config_ptr_->force_callback_ = true;
8909 }
8910 config_ptr_->configurable(false);
8911 // set the option to take the last value and reverse given by default
8912 config_ptr_->multi_option_policy(MultiOptionPolicy::Reverse);
8913 }
8914
8915 return config_ptr_;
8916}
8917
8918CLI11_INLINE bool App::remove_option(Option *opt) {
8919 // Make sure no links exist
8920 for(Option_p &op : options_) {
8921 op->remove_needs(opt);
8922 op->remove_excludes(opt);
8923 }
8924
8925 if(help_ptr_ == opt)
8926 help_ptr_ = nullptr;
8927 if(help_all_ptr_ == opt)
8928 help_all_ptr_ = nullptr;
8929 if(config_ptr_ == opt)
8930 config_ptr_ = nullptr;
8931
8932 auto iterator =
8933 std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
8934 if(iterator != std::end(options_)) {
8935 options_.erase(iterator);
8936 return true;
8937 }
8938 return false;
8939}
8940
8941CLI11_INLINE App *App::add_subcommand(std::string subcommand_name, std::string subcommand_description) {
8942 if(!subcommand_name.empty() && !detail::valid_name_string(subcommand_name)) {
8943 if(!detail::valid_first_char(subcommand_name[0])) {
8945 "Subcommand name starts with invalid character, '!' and '-' and control characters");
8946 }
8947 for(auto c : subcommand_name) {
8948 if(!detail::valid_later_char(c)) {
8949 throw IncorrectConstruction(std::string("Subcommand name contains invalid character ('") + c +
8950 "'), all characters are allowed except"
8951 "'=',':','{','}', ' ', and control characters");
8952 }
8953 }
8954 }
8955 CLI::App_p subcom = std::shared_ptr<App>(new App(std::move(subcommand_description), subcommand_name, this));
8956 return add_subcommand(std::move(subcom));
8957}
8958
8959CLI11_INLINE App *App::add_subcommand(CLI::App_p subcom) {
8960 if(!subcom)
8961 throw IncorrectConstruction("passed App is not valid");
8962 auto *ckapp = (name_.empty() && parent_ != nullptr) ? _get_fallthrough_parent() : this;
8963 const auto &mstrg = _compare_subcommand_names(*subcom, *ckapp);
8964 if(!mstrg.empty()) {
8965 throw(OptionAlreadyAdded("subcommand name or alias matches existing subcommand: " + mstrg));
8966 }
8967 subcom->parent_ = this;
8968 subcommands_.push_back(std::move(subcom));
8969 return subcommands_.back().get();
8970}
8971
8972CLI11_INLINE bool App::remove_subcommand(App *subcom) {
8973 // Make sure no links exist
8974 for(App_p &sub : subcommands_) {
8975 sub->remove_excludes(subcom);
8976 sub->remove_needs(subcom);
8977 }
8978
8979 auto iterator = std::find_if(
8980 std::begin(subcommands_), std::end(subcommands_), [subcom](const App_p &v) { return v.get() == subcom; });
8981 if(iterator != std::end(subcommands_)) {
8982 subcommands_.erase(iterator);
8983 return true;
8984 }
8985 return false;
8986}
8987
8988CLI11_INLINE App *App::get_subcommand(const App *subcom) const {
8989 if(subcom == nullptr)
8990 throw OptionNotFound("nullptr passed");
8991 for(const App_p &subcomptr : subcommands_)
8992 if(subcomptr.get() == subcom)
8993 return subcomptr.get();
8994 throw OptionNotFound(subcom->get_name());
8995}
8996
8997CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(std::string subcom) const {
8998 auto *subc = _find_subcommand(subcom, false, false);
8999 if(subc == nullptr)
9000 throw OptionNotFound(subcom);
9001 return subc;
9002}
9003
9004CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand_no_throw(std::string subcom) const noexcept {
9005 return _find_subcommand(subcom, false, false);
9006}
9007
9008CLI11_NODISCARD CLI11_INLINE App *App::get_subcommand(int index) const {
9009 if(index >= 0) {
9010 auto uindex = static_cast<unsigned>(index);
9011 if(uindex < subcommands_.size())
9012 return subcommands_[uindex].get();
9013 }
9014 throw OptionNotFound(std::to_string(index));
9015}
9016
9017CLI11_INLINE CLI::App_p App::get_subcommand_ptr(App *subcom) const {
9018 if(subcom == nullptr)
9019 throw OptionNotFound("nullptr passed");
9020 for(const App_p &subcomptr : subcommands_)
9021 if(subcomptr.get() == subcom)
9022 return subcomptr;
9023 throw OptionNotFound(subcom->get_name());
9024}
9025
9026CLI11_NODISCARD CLI11_INLINE CLI::App_p App::get_subcommand_ptr(std::string subcom) const {
9027 for(const App_p &subcomptr : subcommands_)
9028 if(subcomptr->check_name(subcom))
9029 return subcomptr;
9030 throw OptionNotFound(subcom);
9031}
9032
9033CLI11_NODISCARD CLI11_INLINE CLI::App_p App::get_subcommand_ptr(int index) const {
9034 if(index >= 0) {
9035 auto uindex = static_cast<unsigned>(index);
9036 if(uindex < subcommands_.size())
9037 return subcommands_[uindex];
9038 }
9039 throw OptionNotFound(std::to_string(index));
9040}
9041
9042CLI11_NODISCARD CLI11_INLINE CLI::App *App::get_option_group(std::string group_name) const {
9043 for(const App_p &app : subcommands_) {
9044 if(app->name_.empty() && app->group_ == group_name) {
9045 return app.get();
9046 }
9047 }
9048 throw OptionNotFound(group_name);
9049}
9050
9051CLI11_NODISCARD CLI11_INLINE std::size_t App::count_all() const {
9052 std::size_t cnt{0};
9053 for(const auto &opt : options_) {
9054 cnt += opt->count();
9055 }
9056 for(const auto &sub : subcommands_) {
9057 cnt += sub->count_all();
9058 }
9059 if(!get_name().empty()) { // for named subcommands add the number of times the subcommand was called
9060 cnt += parsed_;
9061 }
9062 return cnt;
9063}
9064
9065CLI11_INLINE void App::clear() {
9066
9067 parsed_ = 0;
9068 pre_parse_called_ = false;
9069
9070 missing_.clear();
9071 parsed_subcommands_.clear();
9072 parse_order_.clear();
9073 for(const Option_p &opt : options_) {
9074 opt->clear();
9075 }
9076 for(const App_p &subc : subcommands_) {
9077 subc->clear();
9078 }
9079}
9080
9081CLI11_INLINE void App::parse(int argc, const char *const *argv) { parse_char_t(argc, argv); }
9082CLI11_INLINE void App::parse(int argc, const wchar_t *const *argv) { parse_char_t(argc, argv); }
9083
9084namespace detail {
9085
9086// Do nothing or perform narrowing
9087CLI11_INLINE const char *maybe_narrow(const char *str) { return str; }
9088CLI11_INLINE std::string maybe_narrow(const wchar_t *str) { return narrow(str); }
9089
9090} // namespace detail
9091
9092template <class CharT> CLI11_INLINE void App::parse_char_t(int argc, const CharT *const *argv) {
9093 // If the name is not set, read from command line
9094 if(name_.empty() || has_automatic_name_) {
9095 has_automatic_name_ = true;
9096 name_ = detail::maybe_narrow(argv[0]);
9097 }
9098
9099 std::vector<std::string> args;
9100 args.reserve(static_cast<std::size_t>(argc) - 1U);
9101 for(auto i = static_cast<std::size_t>(argc) - 1U; i > 0U; --i)
9102 args.emplace_back(detail::maybe_narrow(argv[i]));
9103
9104 parse(std::move(args));
9105}
9106
9107CLI11_INLINE void App::parse(std::string commandline, bool program_name_included) {
9108
9109 if(program_name_included) {
9110 auto nstr = detail::split_program_name(commandline);
9111 if((name_.empty()) || (has_automatic_name_)) {
9112 has_automatic_name_ = true;
9113 name_ = nstr.first;
9114 }
9115 commandline = std::move(nstr.second);
9116 } else {
9117 detail::trim(commandline);
9118 }
9119 // the next section of code is to deal with quoted arguments after an '=' or ':' for windows like operations
9120 if(!commandline.empty()) {
9121 commandline = detail::find_and_modify(commandline, "=", detail::escape_detect);
9123 commandline = detail::find_and_modify(commandline, ":", detail::escape_detect);
9124 }
9125
9126 auto args = detail::split_up(std::move(commandline));
9127 // remove all empty strings
9128 args.erase(std::remove(args.begin(), args.end(), std::string{}), args.end());
9129 try {
9130 detail::remove_quotes(args);
9131 } catch(const std::invalid_argument &arg) {
9132 throw CLI::ParseError(arg.what(), CLI::ExitCodes::InvalidError);
9133 }
9134 std::reverse(args.begin(), args.end());
9135 parse(std::move(args));
9136}
9137
9138CLI11_INLINE void App::parse(std::wstring commandline, bool program_name_included) {
9139 parse(narrow(commandline), program_name_included);
9140}
9141
9142CLI11_INLINE void App::parse(std::vector<std::string> &args) {
9143 // Clear if parsed
9144 if(parsed_ > 0)
9145 clear();
9146
9147 // parsed_ is incremented in commands/subcommands,
9148 // but placed here to make sure this is cleared when
9149 // running parse after an error is thrown, even by _validate or _configure.
9150 parsed_ = 1;
9151 _validate();
9152 _configure();
9153 // set the parent as nullptr as this object should be the top now
9154 parent_ = nullptr;
9155 parsed_ = 0;
9156
9157 _parse(args);
9158 run_callback();
9159}
9160
9161CLI11_INLINE void App::parse(std::vector<std::string> &&args) {
9162 // Clear if parsed
9163 if(parsed_ > 0)
9164 clear();
9165
9166 // parsed_ is incremented in commands/subcommands,
9167 // but placed here to make sure this is cleared when
9168 // running parse after an error is thrown, even by _validate or _configure.
9169 parsed_ = 1;
9170 _validate();
9171 _configure();
9172 // set the parent as nullptr as this object should be the top now
9173 parent_ = nullptr;
9174 parsed_ = 0;
9175
9176 _parse(std::move(args));
9177 run_callback();
9178}
9179
9180CLI11_INLINE void App::parse_from_stream(std::istream &input) {
9181 if(parsed_ == 0) {
9182 _validate();
9183 _configure();
9184 // set the parent as nullptr as this object should be the top now
9185 }
9186
9187 _parse_stream(input);
9188 run_callback();
9189}
9190
9191CLI11_INLINE int App::exit(const Error &e, std::ostream &out, std::ostream &err) const {
9192
9194 if(e.get_name() == "RuntimeError")
9195 return e.get_exit_code();
9196
9197 if(e.get_name() == "CallForHelp") {
9198 out << help();
9199 return e.get_exit_code();
9200 }
9201
9202 if(e.get_name() == "CallForAllHelp") {
9203 out << help("", AppFormatMode::All);
9204 return e.get_exit_code();
9205 }
9206
9207 if(e.get_name() == "CallForVersion") {
9208 out << e.what() << '\n';
9209 return e.get_exit_code();
9210 }
9211
9212 if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
9214 err << failure_message_(this, e) << std::flush;
9215 }
9216
9217 return e.get_exit_code();
9218}
9219
9220CLI11_INLINE std::vector<const App *> App::get_subcommands(const std::function<bool(const App *)> &filter) const {
9221 std::vector<const App *> subcomms(subcommands_.size());
9222 std::transform(
9223 std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) { return v.get(); });
9224
9225 if(filter) {
9226 subcomms.erase(std::remove_if(std::begin(subcomms),
9227 std::end(subcomms),
9228 [&filter](const App *app) { return !filter(app); }),
9229 std::end(subcomms));
9230 }
9231
9232 return subcomms;
9233}
9234
9235CLI11_INLINE std::vector<App *> App::get_subcommands(const std::function<bool(App *)> &filter) {
9236 std::vector<App *> subcomms(subcommands_.size());
9237 std::transform(
9238 std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) { return v.get(); });
9239
9240 if(filter) {
9241 subcomms.erase(
9242 std::remove_if(std::begin(subcomms), std::end(subcomms), [&filter](App *app) { return !filter(app); }),
9243 std::end(subcomms));
9244 }
9245
9246 return subcomms;
9247}
9248
9249CLI11_INLINE bool App::remove_excludes(Option *opt) {
9250 auto iterator = std::find(std::begin(exclude_options_), std::end(exclude_options_), opt);
9251 if(iterator == std::end(exclude_options_)) {
9252 return false;
9253 }
9254 exclude_options_.erase(iterator);
9255 return true;
9256}
9257
9258CLI11_INLINE bool App::remove_excludes(App *app) {
9259 auto iterator = std::find(std::begin(exclude_subcommands_), std::end(exclude_subcommands_), app);
9260 if(iterator == std::end(exclude_subcommands_)) {
9261 return false;
9262 }
9263 auto *other_app = *iterator;
9264 exclude_subcommands_.erase(iterator);
9265 other_app->remove_excludes(this);
9266 return true;
9267}
9268
9269CLI11_INLINE bool App::remove_needs(Option *opt) {
9270 auto iterator = std::find(std::begin(need_options_), std::end(need_options_), opt);
9271 if(iterator == std::end(need_options_)) {
9272 return false;
9273 }
9274 need_options_.erase(iterator);
9275 return true;
9276}
9277
9278CLI11_INLINE bool App::remove_needs(App *app) {
9279 auto iterator = std::find(std::begin(need_subcommands_), std::end(need_subcommands_), app);
9280 if(iterator == std::end(need_subcommands_)) {
9281 return false;
9282 }
9283 need_subcommands_.erase(iterator);
9284 return true;
9285}
9286
9287CLI11_NODISCARD CLI11_INLINE std::string App::help(std::string prev, AppFormatMode mode) const {
9288 if(prev.empty())
9289 prev = get_name();
9290 else
9291 prev += " " + get_name();
9292
9293 // Delegate to subcommand if needed
9294 auto selected_subcommands = get_subcommands();
9295 if(!selected_subcommands.empty()) {
9296 return selected_subcommands.back()->help(prev, mode);
9297 }
9298 return formatter_->make_help(this, prev, mode);
9299}
9300
9301CLI11_NODISCARD CLI11_INLINE std::string App::version() const {
9302 std::string val;
9303 if(version_ptr_ != nullptr) {
9304 // copy the results for reuse later
9305 results_t rv = version_ptr_->results();
9306 version_ptr_->clear();
9307 version_ptr_->add_result("true");
9308 try {
9309 version_ptr_->run_callback();
9310 } catch(const CLI::CallForVersion &cfv) {
9311 val = cfv.what();
9312 }
9313 version_ptr_->clear();
9314 version_ptr_->add_result(rv);
9315 }
9316 return val;
9317}
9318
9319CLI11_INLINE std::vector<const Option *> App::get_options(const std::function<bool(const Option *)> filter) const {
9320 std::vector<const Option *> options(options_.size());
9321 std::transform(
9322 std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) { return val.get(); });
9323
9324 if(filter) {
9325 options.erase(std::remove_if(std::begin(options),
9326 std::end(options),
9327 [&filter](const Option *opt) { return !filter(opt); }),
9328 std::end(options));
9329 }
9330 for(const auto &subcp : subcommands_) {
9331 // also check down into nameless subcommands
9332 const App *subc = subcp.get();
9333 if(subc->get_name().empty() && !subc->get_group().empty() && subc->get_group().front() == '+') {
9334 std::vector<const Option *> subcopts = subc->get_options(filter);
9335 options.insert(options.end(), subcopts.begin(), subcopts.end());
9336 }
9337 }
9338 if(fallthrough_ && parent_ != nullptr) {
9339 const auto *fallthrough_parent = _get_fallthrough_parent();
9340 std::vector<const Option *> subcopts = fallthrough_parent->get_options(filter);
9341 for(const auto *opt : subcopts) {
9342 if(std::find_if(options.begin(), options.end(), [opt](const Option *opt2) {
9343 return opt->check_name(opt2->get_name());
9344 }) == options.end()) {
9345 options.push_back(opt);
9346 }
9347 }
9348 }
9349 return options;
9350}
9351
9352CLI11_INLINE std::vector<Option *> App::get_options(const std::function<bool(Option *)> filter) {
9353 std::vector<Option *> options(options_.size());
9354 std::transform(
9355 std::begin(options_), std::end(options_), std::begin(options), [](const Option_p &val) { return val.get(); });
9356
9357 if(filter) {
9358 options.erase(
9359 std::remove_if(std::begin(options), std::end(options), [&filter](Option *opt) { return !filter(opt); }),
9360 std::end(options));
9361 }
9362 for(auto &subc : subcommands_) {
9363 // also check down into nameless subcommands and specific groups
9364 if(subc->get_name().empty() || (!subc->get_group().empty() && subc->get_group().front() == '+')) {
9365 auto subcopts = subc->get_options(filter);
9366 options.insert(options.end(), subcopts.begin(), subcopts.end());
9367 }
9368 }
9369 if(fallthrough_ && parent_ != nullptr) {
9370 auto *fallthrough_parent = _get_fallthrough_parent();
9371 std::vector<Option *> subcopts = fallthrough_parent->get_options(filter);
9372 for(auto *opt : subcopts) {
9373 if(std::find_if(options.begin(), options.end(), [opt](Option *opt2) {
9374 return opt->check_name(opt2->get_name());
9375 }) == options.end()) {
9376 options.push_back(opt);
9377 }
9378 }
9379 }
9380 return options;
9381}
9382
9383CLI11_NODISCARD CLI11_INLINE Option *App::get_option_no_throw(std::string option_name) noexcept {
9384 for(Option_p &opt : options_) {
9385 if(opt->check_name(option_name)) {
9386 return opt.get();
9387 }
9388 }
9389 for(auto &subc : subcommands_) {
9390 // also check down into nameless subcommands
9391 if(subc->get_name().empty()) {
9392 auto *opt = subc->get_option_no_throw(option_name);
9393 if(opt != nullptr) {
9394 return opt;
9395 }
9396 }
9397 }
9398 if(fallthrough_ && parent_ != nullptr) {
9399 return _get_fallthrough_parent()->get_option_no_throw(option_name);
9400 }
9401 return nullptr;
9402}
9403
9404CLI11_NODISCARD CLI11_INLINE const Option *App::get_option_no_throw(std::string option_name) const noexcept {
9405 for(const Option_p &opt : options_) {
9406 if(opt->check_name(option_name)) {
9407 return opt.get();
9408 }
9409 }
9410 for(const auto &subc : subcommands_) {
9411 // also check down into nameless subcommands
9412 if(subc->get_name().empty()) {
9413 auto *opt = subc->get_option_no_throw(option_name);
9414 if(opt != nullptr) {
9415 return opt;
9416 }
9417 }
9418 }
9419 if(fallthrough_ && parent_ != nullptr) {
9420 return _get_fallthrough_parent()->get_option_no_throw(option_name);
9421 }
9422 return nullptr;
9423}
9424
9425CLI11_NODISCARD CLI11_INLINE std::string App::get_display_name(bool with_aliases) const {
9426 if(name_.empty()) {
9427 return std::string("[Option Group: ") + get_group() + "]";
9428 }
9429 if(aliases_.empty() || !with_aliases) {
9430 return name_;
9431 }
9432 std::string dispname = name_;
9433 for(const auto &lalias : aliases_) {
9434 dispname.push_back(',');
9435 dispname.push_back(' ');
9436 dispname.append(lalias);
9437 }
9438 return dispname;
9439}
9440
9441CLI11_NODISCARD CLI11_INLINE bool App::check_name(std::string name_to_check) const {
9442 auto result = check_name_detail(std::move(name_to_check));
9443 return (result != NameMatch::none);
9444}
9445
9446CLI11_NODISCARD CLI11_INLINE App::NameMatch App::check_name_detail(std::string name_to_check) const {
9447 std::string local_name = name_;
9448 if(ignore_underscore_) {
9449 local_name = detail::remove_underscore(name_);
9450 name_to_check = detail::remove_underscore(name_to_check);
9451 }
9452 if(ignore_case_) {
9453 local_name = detail::to_lower(name_);
9454 name_to_check = detail::to_lower(name_to_check);
9455 }
9456
9457 if(local_name == name_to_check) {
9458 return App::NameMatch::exact;
9459 }
9460 if(allow_prefix_matching_ && name_to_check.size() < local_name.size()) {
9461 if(local_name.compare(0, name_to_check.size(), name_to_check) == 0) {
9462 return App::NameMatch::prefix;
9463 }
9464 }
9465 for(std::string les : aliases_) { // NOLINT(performance-for-range-copy)
9466 if(ignore_underscore_) {
9467 les = detail::remove_underscore(les);
9468 }
9469 if(ignore_case_) {
9470 les = detail::to_lower(les);
9471 }
9472 if(les == name_to_check) {
9473 return App::NameMatch::exact;
9474 }
9475 if(allow_prefix_matching_ && name_to_check.size() < les.size()) {
9476 if(les.compare(0, name_to_check.size(), name_to_check) == 0) {
9477 return App::NameMatch::prefix;
9478 }
9479 }
9480 }
9481 return App::NameMatch::none;
9482}
9483
9484CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::get_groups() const {
9485 std::vector<std::string> groups;
9486
9487 for(const Option_p &opt : options_) {
9488 // Add group if it is not already in there
9489 if(std::find(groups.begin(), groups.end(), opt->get_group()) == groups.end()) {
9490 groups.push_back(opt->get_group());
9491 }
9492 }
9493
9494 return groups;
9495}
9496
9497CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::remaining(bool recurse) const {
9498 std::vector<std::string> miss_list;
9499 for(const std::pair<detail::Classifier, std::string> &miss : missing_) {
9500 miss_list.push_back(std::get<1>(miss));
9501 }
9502 // Get from a subcommand that may allow extras
9503 if(recurse) {
9504 if(allow_extras_ == ExtrasMode::Error || allow_extras_ == ExtrasMode::Ignore) {
9505 for(const auto &sub : subcommands_) {
9506 if(sub->name_.empty() && !sub->missing_.empty()) {
9507 for(const std::pair<detail::Classifier, std::string> &miss : sub->missing_) {
9508 miss_list.push_back(std::get<1>(miss));
9509 }
9510 }
9511 }
9512 }
9513 // Recurse into subcommands
9514
9515 for(const App *sub : parsed_subcommands_) {
9516 std::vector<std::string> output = sub->remaining(recurse);
9517 std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
9518 }
9519 }
9520 return miss_list;
9521}
9522
9523CLI11_NODISCARD CLI11_INLINE std::vector<std::string> App::remaining_for_passthrough(bool recurse) const {
9524 std::vector<std::string> miss_list = remaining(recurse);
9525 std::reverse(std::begin(miss_list), std::end(miss_list));
9526 return miss_list;
9527}
9528
9529CLI11_NODISCARD CLI11_INLINE std::size_t App::remaining_size(bool recurse) const {
9530 auto remaining_options = static_cast<std::size_t>(std::count_if(
9531 std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifier, std::string> &val) {
9532 return val.first != detail::Classifier::POSITIONAL_MARK;
9533 }));
9534
9535 if(recurse) {
9536 for(const App_p &sub : subcommands_) {
9537 remaining_options += sub->remaining_size(recurse);
9538 }
9539 }
9540 return remaining_options;
9541}
9542
9543CLI11_INLINE void App::_validate() const {
9544 // count the number of positional only args
9545 auto pcount = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
9546 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional();
9547 });
9548 if(pcount > 1) {
9549 auto pcount_req = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
9550 return opt->get_items_expected_max() >= detail::expected_max_vector_size && !opt->nonpositional() &&
9551 opt->get_required();
9552 });
9553 if(pcount - pcount_req > 1) {
9554 throw InvalidError(name_);
9555 }
9556 }
9557
9558 std::size_t nameless_subs{0};
9559 for(const App_p &app : subcommands_) {
9560 app->_validate();
9561 if(app->get_name().empty())
9562 ++nameless_subs;
9563 }
9564
9565 if(require_option_min_ > 0) {
9566 if(require_option_max_ > 0) {
9568 throw(InvalidError("Required min options greater than required max options", ExitCodes::InvalidError));
9569 }
9570 }
9571 if(require_option_min_ > (options_.size() + nameless_subs)) {
9572 throw(
9573 InvalidError("Required min options greater than number of available options", ExitCodes::InvalidError));
9574 }
9575 }
9576}
9577
9578CLI11_INLINE void App::_configure() {
9579 if(default_startup == startup_mode::enabled) {
9580 disabled_ = false;
9581 } else if(default_startup == startup_mode::disabled) {
9582 disabled_ = true;
9583 }
9584 for(const App_p &app : subcommands_) {
9585 if(app->has_automatic_name_) {
9586 app->name_.clear();
9587 }
9588 if(app->name_.empty()) {
9589 app->fallthrough_ = false; // make sure fallthrough_ is false to prevent infinite loop
9590 app->prefix_command_ = PrefixCommandMode::Off;
9591 }
9592 // make sure the parent is set to be this object in preparation for parse
9593 app->parent_ = this;
9594 app->_configure();
9595 }
9596}
9597
9598CLI11_INLINE void App::run_callback(bool final_mode, bool suppress_final_callback) {
9599 pre_callback();
9600 // in the main app if immediate_callback_ is set it runs the main callback before the used subcommands
9601 if(!final_mode && parse_complete_callback_) {
9603 }
9604 // run the callbacks for the received subcommands
9605 for(App *subc : get_subcommands()) {
9606 if(subc->parent_ == this) {
9607 subc->run_callback(true, suppress_final_callback);
9608 }
9609 }
9610 // now run callbacks for option_groups
9611 for(auto &subc : subcommands_) {
9612 if(subc->name_.empty() && subc->count_all() > 0) {
9613 subc->run_callback(true, suppress_final_callback);
9614 }
9615 }
9616
9617 // finally run the main callback
9618 if(final_callback_ && (parsed_ > 0) && (!suppress_final_callback)) {
9619 if(!name_.empty() || count_all() > 0 || parent_ == nullptr) {
9621 }
9622 }
9623}
9624
9625CLI11_NODISCARD CLI11_INLINE bool App::_valid_subcommand(const std::string &current, bool ignore_used) const {
9626 // Don't match if max has been reached - but still check parents
9629 return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
9630 }
9631 auto *com = _find_subcommand(current, true, ignore_used);
9632 if(com != nullptr) {
9633 return true;
9634 }
9635 // Check parent if exists, else return false
9637 return parent_ != nullptr && parent_->_valid_subcommand(current, ignore_used);
9638 }
9639 return false;
9640}
9641
9642CLI11_NODISCARD CLI11_INLINE detail::Classifier App::_recognize(const std::string &current,
9643 bool ignore_used_subcommands) const {
9644 std::string dummy1, dummy2;
9645
9646 if(current == "--")
9647 return detail::Classifier::POSITIONAL_MARK;
9648 if(_valid_subcommand(current, ignore_used_subcommands))
9649 return detail::Classifier::SUBCOMMAND;
9650 if(detail::split_long(current, dummy1, dummy2))
9651 return detail::Classifier::LONG;
9652 if(detail::split_short(current, dummy1, dummy2)) {
9653 if((dummy1[0] >= '0' && dummy1[0] <= '9') ||
9654 (dummy1[0] == '.' && !dummy2.empty() && (dummy2[0] >= '0' && dummy2[0] <= '9'))) {
9655 // it looks like a number but check if it could be an option
9656 if(get_option_no_throw(std::string{'-', dummy1[0]}) == nullptr) {
9657 return detail::Classifier::NONE;
9658 }
9659 }
9660 return detail::Classifier::SHORT;
9661 }
9662 if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))
9663 return detail::Classifier::WINDOWS_STYLE;
9664 if((current == "++") && !name_.empty() && parent_ != nullptr)
9665 return detail::Classifier::SUBCOMMAND_TERMINATOR;
9666 auto dotloc = current.find_first_of('.');
9667 if(dotloc != std::string::npos) {
9668 auto *cm = _find_subcommand(current.substr(0, dotloc), true, ignore_used_subcommands);
9669 if(cm != nullptr) {
9670 auto res = cm->_recognize(current.substr(dotloc + 1), ignore_used_subcommands);
9671 if(res == detail::Classifier::SUBCOMMAND) {
9672 return res;
9673 }
9674 }
9675 }
9676 return detail::Classifier::NONE;
9677}
9678
9679CLI11_INLINE bool App::_process_config_file(const std::string &config_file, bool throw_error) {
9680 auto path_result = detail::check_path(config_file.c_str());
9681 if(path_result == detail::path_type::file) {
9682 try {
9683 std::vector<ConfigItem> values = config_formatter_->from_file(config_file);
9684 _parse_config(values);
9685 return true;
9686 } catch(const FileError &) {
9687 if(throw_error) {
9688 throw;
9689 }
9690 return false;
9691 }
9692 } else if(throw_error) {
9693 throw FileError::Missing(config_file);
9694 } else {
9695 return false;
9696 }
9697}
9698
9699CLI11_INLINE void App::_process_config_file() {
9700 if(config_ptr_ != nullptr) {
9701 bool config_required = config_ptr_->get_required();
9702 auto file_given = config_ptr_->count() > 0;
9703 if(!(file_given || config_ptr_->envname_.empty())) {
9704 std::string ename_string = detail::get_environment_value(config_ptr_->envname_);
9705 if(!ename_string.empty()) {
9706 config_ptr_->add_result(ename_string);
9707 }
9708 }
9709 config_ptr_->run_callback();
9710
9711 auto config_files = config_ptr_->as<std::vector<std::string>>();
9712 bool files_used{file_given};
9713 if(config_files.empty() || config_files.front().empty()) {
9714 if(config_required) {
9715 throw FileError("config file is required but none was given");
9716 }
9717 return;
9718 }
9719 for(const auto &config_file : config_files) {
9720 if(_process_config_file(config_file, config_required || file_given)) {
9721 files_used = true;
9722 }
9723 }
9724 if(!files_used) {
9725 // this is done so the count shows as 0 if no callbacks were processed
9726 config_ptr_->clear();
9727 bool force = config_ptr_->force_callback_;
9728 config_ptr_->force_callback_ = false;
9729 config_ptr_->run_callback();
9730 config_ptr_->force_callback_ = force;
9731 }
9732 }
9733}
9734
9735CLI11_INLINE void App::_process_env() {
9736 for(const Option_p &opt : options_) {
9737 if(opt->count() == 0 && !opt->envname_.empty()) {
9738 std::string ename_string = detail::get_environment_value(opt->envname_);
9739 if(!ename_string.empty()) {
9740 std::string result = ename_string;
9741 result = opt->_validate(result, 0);
9742 if(result.empty()) {
9743 opt->add_result(ename_string);
9744 }
9745 }
9746 }
9747 }
9748
9749 for(App_p &sub : subcommands_) {
9750 if(sub->get_name().empty() || (sub->count_all() > 0 && !sub->parse_complete_callback_)) {
9751 // only process environment variables if the callback has actually been triggered already
9752 sub->_process_env();
9753 }
9754 }
9755}
9756
9757CLI11_INLINE void App::_process_callbacks(CallbackPriority priority) {
9758
9759 for(App_p &sub : subcommands_) {
9760 // process the priority option_groups first
9761 if(sub->get_name().empty() && sub->parse_complete_callback_) {
9762 if(sub->count_all() > 0) {
9763 sub->_process_callbacks(priority);
9764 if(priority == CallbackPriority::Normal) {
9765 // only run the subcommand callback at normal priority
9766 sub->run_callback();
9767 }
9768 }
9769 }
9770 }
9771
9772 for(const Option_p &opt : options_) {
9773 if(opt->get_callback_priority() == priority) {
9774 if((*opt) && !opt->get_callback_run()) {
9775 opt->run_callback();
9776 }
9777 }
9778 }
9779 for(App_p &sub : subcommands_) {
9780 if(!sub->parse_complete_callback_) {
9781 sub->_process_callbacks(priority);
9782 }
9783 }
9784}
9785
9786CLI11_INLINE void App::_process_help_flags(CallbackPriority priority, bool trigger_help, bool trigger_all_help) const {
9787 const Option *help_ptr = get_help_ptr();
9788 const Option *help_all_ptr = get_help_all_ptr();
9789
9790 if(help_ptr != nullptr && help_ptr->count() > 0 && help_ptr->get_callback_priority() == priority) {
9791 trigger_help = true;
9792 }
9793 if(help_all_ptr != nullptr && help_all_ptr->count() > 0 && help_all_ptr->get_callback_priority() == priority) {
9794 trigger_all_help = true;
9795 }
9796
9797 // If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.
9798 if(!parsed_subcommands_.empty()) {
9799 for(const App *sub : parsed_subcommands_) {
9800 sub->_process_help_flags(priority, trigger_help, trigger_all_help);
9801 }
9802
9803 // Only the final subcommand should call for help. All help wins over help.
9804 } else if(trigger_all_help) {
9805 throw CallForAllHelp();
9806 } else if(trigger_help) {
9807 throw CallForHelp();
9808 }
9809}
9810
9811CLI11_INLINE void App::_process_requirements() {
9812 // check excludes
9813 bool excluded{false};
9814 std::string excluder;
9815 for(const auto &opt : exclude_options_) {
9816 if(opt->count() > 0) {
9817 excluded = true;
9818 excluder = opt->get_name();
9819 }
9820 }
9821 for(const auto &subc : exclude_subcommands_) {
9822 if(subc->count_all() > 0) {
9823 excluded = true;
9824 excluder = subc->get_display_name();
9825 }
9826 }
9827 if(excluded) {
9828 if(count_all() > 0) {
9829 throw ExcludesError(get_display_name(), excluder);
9830 }
9831 // if we are excluded but didn't receive anything, just return
9832 return;
9833 }
9834
9835 // check excludes
9836 bool missing_needed{false};
9837 std::string missing_need;
9838 for(const auto &opt : need_options_) {
9839 if(opt->count() == 0) {
9840 missing_needed = true;
9841 missing_need = opt->get_name();
9842 }
9843 }
9844 for(const auto &subc : need_subcommands_) {
9845 if(subc->count_all() == 0) {
9846 missing_needed = true;
9847 missing_need = subc->get_display_name();
9848 }
9849 }
9850 if(missing_needed) {
9851 if(count_all() > 0) {
9852 throw RequiresError(get_display_name(), missing_need);
9853 }
9854 // if we missing something but didn't have any options, just return
9855 return;
9856 }
9857
9858 std::size_t used_options = 0;
9859 for(const Option_p &opt : options_) {
9860
9861 if(opt->count() != 0) {
9862 ++used_options;
9863 }
9864 // Required but empty
9865 if(opt->get_required() && opt->count() == 0) {
9866 throw RequiredError(opt->get_name());
9867 }
9868 // Requires
9869 for(const Option *opt_req : opt->needs_)
9870 if(opt->count() > 0 && opt_req->count() == 0)
9871 throw RequiresError(opt->get_name(), opt_req->get_name());
9872 // Excludes
9873 for(const Option *opt_ex : opt->excludes_)
9874 if(opt->count() > 0 && opt_ex->count() != 0)
9875 throw ExcludesError(opt->get_name(), opt_ex->get_name());
9876 }
9877 // check for the required number of subcommands
9878 if(require_subcommand_min_ > 0) {
9879 auto selected_subcommands = get_subcommands();
9880 if(require_subcommand_min_ > selected_subcommands.size())
9881 throw RequiredError::Subcommand(require_subcommand_min_);
9882 }
9883
9884 // Max error cannot occur, the extra subcommand will parse as an ExtrasError or a remaining item.
9885
9886 // run this loop to check how many unnamed subcommands were actually used since they are considered options
9887 // from the perspective of an App
9888 for(App_p &sub : subcommands_) {
9889 if(sub->disabled_)
9890 continue;
9891 if(sub->name_.empty() && sub->count_all() > 0) {
9892 ++used_options;
9893 }
9894 }
9895
9896 if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
9897 auto option_list = detail::join(options_, [this](const Option_p &ptr) {
9898 if(ptr.get() == help_ptr_ || ptr.get() == help_all_ptr_) {
9899 return std::string{};
9900 }
9901 return ptr->get_name(false, true);
9902 });
9903
9904 auto subc_list = get_subcommands([](App *app) { return ((app->get_name().empty()) && (!app->disabled_)); });
9905 if(!subc_list.empty()) {
9906 option_list += "," + detail::join(subc_list, [](const App *app) { return app->get_display_name(); });
9907 }
9908 throw RequiredError::Option(require_option_min_, require_option_max_, used_options, option_list);
9909 }
9910
9911 // now process the requirements for subcommands if needed
9912 for(App_p &sub : subcommands_) {
9913 if(sub->disabled_)
9914 continue;
9915 if(sub->name_.empty() && sub->required_ == false) {
9916 if(sub->count_all() == 0) {
9917 if(require_option_min_ > 0 && require_option_min_ <= used_options) {
9918 continue;
9919 // if we have met the requirement and there is nothing in this option group skip checking
9920 // requirements
9921 }
9922 if(require_option_max_ > 0 && used_options >= require_option_min_) {
9923 continue;
9924 // if we have met the requirement and there is nothing in this option group skip checking
9925 // requirements
9926 }
9927 }
9928 }
9929 if(sub->count() > 0 || sub->name_.empty()) {
9930 sub->_process_requirements();
9931 }
9932
9933 if(sub->required_ && sub->count_all() == 0) {
9934 throw(CLI::RequiredError(sub->get_display_name()));
9935 }
9936 }
9937}
9938
9939CLI11_INLINE void App::_process() {
9940 // help takes precedence over other potential errors and config and environment shouldn't be processed if help
9941 // throws
9942 _process_callbacks(CallbackPriority::FirstPreHelp);
9943 _process_help_flags(CallbackPriority::First);
9944 _process_callbacks(CallbackPriority::First);
9945
9946 std::exception_ptr config_exception;
9947 try {
9948 // the config file might generate a FileError but that should not be processed until later in the process
9949 // to allow for help, version and other errors to generate first.
9951
9952 // process env shouldn't throw but no reason to process it if config generated an error
9953 _process_env();
9954 } catch(const CLI::FileError &) {
9955 config_exception = std::current_exception();
9956 }
9957 // callbacks and requirements processing can generate exceptions which should take priority
9958 // over the config file error if one exists.
9959 _process_callbacks(CallbackPriority::PreRequirementsCheckPreHelp);
9960 _process_help_flags(CallbackPriority::PreRequirementsCheck);
9961 _process_callbacks(CallbackPriority::PreRequirementsCheck);
9962
9964
9965 _process_callbacks(CallbackPriority::NormalPreHelp);
9966 _process_help_flags(CallbackPriority::Normal);
9967 _process_callbacks(CallbackPriority::Normal);
9968
9969 if(config_exception) {
9970 std::rethrow_exception(config_exception);
9971 }
9972
9973 _process_callbacks(CallbackPriority::LastPreHelp);
9974 _process_help_flags(CallbackPriority::Last);
9975 _process_callbacks(CallbackPriority::Last);
9976}
9977
9978CLI11_INLINE void App::_process_extras() {
9979 if(allow_extras_ == ExtrasMode::Error && prefix_command_ == PrefixCommandMode::Off) {
9980 std::size_t num_left_over = remaining_size();
9981 if(num_left_over > 0) {
9982 throw ExtrasError(name_, remaining(false));
9983 }
9984 }
9985 if(allow_extras_ == ExtrasMode::Error && prefix_command_ == PrefixCommandMode::SeparatorOnly) {
9986 std::size_t num_left_over = remaining_size();
9987 if(num_left_over > 0) {
9988 if(remaining(false).front() != "--") {
9989 throw ExtrasError(name_, remaining(false));
9990 }
9991 }
9992 }
9993 for(App_p &sub : subcommands_) {
9994 if(sub->count() > 0)
9995 sub->_process_extras();
9996 }
9997}
9998
9999CLI11_INLINE void App::increment_parsed() {
10000 ++parsed_;
10001 for(App_p &sub : subcommands_) {
10002 if(sub->get_name().empty())
10003 sub->increment_parsed();
10004 }
10005}
10006
10007CLI11_INLINE void App::_parse(std::vector<std::string> &args) {
10009 _trigger_pre_parse(args.size());
10010 bool positional_only = false;
10011
10012 while(!args.empty()) {
10013 if(!_parse_single(args, positional_only)) {
10014 break;
10015 }
10016 }
10017
10018 if(parent_ == nullptr) {
10019 _process();
10020
10021 // Throw error if any items are left over (depending on settings)
10023 // Convert missing (pairs) to extras (string only) ready for processing in another app
10024 args = remaining_for_passthrough(false);
10025 } else if(parse_complete_callback_) {
10026 _process_callbacks(CallbackPriority::FirstPreHelp);
10027 _process_help_flags(CallbackPriority::First);
10028 _process_callbacks(CallbackPriority::First);
10029 _process_env();
10030 _process_callbacks(CallbackPriority::PreRequirementsCheckPreHelp);
10031 _process_help_flags(CallbackPriority::PreRequirementsCheck);
10032 _process_callbacks(CallbackPriority::PreRequirementsCheck);
10034 _process_callbacks(CallbackPriority::NormalPreHelp);
10035 _process_help_flags(CallbackPriority::Normal);
10036 _process_callbacks(CallbackPriority::Normal);
10037 _process_callbacks(CallbackPriority::LastPreHelp);
10038 _process_help_flags(CallbackPriority::Last);
10039 _process_callbacks(CallbackPriority::Last);
10040 run_callback(false, true);
10041 }
10042}
10043
10044CLI11_INLINE void App::_parse(std::vector<std::string> &&args) {
10045 // this can only be called by the top level in which case parent == nullptr by definition
10046 // operation is simplified
10048 _trigger_pre_parse(args.size());
10049 bool positional_only = false;
10050
10051 while(!args.empty()) {
10052 _parse_single(args, positional_only);
10053 }
10054 _process();
10055
10056 // Throw error if any items are left over (depending on settings)
10058}
10059
10060CLI11_INLINE void App::_parse_stream(std::istream &input) {
10061 auto values = config_formatter_->from_config(input);
10062 _parse_config(values);
10064 _trigger_pre_parse(values.size());
10065 _process();
10066
10067 // Throw error if any items are left over (depending on settings)
10069}
10070
10071CLI11_INLINE void App::_parse_config(const std::vector<ConfigItem> &args) {
10072 for(const ConfigItem &item : args) {
10073 if(!_parse_single_config(item) && allow_config_extras_ == ConfigExtrasMode::Error)
10074 throw ConfigError::Extras(item.fullname());
10075 }
10076}
10077
10078CLI11_INLINE bool
10079App::_add_flag_like_result(Option *op, const ConfigItem &item, const std::vector<std::string> &inputs) {
10080 if(item.inputs.size() <= 1) {
10081 // Flag parsing
10082 auto res = config_formatter_->to_flag(item);
10083 bool converted{false};
10084 if(op->get_disable_flag_override()) {
10085 auto val = detail::to_flag_value(res);
10086 if(val == 1) {
10087 res = op->get_flag_value(item.name, "{}");
10088 converted = true;
10089 }
10090 }
10091
10092 if(!converted) {
10093 errno = 0;
10094 if(res != "{}" || op->get_expected_max() <= 1) {
10095 res = op->get_flag_value(item.name, res);
10096 }
10097 }
10098
10099 op->add_result(res);
10100 return true;
10101 }
10102 if(static_cast<int>(inputs.size()) > op->get_items_expected_max() &&
10103 op->get_multi_option_policy() != MultiOptionPolicy::TakeAll &&
10104 op->get_multi_option_policy() != MultiOptionPolicy::Join) {
10105 if(op->get_items_expected_max() > 1) {
10106 throw ArgumentMismatch::AtMost(item.fullname(), op->get_items_expected_max(), inputs.size());
10107 }
10108
10109 if(!op->get_disable_flag_override()) {
10110 throw ConversionError::TooManyInputsFlag(item.fullname());
10111 }
10112 // if the disable flag override is set then we must have the flag values match a known flag value
10113 // this is true regardless of the output value, so an array input is possible and must be accounted for
10114 for(const auto &res : inputs) {
10115 bool valid_value{false};
10116 if(op->default_flag_values_.empty()) {
10117 if(res == "true" || res == "false" || res == "1" || res == "0") {
10118 valid_value = true;
10119 }
10120 } else {
10121 for(const auto &valid_res : op->default_flag_values_) {
10122 if(valid_res.second == res) {
10123 valid_value = true;
10124 break;
10125 }
10126 }
10127 }
10128
10129 if(valid_value) {
10130 op->add_result(res);
10131 } else {
10132 throw InvalidError("invalid flag argument given");
10133 }
10134 }
10135 return true;
10136 }
10137 return false;
10138}
10139
10140CLI11_INLINE bool App::_parse_single_config(const ConfigItem &item, std::size_t level) {
10141
10142 if(level < item.parents.size()) {
10143 auto *subcom = get_subcommand_no_throw(item.parents.at(level));
10144 return (subcom != nullptr) ? subcom->_parse_single_config(item, level + 1) : false;
10145 }
10146 // check for section open
10147 if(item.name == "++") {
10148 if(configurable_) {
10151 if(parent_ != nullptr) {
10152 parent_->parsed_subcommands_.push_back(this);
10153 }
10154 }
10155 return true;
10156 }
10157 // check for section close
10158 if(item.name == "--") {
10160 _process_callbacks(CallbackPriority::FirstPreHelp);
10161 _process_callbacks(CallbackPriority::First);
10162 _process_callbacks(CallbackPriority::PreRequirementsCheckPreHelp);
10163 _process_callbacks(CallbackPriority::PreRequirementsCheck);
10165 _process_callbacks(CallbackPriority::NormalPreHelp);
10166 _process_callbacks(CallbackPriority::Normal);
10167 _process_callbacks(CallbackPriority::LastPreHelp);
10168 _process_callbacks(CallbackPriority::Last);
10169 run_callback();
10170 }
10171 return true;
10172 }
10173 Option *op = get_option_no_throw("--" + item.name);
10174 if(op == nullptr) {
10175 if(item.name.size() == 1) {
10176 op = get_option_no_throw("-" + item.name);
10177 }
10178 if(op == nullptr) {
10179 op = get_option_no_throw(item.name);
10180 }
10181 } else if(!op->get_configurable()) {
10182 if(item.name.size() == 1) {
10183 auto *testop = get_option_no_throw("-" + item.name);
10184 if(testop != nullptr && testop->get_configurable()) {
10185 op = testop;
10186 }
10187 }
10188 }
10189 if(op == nullptr || !op->get_configurable()) {
10190 std::string iname = item.name;
10191 auto options = get_options([iname](const CLI::Option *opt) {
10192 return (opt->get_configurable() &&
10193 (opt->check_name(iname) || opt->check_lname(iname) || opt->check_sname(iname)));
10194 });
10195 if(!options.empty()) {
10196 op = options[0];
10197 }
10198 }
10199 if(op == nullptr) {
10200 // If the option was not present
10201 if(get_allow_config_extras() == config_extras_mode::capture) {
10202 // Should we worry about classifying the extras properly?
10203 missing_.emplace_back(detail::Classifier::NONE, item.fullname());
10204 for(const auto &input : item.inputs) {
10205 missing_.emplace_back(detail::Classifier::NONE, input);
10206 }
10207 }
10208 return false;
10209 }
10210
10211 if(!op->get_configurable()) {
10212 if(get_allow_config_extras() == config_extras_mode::ignore_all) {
10213 return false;
10214 }
10215 throw ConfigError::NotConfigurable(item.fullname());
10216 }
10217 if(op->empty()) {
10218 std::vector<std::string> buffer; // a buffer to use for copying and modifying inputs in a few cases
10219 bool useBuffer{false};
10220 if(item.multiline) {
10221 if(!op->get_inject_separator()) {
10222 buffer = item.inputs;
10223 buffer.erase(std::remove(buffer.begin(), buffer.end(), "%%"), buffer.end());
10224 useBuffer = true;
10225 }
10226 }
10227 const std::vector<std::string> &inputs = (useBuffer) ? buffer : item.inputs;
10228 if(op->get_expected_min() == 0) {
10229 if(_add_flag_like_result(op, item, inputs)) {
10230 return true;
10231 }
10232 }
10233 op->add_result(inputs);
10234 op->run_callback();
10235 }
10236
10237 return true;
10238}
10239
10240CLI11_INLINE bool App::_parse_single(std::vector<std::string> &args, bool &positional_only) {
10241 bool retval = true;
10242 detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back());
10243 switch(classifier) {
10244 case detail::Classifier::POSITIONAL_MARK:
10245 args.pop_back();
10246 positional_only = true;
10247 if(get_prefix_command()) {
10248 // don't care about extras mode here
10249 missing_.emplace_back(classifier, "--");
10250 while(!args.empty()) {
10251 missing_.emplace_back(detail::Classifier::NONE, args.back());
10252 args.pop_back();
10253 }
10254 } else if((!_has_remaining_positionals()) && (parent_ != nullptr)) {
10255 retval = false;
10256 } else {
10257 _move_to_missing(classifier, "--");
10258 }
10259 break;
10260 case detail::Classifier::SUBCOMMAND_TERMINATOR:
10261 // treat this like a positional mark if in the parent app
10262 args.pop_back();
10263 retval = false;
10264 break;
10265 case detail::Classifier::SUBCOMMAND:
10266 retval = _parse_subcommand(args);
10267 break;
10268 case detail::Classifier::LONG:
10269 case detail::Classifier::SHORT:
10270 case detail::Classifier::WINDOWS_STYLE:
10271 // If already parsed a subcommand, don't accept options_
10272 retval = _parse_arg(args, classifier, false);
10273 break;
10274 case detail::Classifier::NONE:
10275 // Probably a positional or something for a parent (sub)command
10276 retval = _parse_positional(args, false);
10277 if(retval && positionals_at_end_) {
10278 positional_only = true;
10279 }
10280 break;
10281 // LCOV_EXCL_START
10282 default:
10283 throw HorribleError("unrecognized classifier (you should not see this!)");
10284 // LCOV_EXCL_STOP
10285 }
10286 return retval;
10287}
10288
10289CLI11_NODISCARD CLI11_INLINE std::size_t App::_count_remaining_positionals(bool required_only) const {
10290 std::size_t retval = 0;
10291 for(const Option_p &opt : options_) {
10292 if(opt->get_positional() && (!required_only || opt->get_required())) {
10293 if(opt->get_items_expected_min() > 0 && static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
10294 retval += static_cast<std::size_t>(opt->get_items_expected_min()) - opt->count();
10295 }
10296 }
10297 }
10298 return retval;
10299}
10300
10301CLI11_NODISCARD CLI11_INLINE bool App::_has_remaining_positionals() const {
10302 for(const Option_p &opt : options_) {
10303 if(opt->get_positional() && ((static_cast<int>(opt->count()) < opt->get_items_expected_min()))) {
10304 return true;
10305 }
10306 }
10307
10308 return false;
10309}
10310
10311CLI11_INLINE bool App::_parse_positional(std::vector<std::string> &args, bool haltOnSubcommand) {
10312
10313 const std::string &positional = args.back();
10314 Option *posOpt{nullptr};
10315
10317 // deal with the case of required arguments at the end which should take precedence over other arguments
10318 auto arg_rem = args.size();
10319 auto remreq = _count_remaining_positionals(true);
10320 if(arg_rem <= remreq) {
10321 for(const Option_p &opt : options_) {
10322 if(opt->get_positional() && opt->required_) {
10323 if(static_cast<int>(opt->count()) < opt->get_items_expected_min()) {
10325 std::string pos = positional;
10326 pos = opt->_validate(pos, 0);
10327 if(!pos.empty()) {
10328 continue;
10329 }
10330 }
10331 posOpt = opt.get();
10332 break;
10333 }
10334 }
10335 }
10336 }
10337 }
10338 if(posOpt == nullptr) {
10339 for(const Option_p &opt : options_) {
10340 // Eat options, one by one, until done
10341 if(opt->get_positional() &&
10342 (static_cast<int>(opt->count()) < opt->get_items_expected_max() || opt->get_allow_extra_args())) {
10344 std::string pos = positional;
10345 pos = opt->_validate(pos, 0);
10346 if(!pos.empty()) {
10347 continue;
10348 }
10349 }
10350 posOpt = opt.get();
10351 break;
10352 }
10353 }
10354 }
10355 if(posOpt != nullptr) {
10356 parse_order_.push_back(posOpt);
10357 if(posOpt->get_inject_separator()) {
10358 if(!posOpt->results().empty() && !posOpt->results().back().empty()) {
10359 posOpt->add_result(std::string{});
10360 }
10361 }
10362 results_t prev;
10364 prev = posOpt->results();
10365 posOpt->clear();
10366 }
10367 if(posOpt->get_expected_min() == 0) {
10368 ConfigItem item;
10369 item.name = posOpt->pname_;
10370 item.inputs.push_back(positional);
10371 // input is singular guaranteed to return true in that case
10372 _add_flag_like_result(posOpt, item, item.inputs);
10373 } else {
10374 posOpt->add_result(positional);
10375 }
10376
10377 if(posOpt->get_trigger_on_parse()) {
10378 if(!posOpt->empty()) {
10379 posOpt->run_callback();
10380 } else {
10381 if(!prev.empty()) {
10382 posOpt->add_result(prev);
10383 }
10384 }
10385 }
10386
10387 args.pop_back();
10388 return true;
10389 }
10390
10391 for(auto &subc : subcommands_) {
10392 if((subc->name_.empty()) && (!subc->disabled_)) {
10393 if(subc->_parse_positional(args, false)) {
10394 if(!subc->pre_parse_called_) {
10395 subc->_trigger_pre_parse(args.size());
10396 }
10397 return true;
10398 }
10399 }
10400 }
10401 // let the parent deal with it if possible
10402 if(parent_ != nullptr && fallthrough_) {
10403 return _get_fallthrough_parent()->_parse_positional(args, static_cast<bool>(parse_complete_callback_));
10404 }
10406 auto *com = _find_subcommand(args.back(), true, false);
10407 if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
10408 if(haltOnSubcommand) {
10409 return false;
10410 }
10411 args.pop_back();
10412 com->_parse(args);
10413 return true;
10414 }
10418 auto *parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
10419 com = parent_app->_find_subcommand(args.back(), true, false);
10420 if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||
10421 com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
10422 return false;
10423 }
10424 }
10426 std::vector<std::string> rargs;
10427 rargs.resize(args.size());
10428 std::reverse_copy(args.begin(), args.end(), rargs.begin());
10429 throw CLI::ExtrasError(name_, rargs);
10430 }
10432 if(parent_ != nullptr && name_.empty()) {
10433 return false;
10434 }
10436 _move_to_missing(detail::Classifier::NONE, positional);
10437 args.pop_back();
10438 if(get_prefix_command()) {
10439 while(!args.empty()) {
10440 missing_.emplace_back(detail::Classifier::NONE, args.back());
10441 args.pop_back();
10442 }
10443 }
10444
10445 return true;
10446}
10447
10448CLI11_NODISCARD CLI11_INLINE App *
10449App::_find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {
10450 App *bcom{nullptr};
10451 for(const App_p &com : subcommands_) {
10452 if(com->disabled_ && ignore_disabled)
10453 continue;
10454 if(com->get_name().empty()) {
10455 auto *subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
10456 if(subc != nullptr) {
10457 if(bcom != nullptr) {
10458 return nullptr;
10459 }
10460 bcom = subc;
10462 return bcom;
10463 }
10464 }
10465 }
10466 auto res = com->check_name_detail(subc_name);
10467 if(res != NameMatch::none) {
10468 if((!*com) || !ignore_used) {
10469 if(res == NameMatch::exact) {
10470 return com.get();
10471 }
10472 if(bcom != nullptr) {
10473 return nullptr;
10474 }
10475 bcom = com.get();
10477 return bcom;
10478 }
10479 }
10480 }
10481 }
10482 return bcom;
10483}
10484
10485CLI11_INLINE bool App::_parse_subcommand(std::vector<std::string> &args) {
10486 if(_count_remaining_positionals(/* required */ true) > 0) {
10487 _parse_positional(args, false);
10488 return true;
10489 }
10490 auto *com = _find_subcommand(args.back(), true, true);
10491 if(com == nullptr) {
10492 // the main way to get here is using .notation
10493 auto dotloc = args.back().find_first_of('.');
10494 if(dotloc != std::string::npos) {
10495 com = _find_subcommand(args.back().substr(0, dotloc), true, true);
10496 if(com != nullptr) {
10497 args.back() = args.back().substr(dotloc + 1);
10498 args.push_back(com->get_display_name());
10499 }
10500 }
10501 }
10502 if(com != nullptr) {
10503 args.pop_back();
10504 if(!com->silent_) {
10505 parsed_subcommands_.push_back(com);
10506 }
10507 com->_parse(args);
10508 auto *parent_app = com->parent_;
10509 while(parent_app != this) {
10510 parent_app->_trigger_pre_parse(args.size());
10511 if(!com->silent_) {
10512 parent_app->parsed_subcommands_.push_back(com);
10513 }
10514 parent_app = parent_app->parent_;
10515 }
10516 return true;
10517 }
10518
10519 if(parent_ == nullptr)
10520 throw HorribleError("Subcommand " + args.back() + " missing");
10521 return false;
10522}
10523
10524CLI11_INLINE bool
10525App::_parse_arg(std::vector<std::string> &args, detail::Classifier current_type, bool local_processing_only) {
10526
10527 std::string current = args.back();
10528
10529 std::string arg_name;
10530 std::string value;
10531 std::string rest;
10532
10533 switch(current_type) {
10534 case detail::Classifier::LONG:
10535 if(!detail::split_long(current, arg_name, value))
10536 throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
10537 break;
10538 case detail::Classifier::SHORT:
10539 if(!detail::split_short(current, arg_name, rest))
10540 throw HorribleError("Short parsed but missing! You should not see this");
10541 break;
10542 case detail::Classifier::WINDOWS_STYLE:
10543 if(!detail::split_windows_style(current, arg_name, value))
10544 throw HorribleError("windows option parsed but missing! You should not see this");
10545 break;
10546 case detail::Classifier::SUBCOMMAND:
10547 case detail::Classifier::SUBCOMMAND_TERMINATOR:
10548 case detail::Classifier::POSITIONAL_MARK:
10549 case detail::Classifier::NONE:
10550 default:
10551 throw HorribleError("parsing got called with invalid option! You should not see this");
10552 }
10553
10554 auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [arg_name, current_type](const Option_p &opt) {
10555 if(current_type == detail::Classifier::LONG)
10556 return opt->check_lname(arg_name);
10557 if(current_type == detail::Classifier::SHORT)
10558 return opt->check_sname(arg_name);
10559 // this will only get called for detail::Classifier::WINDOWS_STYLE
10560 return opt->check_lname(arg_name) || opt->check_sname(arg_name);
10561 });
10562
10563 // Option not found
10564 while(op_ptr == std::end(options_)) {
10565 // using while so we can break
10566 for(auto &subc : subcommands_) {
10567 if(subc->name_.empty() && !subc->disabled_) {
10568 if(subc->_parse_arg(args, current_type, local_processing_only)) {
10569 if(!subc->pre_parse_called_) {
10570 subc->_trigger_pre_parse(args.size());
10571 }
10572 return true;
10573 }
10574 }
10575 }
10576 if(allow_non_standard_options_ && current_type == detail::Classifier::SHORT && current.size() > 2) {
10577 std::string narg_name;
10578 std::string nvalue;
10579 detail::split_long(std::string{'-'} + current, narg_name, nvalue);
10580 op_ptr = std::find_if(std::begin(options_), std::end(options_), [narg_name](const Option_p &opt) {
10581 return opt->check_sname(narg_name);
10582 });
10583 if(op_ptr != std::end(options_)) {
10584 arg_name = narg_name;
10585 value = nvalue;
10586 rest.clear();
10587 break;
10588 }
10589 }
10590
10591 // don't capture missing if this is a nameless subcommand and nameless subcommands can't fallthrough
10592 if(parent_ != nullptr && name_.empty()) {
10593 return false;
10594 }
10595
10596 // now check for '.' notation of subcommands
10597 auto dotloc = arg_name.find_first_of('.', 1);
10598 if(dotloc != std::string::npos && dotloc < arg_name.size() - 1) {
10599 // using dot notation is equivalent to single argument subcommand
10600 auto *sub = _find_subcommand(arg_name.substr(0, dotloc), true, false);
10601 if(sub != nullptr) {
10602 std::string v = args.back();
10603 args.pop_back();
10604 arg_name = arg_name.substr(dotloc + 1);
10605 if(arg_name.size() > 1) {
10606 args.push_back(std::string("--") + v.substr(dotloc + 3));
10607 current_type = detail::Classifier::LONG;
10608 } else {
10609 auto nval = v.substr(dotloc + 2);
10610 nval.front() = '-';
10611 if(nval.size() > 2) {
10612 // '=' not allowed in short form arguments
10613 args.push_back(nval.substr(3));
10614 nval.resize(2);
10615 }
10616 args.push_back(nval);
10617 current_type = detail::Classifier::SHORT;
10618 }
10619 std::string dummy1, dummy2;
10620 bool val = false;
10621 if((current_type == detail::Classifier::SHORT && detail::valid_first_char(args.back()[1])) ||
10622 detail::split_long(args.back(), dummy1, dummy2)) {
10623 val = sub->_parse_arg(args, current_type, true);
10624 }
10625
10626 if(val) {
10627 if(!sub->silent_) {
10628 parsed_subcommands_.push_back(sub);
10629 }
10630 // deal with preparsing
10632 _trigger_pre_parse(args.size());
10633 // run the parse complete callback since the subcommand processing is now complete
10634 if(sub->parse_complete_callback_) {
10635 sub->_process_callbacks(CallbackPriority::FirstPreHelp);
10636 sub->_process_help_flags(CallbackPriority::First);
10637 sub->_process_callbacks(CallbackPriority::First);
10638 sub->_process_env();
10639 sub->_process_callbacks(CallbackPriority::PreRequirementsCheckPreHelp);
10640 sub->_process_help_flags(CallbackPriority::PreRequirementsCheck);
10641 sub->_process_callbacks(CallbackPriority::PreRequirementsCheck);
10642 sub->_process_requirements();
10643 sub->_process_callbacks(CallbackPriority::NormalPreHelp);
10644 sub->_process_help_flags(CallbackPriority::Normal);
10645 sub->_process_callbacks(CallbackPriority::Normal);
10646 sub->_process_callbacks(CallbackPriority::LastPreHelp);
10647 sub->_process_help_flags(CallbackPriority::Last);
10648 sub->_process_callbacks(CallbackPriority::Last);
10649 sub->run_callback(false, true);
10650 }
10651 return true;
10652 }
10653 args.pop_back();
10654 args.push_back(v);
10655 }
10656 }
10657 if(local_processing_only) {
10658 return false;
10659 }
10660 // If a subcommand, try the main command
10661 if(parent_ != nullptr && fallthrough_)
10662 return _get_fallthrough_parent()->_parse_arg(args, current_type, false);
10663
10664 // Otherwise, add to missing
10665 args.pop_back();
10666 _move_to_missing(current_type, current);
10667 if(get_prefix_command_mode() == PrefixCommandMode::On) {
10668 while(!args.empty()) {
10669 missing_.emplace_back(detail::Classifier::NONE, args.back());
10670 args.pop_back();
10671 }
10672 } else if(allow_extras_ == ExtrasMode::AssumeSingleArgument) {
10673 if(!args.empty() && _recognize(args.back(), false) == detail::Classifier::NONE) {
10674 _move_to_missing(detail::Classifier::NONE, args.back());
10675 args.pop_back();
10676 }
10677 } else if(allow_extras_ == ExtrasMode::AssumeMultipleArguments) {
10678 while(!args.empty() && _recognize(args.back(), false) == detail::Classifier::NONE) {
10679 _move_to_missing(detail::Classifier::NONE, args.back());
10680 args.pop_back();
10681 }
10682 }
10683 return true;
10684 }
10685
10686 args.pop_back();
10687
10688 // Get a reference to the pointer to make syntax bearable
10689 Option_p &op = *op_ptr;
10691 if(op->get_inject_separator()) {
10692 if(!op->results().empty() && !op->results().back().empty()) {
10693 op->add_result(std::string{});
10694 }
10695 }
10696 if(op->get_trigger_on_parse() && op->current_option_state_ == Option::option_state::callback_run) {
10697 op->clear();
10698 }
10699 int min_num = (std::min)(op->get_type_size_min(), op->get_items_expected_min());
10700 int max_num = op->get_items_expected_max();
10701 // check container like options to limit the argument size to a single type if the allow_extra_flags argument is
10702 // set. 16 is somewhat arbitrary (needs to be at least 4)
10703 if(max_num >= detail::expected_max_vector_size / 16 && !op->get_allow_extra_args()) {
10704 auto tmax = op->get_type_size_max();
10705 max_num = detail::checked_multiply(tmax, op->get_expected_min()) ? tmax : detail::expected_max_vector_size;
10706 }
10707 // Make sure we always eat the minimum for unlimited vectors
10708 int collected = 0; // total number of arguments collected
10709 int result_count = 0; // local variable for number of results in a single arg string
10710 // deal with purely flag like things
10711 if(max_num == 0) {
10712 auto res = op->get_flag_value(arg_name, value);
10713 op->add_result(res);
10714 parse_order_.push_back(op.get());
10715 } else if(!value.empty()) { // --this=value
10716 op->add_result(value, result_count);
10717 parse_order_.push_back(op.get());
10718 collected += result_count;
10719 // -Trest
10720 } else if(!rest.empty()) {
10721 op->add_result(rest, result_count);
10722 parse_order_.push_back(op.get());
10723 rest = "";
10724 collected += result_count;
10725 }
10726
10727 // gather the minimum number of arguments
10728 while(min_num > collected && !args.empty()) {
10729 std::string current_ = args.back();
10730 args.pop_back();
10731 op->add_result(current_, result_count);
10732 parse_order_.push_back(op.get());
10733 collected += result_count;
10734 }
10735
10736 if(min_num > collected) { // if we have run out of arguments and the minimum was not met
10737 throw ArgumentMismatch::TypedAtLeast(op->get_name(), min_num, op->get_type_name());
10738 }
10739
10740 // now check for optional arguments
10741 if(max_num > collected || op->get_allow_extra_args()) { // we allow optional arguments
10742 auto remreqpos = _count_remaining_positionals(true);
10743 // we have met the minimum now optionally check up to the maximum
10744 while((collected < max_num || op->get_allow_extra_args()) && !args.empty() &&
10745 _recognize(args.back(), false) == detail::Classifier::NONE) {
10746 // If any required positionals remain, don't keep eating
10747 if(remreqpos >= args.size()) {
10748 break;
10749 }
10751 std::string arg = args.back();
10752 arg = op->_validate(arg, 0);
10753 if(!arg.empty()) {
10754 break;
10755 }
10756 }
10757 op->add_result(args.back(), result_count);
10758 parse_order_.push_back(op.get());
10759 args.pop_back();
10760 collected += result_count;
10761 }
10762
10763 // Allow -- to end an unlimited list and "eat" it
10764 if(!args.empty() && _recognize(args.back()) == detail::Classifier::POSITIONAL_MARK)
10765 args.pop_back();
10766 // optional flag that didn't receive anything now get the default value
10767 if(min_num == 0 && max_num > 0 && collected == 0) {
10768 auto res = op->get_flag_value(arg_name, std::string{});
10769 op->add_result(res);
10770 parse_order_.push_back(op.get());
10771 }
10772 }
10773 // if we only partially completed a type then add an empty string if allowed for later processing
10774 if(min_num > 0 && (collected % op->get_type_size_max()) != 0) {
10775 if(op->get_type_size_max() != op->get_type_size_min()) {
10776 op->add_result(std::string{});
10777 } else {
10778 throw ArgumentMismatch::PartialType(op->get_name(), op->get_type_size_min(), op->get_type_name());
10779 }
10780 }
10781 if(op->get_trigger_on_parse()) {
10782 op->run_callback();
10783 }
10784 if(!rest.empty()) {
10785 rest = "-" + rest;
10786 args.push_back(rest);
10787 }
10788 return true;
10789}
10790
10791CLI11_INLINE void App::_trigger_pre_parse(std::size_t remaining_args) {
10792 if(!pre_parse_called_) {
10793 pre_parse_called_ = true;
10795 pre_parse_callback_(remaining_args);
10796 }
10797 } else if(immediate_callback_) {
10798 if(!name_.empty()) {
10799 auto pcnt = parsed_;
10800 missing_t extras = std::move(missing_);
10801 clear();
10802 parsed_ = pcnt;
10803 pre_parse_called_ = true;
10804 missing_ = std::move(extras);
10805 }
10806 }
10807}
10808
10809CLI11_INLINE App *App::_get_fallthrough_parent() noexcept {
10810 if(parent_ == nullptr) {
10811 return nullptr;
10812 }
10813 auto *fallthrough_parent = parent_;
10814 while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {
10815 fallthrough_parent = fallthrough_parent->parent_;
10816 }
10817 return fallthrough_parent;
10818}
10819
10820CLI11_INLINE const App *App::_get_fallthrough_parent() const noexcept {
10821 if(parent_ == nullptr) {
10822 return nullptr;
10823 }
10824 const auto *fallthrough_parent = parent_;
10825 while((fallthrough_parent->parent_ != nullptr) && (fallthrough_parent->get_name().empty())) {
10826 fallthrough_parent = fallthrough_parent->parent_;
10827 }
10828 return fallthrough_parent;
10829}
10830
10831CLI11_NODISCARD CLI11_INLINE const std::string &App::_compare_subcommand_names(const App &subcom,
10832 const App &base) const {
10833 static const std::string estring;
10834 if(subcom.disabled_) {
10835 return estring;
10836 }
10837 for(const auto &subc : base.subcommands_) {
10838 if(subc.get() != &subcom) {
10839 if(subc->disabled_) {
10840 continue;
10841 }
10842 if(!subcom.get_name().empty()) {
10843 if(subc->check_name(subcom.get_name())) {
10844 return subcom.get_name();
10845 }
10846 }
10847 if(!subc->get_name().empty()) {
10848 if(subcom.check_name(subc->get_name())) {
10849 return subc->get_name();
10850 }
10851 }
10852 for(const auto &les : subcom.aliases_) {
10853 if(subc->check_name(les)) {
10854 return les;
10855 }
10856 }
10857 // this loop is needed in case of ignore_underscore or ignore_case on one but not the other
10858 for(const auto &les : subc->aliases_) {
10859 if(subcom.check_name(les)) {
10860 return les;
10861 }
10862 }
10863 // if the subcommand is an option group we need to check deeper
10864 if(subc->get_name().empty()) {
10865 const auto &cmpres = _compare_subcommand_names(subcom, *subc);
10866 if(!cmpres.empty()) {
10867 return cmpres;
10868 }
10869 }
10870 // if the test subcommand is an option group we need to check deeper
10871 if(subcom.get_name().empty()) {
10872 const auto &cmpres = _compare_subcommand_names(*subc, subcom);
10873 if(!cmpres.empty()) {
10874 return cmpres;
10875 }
10876 }
10877 }
10878 }
10879 return estring;
10880}
10881
10882inline bool capture_extras(ExtrasMode mode) {
10883 return mode == ExtrasMode::Capture || mode == ExtrasMode::AssumeSingleArgument ||
10884 mode == ExtrasMode::AssumeMultipleArguments;
10885}
10886CLI11_INLINE void App::_move_to_missing(detail::Classifier val_type, const std::string &val) {
10887 if(allow_extras_ == ExtrasMode::ErrorImmediately) {
10888 throw ExtrasError(name_, std::vector<std::string>{val});
10889 }
10890 if(capture_extras(allow_extras_) || subcommands_.empty() || get_prefix_command()) {
10891 if(allow_extras_ != ExtrasMode::Ignore) {
10892 missing_.emplace_back(val_type, val);
10893 }
10894 return;
10895 }
10896 // allow extra arguments to be placed in an option group if it is allowed there
10897 for(auto &subc : subcommands_) {
10898 if(subc->name_.empty() && capture_extras(subc->allow_extras_)) {
10899 subc->missing_.emplace_back(val_type, val);
10900 return;
10901 }
10902 }
10903 if(allow_extras_ != ExtrasMode::Ignore) {
10904 // if we haven't found any place to put them yet put them in missing
10905 missing_.emplace_back(val_type, val);
10906 }
10907}
10908
10909CLI11_INLINE void App::_move_option(Option *opt, App *app) {
10910 if(opt == nullptr) {
10911 throw OptionNotFound("the option is NULL");
10912 }
10913 // verify that the give app is actually a subcommand
10914 bool found = false;
10915 for(auto &subc : subcommands_) {
10916 if(app == subc.get()) {
10917 found = true;
10918 }
10919 }
10920 if(!found) {
10921 throw OptionNotFound("The Given app is not a subcommand");
10922 }
10923
10924 if((help_ptr_ == opt) || (help_all_ptr_ == opt))
10925 throw OptionAlreadyAdded("cannot move help options");
10926
10927 if(config_ptr_ == opt)
10928 throw OptionAlreadyAdded("cannot move config file options");
10929
10930 auto iterator =
10931 std::find_if(std::begin(options_), std::end(options_), [opt](const Option_p &v) { return v.get() == opt; });
10932 if(iterator != std::end(options_)) {
10933 const auto &opt_p = *iterator;
10934 if(std::find_if(std::begin(app->options_), std::end(app->options_), [&opt_p](const Option_p &v) {
10935 return (*v == *opt_p);
10936 }) == std::end(app->options_)) {
10937 // only erase after the insertion was successful
10938 app->options_.push_back(std::move(*iterator));
10939 options_.erase(iterator);
10940 } else {
10941 throw OptionAlreadyAdded("option was not located: " + opt->get_name());
10942 }
10943 } else {
10944 throw OptionNotFound("could not locate the given Option");
10945 }
10946}
10947
10948CLI11_INLINE void TriggerOn(App *trigger_app, App *app_to_enable) {
10949 app_to_enable->enabled_by_default(false);
10950 app_to_enable->disabled_by_default();
10951 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(false); });
10952}
10953
10954CLI11_INLINE void TriggerOn(App *trigger_app, std::vector<App *> apps_to_enable) {
10955 for(auto &app : apps_to_enable) {
10956 app->enabled_by_default(false);
10957 app->disabled_by_default();
10958 }
10959
10960 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
10961 for(const auto &app : apps_to_enable) {
10962 app->disabled(false);
10963 }
10964 });
10965}
10966
10967CLI11_INLINE void TriggerOff(App *trigger_app, App *app_to_enable) {
10968 app_to_enable->disabled_by_default(false);
10969 app_to_enable->enabled_by_default();
10970 trigger_app->preparse_callback([app_to_enable](std::size_t) { app_to_enable->disabled(); });
10971}
10972
10973CLI11_INLINE void TriggerOff(App *trigger_app, std::vector<App *> apps_to_enable) {
10974 for(auto &app : apps_to_enable) {
10975 app->disabled_by_default(false);
10976 app->enabled_by_default();
10977 }
10978
10979 trigger_app->preparse_callback([apps_to_enable](std::size_t) {
10980 for(const auto &app : apps_to_enable) {
10981 app->disabled();
10982 }
10983 });
10984}
10985
10986CLI11_INLINE void deprecate_option(Option *opt, const std::string &replacement) {
10987 Validator deprecate_warning{[opt, replacement](std::string &) {
10988 std::cout << opt->get_name() << " is deprecated please use '" << replacement
10989 << "' instead\n";
10990 return std::string();
10991 },
10992 "DEPRECATED"};
10993 deprecate_warning.application_index(0);
10994 opt->check(deprecate_warning);
10995 if(!replacement.empty()) {
10996 opt->description(opt->get_description() + " DEPRECATED: please use '" + replacement + "' instead");
10997 }
10998}
10999
11000CLI11_INLINE void retire_option(App *app, Option *opt) {
11001 App temp;
11002 auto *option_copy = temp.add_option(opt->get_name(false, true))
11003 ->type_size(opt->get_type_size_min(), opt->get_type_size_max())
11004 ->expected(opt->get_expected_min(), opt->get_expected_max())
11005 ->allow_extra_args(opt->get_allow_extra_args());
11006
11007 app->remove_option(opt);
11008 auto *opt2 = app->add_option(option_copy->get_name(false, true), "option has been retired and has no effect");
11009 opt2->type_name("RETIRED")
11010 ->default_str("RETIRED")
11011 ->type_size(option_copy->get_type_size_min(), option_copy->get_type_size_max())
11012 ->expected(option_copy->get_expected_min(), option_copy->get_expected_max())
11013 ->allow_extra_args(option_copy->get_allow_extra_args());
11014
11015 // LCOV_EXCL_START
11016 // something odd with coverage on new compilers
11017 Validator retired_warning{[opt2](std::string &) {
11018 std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
11019 return std::string();
11020 },
11021 ""};
11022 // LCOV_EXCL_STOP
11023 retired_warning.application_index(0);
11024 opt2->check(retired_warning);
11025}
11026
11027CLI11_INLINE void retire_option(App &app, Option *opt) { retire_option(&app, opt); }
11028
11029CLI11_INLINE void retire_option(App *app, const std::string &option_name) {
11030
11031 auto *opt = app->get_option_no_throw(option_name);
11032 if(opt != nullptr) {
11033 retire_option(app, opt);
11034 return;
11035 }
11036 auto *opt2 = app->add_option(option_name, "option has been retired and has no effect")
11037 ->type_name("RETIRED")
11038 ->expected(0, 1)
11039 ->default_str("RETIRED");
11040 // LCOV_EXCL_START
11041 // something odd with coverage on new compilers
11042 Validator retired_warning{[opt2](std::string &) {
11043 std::cout << "WARNING " << opt2->get_name() << " is retired and has no effect\n";
11044 return std::string();
11045 },
11046 ""};
11047 // LCOV_EXCL_STOP
11048 retired_warning.application_index(0);
11049 opt2->check(retired_warning);
11050}
11051
11052CLI11_INLINE void retire_option(App &app, const std::string &option_name) { retire_option(&app, option_name); }
11053
11054namespace FailureMessage {
11055
11056CLI11_INLINE std::string simple(const App *app, const Error &e) {
11057 std::string header = std::string(e.what()) + "\n";
11058 std::vector<std::string> names;
11059
11060 // Collect names
11061 if(app->get_help_ptr() != nullptr)
11062 names.push_back(app->get_help_ptr()->get_name());
11063
11064 if(app->get_help_all_ptr() != nullptr)
11065 names.push_back(app->get_help_all_ptr()->get_name());
11066
11067 // If any names found, suggest those
11068 if(!names.empty())
11069 header += "Run with " + detail::join(names, " or ") + " for more information.\n";
11070
11071 return header;
11072}
11073
11074CLI11_INLINE std::string help(const App *app, const Error &e) {
11075 std::string header = std::string("ERROR: ") + e.get_name() + ": " + e.what() + "\n";
11076 header += app->help();
11077 return header;
11078}
11079
11080} // namespace FailureMessage
11081
11082
11083
11084
11085namespace detail {
11086
11087std::string convert_arg_for_ini(const std::string &arg,
11088 char stringQuote = '"',
11089 char literalQuote = '\'',
11090 bool disable_multi_line = false);
11091
11093std::string ini_join(const std::vector<std::string> &args,
11094 char sepChar = ',',
11095 char arrayStart = '[',
11096 char arrayEnd = ']',
11097 char stringQuote = '"',
11098 char literalQuote = '\'');
11099
11100void clean_name_string(std::string &name, const std::string &keyChars);
11101
11102std::vector<std::string> generate_parents(const std::string &section, std::string &name, char parentSeparator);
11103
11105void checkParentSegments(std::vector<ConfigItem> &output, const std::string &currentSection, char parentSeparator);
11106} // namespace detail
11107
11108
11109
11110
11111static constexpr auto multiline_literal_quote = R"(''')";
11112static constexpr auto multiline_string_quote = R"(""")";
11113
11114namespace detail {
11115
11116CLI11_INLINE bool is_printable(const std::string &test_string) {
11117 return std::all_of(test_string.begin(), test_string.end(), [](char x) {
11118 return (isprint(static_cast<unsigned char>(x)) != 0 || x == '\n' || x == '\t');
11119 });
11120}
11121
11122CLI11_INLINE std::string
11123convert_arg_for_ini(const std::string &arg, char stringQuote, char literalQuote, bool disable_multi_line) {
11124 if(arg.empty()) {
11125 return std::string(2, stringQuote);
11126 }
11127 // some specifically supported strings
11128 if(arg == "true" || arg == "false" || arg == "nan" || arg == "inf") {
11129 return arg;
11130 }
11131 // floating point conversion can convert some hex codes, but don't try that here
11132 if(arg.compare(0, 2, "0x") != 0 && arg.compare(0, 2, "0X") != 0) {
11133 using CLI::detail::lexical_cast;
11134 double val = 0.0;
11135 if(lexical_cast(arg, val)) {
11136 if(arg.find_first_not_of("0123456789.-+eE") == std::string::npos) {
11137 return arg;
11138 }
11139 }
11140 }
11141 // just quote a single non numeric character
11142 if(arg.size() == 1) {
11143 if(isprint(static_cast<unsigned char>(arg.front())) == 0) {
11144 return binary_escape_string(arg);
11145 }
11146 if(arg == "'") {
11147 return std::string(1, stringQuote) + "'" + stringQuote;
11148 }
11149 return std::string(1, literalQuote) + arg + literalQuote;
11150 }
11151 // handle hex, binary or octal arguments
11152 if(arg.front() == '0') {
11153 if(arg[1] == 'x') {
11154 if(std::all_of(arg.begin() + 2, arg.end(), [](char x) {
11155 return (x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f');
11156 })) {
11157 return arg;
11158 }
11159 } else if(arg[1] == 'o') {
11160 if(std::all_of(arg.begin() + 2, arg.end(), [](char x) { return (x >= '0' && x <= '7'); })) {
11161 return arg;
11162 }
11163 } else if(arg[1] == 'b') {
11164 if(std::all_of(arg.begin() + 2, arg.end(), [](char x) { return (x == '0' || x == '1'); })) {
11165 return arg;
11166 }
11167 }
11168 }
11169 if(!is_printable(arg)) {
11170 return binary_escape_string(arg);
11171 }
11172 if(detail::has_escapable_character(arg)) {
11173 if(arg.size() > 100 && !disable_multi_line) {
11174 if(arg.find(multiline_literal_quote) != std::string::npos) {
11175 return binary_escape_string(arg, true);
11176 }
11177 std::string return_string{multiline_literal_quote};
11178 return_string.reserve(7 + arg.size());
11179 if(arg.front() == '\n' || arg.front() == '\r') {
11180 return_string.push_back('\n');
11181 }
11182 return_string.append(arg);
11183 if(arg.back() == '\n' || arg.back() == '\r') {
11184 return_string.push_back('\n');
11185 }
11186 return_string.append(multiline_literal_quote, 3);
11187 return return_string;
11188 }
11189 return std::string(1, stringQuote) + detail::add_escaped_characters(arg) + stringQuote;
11190 }
11191 return std::string(1, stringQuote) + arg + stringQuote;
11192}
11193
11194CLI11_INLINE std::string ini_join(const std::vector<std::string> &args,
11195 char sepChar,
11196 char arrayStart,
11197 char arrayEnd,
11198 char stringQuote,
11199 char literalQuote) {
11200 bool disable_multi_line{false};
11201 std::string joined;
11202 if(args.size() > 1 && arrayStart != '\0') {
11203 joined.push_back(arrayStart);
11204 disable_multi_line = true;
11205 }
11206 std::size_t start = 0;
11207 for(const auto &arg : args) {
11208 if(start++ > 0) {
11209 joined.push_back(sepChar);
11210 if(!std::isspace<char>(sepChar, std::locale())) {
11211 joined.push_back(' ');
11212 }
11213 }
11214 joined.append(convert_arg_for_ini(arg, stringQuote, literalQuote, disable_multi_line));
11215 }
11216 if(args.size() > 1 && arrayEnd != '\0') {
11217 joined.push_back(arrayEnd);
11218 }
11219 return joined;
11220}
11221
11222CLI11_INLINE std::vector<std::string>
11223generate_parents(const std::string &section, std::string &name, char parentSeparator) {
11224 std::vector<std::string> parents;
11225 if(detail::to_lower(section) != "default") {
11226 if(section.find(parentSeparator) != std::string::npos) {
11227 parents = detail::split_up(section, parentSeparator);
11228 } else {
11229 parents = {section};
11230 }
11231 }
11232 if(name.find(parentSeparator) != std::string::npos) {
11233 std::vector<std::string> plist = detail::split_up(name, parentSeparator);
11234 name = plist.back();
11235 plist.pop_back();
11236 parents.insert(parents.end(), plist.begin(), plist.end());
11237 }
11238 // clean up quotes on the parents
11239 try {
11240 detail::remove_quotes(parents);
11241 } catch(const std::invalid_argument &iarg) {
11242 throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError);
11243 }
11244 return parents;
11245}
11246
11247CLI11_INLINE void
11248checkParentSegments(std::vector<ConfigItem> &output, const std::string &currentSection, char parentSeparator) {
11249
11250 std::string estring;
11251 auto parents = detail::generate_parents(currentSection, estring, parentSeparator);
11252 if(!output.empty() && output.back().name == "--") {
11253 std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
11254 while(output.back().parents.size() >= msize) {
11255 output.push_back(output.back());
11256 output.back().parents.pop_back();
11257 }
11258
11259 if(parents.size() > 1) {
11260 std::size_t common = 0;
11261 std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
11262 for(std::size_t ii = 0; ii < mpair; ++ii) {
11263 if(output.back().parents[ii] != parents[ii]) {
11264 break;
11265 }
11266 ++common;
11267 }
11268 if(common == mpair) {
11269 output.pop_back();
11270 } else {
11271 while(output.back().parents.size() > common + 1) {
11272 output.push_back(output.back());
11273 output.back().parents.pop_back();
11274 }
11275 }
11276 for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
11277 output.emplace_back();
11278 output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
11279 output.back().name = "++";
11280 }
11281 }
11282 } else if(parents.size() > 1) {
11283 for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
11284 output.emplace_back();
11285 output.back().parents.assign(parents.begin(), parents.begin() + static_cast<std::ptrdiff_t>(ii) + 1);
11286 output.back().name = "++";
11287 }
11288 }
11289
11290 // insert a section end which is just an empty items_buffer
11291 output.emplace_back();
11292 output.back().parents = std::move(parents);
11293 output.back().name = "++";
11294}
11295
11297CLI11_INLINE bool hasMLString(std::string const &fullString, char check) {
11298 if(fullString.length() < 3) {
11299 return false;
11300 }
11301 auto it = fullString.rbegin();
11302 return (*it == check) && (*(it + 1) == check) && (*(it + 2) == check);
11303}
11304
11306inline auto find_matching_config(std::vector<ConfigItem> &items,
11307 const std::vector<std::string> &parents,
11308 const std::string &name,
11309 bool fullSearch) -> decltype(items.begin()) {
11310 if(items.empty()) {
11311 return items.end();
11312 }
11313 auto search = items.end() - 1;
11314 do {
11315 if(search->parents == parents && search->name == name) {
11316 return search;
11317 }
11318 if(search == items.begin()) {
11319 break;
11320 }
11321 --search;
11322 } while(fullSearch);
11323 return items.end();
11324}
11325} // namespace detail
11326
11327inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) const {
11328 std::string line;
11329 std::string buffer;
11330 std::string currentSection = "default";
11331 std::string previousSection = "default";
11332 std::vector<ConfigItem> output;
11333 bool isDefaultArray = (arrayStart == '[' && arrayEnd == ']' && arraySeparator == ',');
11334 bool isINIArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
11335 bool inSection{false};
11336 bool inMLineComment{false};
11337 bool inMLineValue{false};
11338
11339 char aStart = (isINIArray) ? '[' : arrayStart;
11340 char aEnd = (isINIArray) ? ']' : arrayEnd;
11341 char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
11342 int currentSectionIndex{0};
11343
11344 std::string line_sep_chars{parentSeparatorChar, commentChar, valueDelimiter};
11345 while(getline(input, buffer)) {
11346 std::vector<std::string> items_buffer;
11347 std::string name;
11348 line = detail::trim_copy(buffer);
11349 std::size_t len = line.length();
11350 // lines have to be at least 3 characters to have any meaning to CLI just skip the rest
11351 if(len < 3) {
11352 continue;
11353 }
11354 if(line.compare(0, 3, multiline_string_quote) == 0 || line.compare(0, 3, multiline_literal_quote) == 0) {
11355 inMLineComment = true;
11356 auto cchar = line.front();
11357 while(inMLineComment) {
11358 if(getline(input, line)) {
11359 detail::trim(line);
11360 } else {
11361 break;
11362 }
11363 if(detail::hasMLString(line, cchar)) {
11364 inMLineComment = false;
11365 }
11366 }
11367 continue;
11368 }
11369 if(line.front() == '[' && line.back() == ']') {
11370 if(currentSection != "default") {
11371 // insert a section end which is just an empty items_buffer
11372 output.emplace_back();
11373 output.back().parents = detail::generate_parents(currentSection, name, parentSeparatorChar);
11374 output.back().name = "--";
11375 }
11376 currentSection = line.substr(1, len - 2);
11377 // deal with double brackets for TOML
11378 if(currentSection.size() > 1 && currentSection.front() == '[' && currentSection.back() == ']') {
11379 currentSection = currentSection.substr(1, currentSection.size() - 2);
11380 }
11381 if(detail::to_lower(currentSection) == "default") {
11382 currentSection = "default";
11383 } else {
11384 detail::checkParentSegments(output, currentSection, parentSeparatorChar);
11385 }
11386 inSection = false;
11387 if(currentSection == previousSection) {
11388 ++currentSectionIndex;
11389 } else {
11390 currentSectionIndex = 0;
11391 previousSection = currentSection;
11392 }
11393 continue;
11394 }
11395
11396 // comment lines
11397 if(line.front() == ';' || line.front() == '#' || line.front() == commentChar) {
11398 continue;
11399 }
11400 std::size_t search_start = 0;
11401 if(line.find_first_of("\"'`") != std::string::npos) {
11402 while(search_start < line.size()) {
11403 auto test_char = line[search_start];
11404 if(test_char == '\"' || test_char == '\'' || test_char == '`') {
11405 search_start = detail::close_sequence(line, search_start, line[search_start]);
11406 ++search_start;
11407 } else if(test_char == valueDelimiter || test_char == commentChar) {
11408 --search_start;
11409 break;
11410 } else if(test_char == ' ' || test_char == '\t' || test_char == parentSeparatorChar) {
11411 ++search_start;
11412 } else {
11413 search_start = line.find_first_of(line_sep_chars, search_start);
11414 }
11415 }
11416 }
11417 // Find = in string, split and recombine
11418 auto delimiter_pos = line.find_first_of(valueDelimiter, search_start + 1);
11419 auto comment_pos = line.find_first_of(commentChar, search_start);
11420 if(comment_pos < delimiter_pos) {
11421 delimiter_pos = std::string::npos;
11422 }
11423 if(delimiter_pos != std::string::npos) {
11424
11425 name = detail::trim_copy(line.substr(0, delimiter_pos));
11426 std::string item = detail::trim_copy(line.substr(delimiter_pos + 1, std::string::npos));
11427 bool mlquote =
11428 (item.compare(0, 3, multiline_literal_quote) == 0 || item.compare(0, 3, multiline_string_quote) == 0);
11429 if(!mlquote && comment_pos != std::string::npos) {
11430 auto citems = detail::split_up(item, commentChar);
11431 item = detail::trim_copy(citems.front());
11432 }
11433 if(mlquote) {
11434 // multiline string
11435 auto keyChar = item.front();
11436 item = buffer.substr(delimiter_pos + 1, std::string::npos);
11437 detail::ltrim(item);
11438 item.erase(0, 3);
11439 inMLineValue = true;
11440 bool lineExtension{false};
11441 bool firstLine = true;
11442 if(!item.empty() && item.back() == '\\' && keyChar == '\"') {
11443 item.pop_back();
11444 lineExtension = true;
11445 } else if(detail::hasMLString(item, keyChar)) {
11446 // deal with the first line closing the multiline literal
11447 item.pop_back();
11448 item.pop_back();
11449 item.pop_back();
11450 if(keyChar == '\"') {
11451 try {
11452 item = detail::remove_escaped_characters(item);
11453 } catch(const std::invalid_argument &iarg) {
11454 throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError);
11455 }
11456 }
11457 inMLineValue = false;
11458 }
11459 while(inMLineValue) {
11460 std::string l2;
11461 if(!std::getline(input, l2)) {
11462 break;
11463 }
11464 line = l2;
11465 detail::rtrim(line);
11466 if(detail::hasMLString(line, keyChar)) {
11467 line.pop_back();
11468 line.pop_back();
11469 line.pop_back();
11470 if(lineExtension) {
11471 detail::ltrim(line);
11472 } else if(!(firstLine && item.empty())) {
11473 item.push_back('\n');
11474 }
11475 firstLine = false;
11476 item += line;
11477 inMLineValue = false;
11478 if(!item.empty() && item.back() == '\n') {
11479 item.pop_back();
11480 }
11481 if(keyChar == '\"') {
11482 try {
11483 item = detail::remove_escaped_characters(item);
11484 } catch(const std::invalid_argument &iarg) {
11485 throw CLI::ParseError(iarg.what(), CLI::ExitCodes::InvalidError);
11486 }
11487 }
11488 } else {
11489 if(lineExtension) {
11490 detail::trim(l2);
11491 } else if(!(firstLine && item.empty())) {
11492 item.push_back('\n');
11493 }
11494 lineExtension = false;
11495 firstLine = false;
11496 if(!l2.empty() && l2.back() == '\\' && keyChar == '\"') {
11497 lineExtension = true;
11498 l2.pop_back();
11499 }
11500 item += l2;
11501 }
11502 }
11503 items_buffer = {item};
11504 } else if(!item.empty() && item.front() == aStart) {
11505 for(std::string multiline; item.back() != aEnd && std::getline(input, multiline);) {
11506 detail::trim(multiline);
11507 item += multiline;
11508 }
11509 if(item.back() == aEnd) {
11510 items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
11511 } else {
11512 items_buffer = detail::split_up(item.substr(1, std::string::npos), aSep);
11513 }
11514 } else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
11515 items_buffer = detail::split_up(item, aSep);
11516 } else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
11517 items_buffer = detail::split_up(item, '\0');
11518 } else {
11519 items_buffer = {item};
11520 }
11521 } else {
11522 name = detail::trim_copy(line.substr(0, comment_pos));
11523 items_buffer = {"true"};
11524 }
11525 std::vector<std::string> parents;
11526 try {
11527 parents = detail::generate_parents(currentSection, name, parentSeparatorChar);
11528 detail::process_quoted_string(name, '"', '\'', true);
11529 // clean up quotes on the items and check for escaped strings
11530 for(auto &it : items_buffer) {
11531 detail::process_quoted_string(it, stringQuote, literalQuote);
11532 }
11533 } catch(const std::invalid_argument &ia) {
11534 throw CLI::ParseError(ia.what(), CLI::ExitCodes::InvalidError);
11535 }
11536
11537 if(parents.size() > maximumLayers) {
11538 continue;
11539 }
11540 if(!configSection.empty() && !inSection) {
11541 if(parents.empty() || parents.front() != configSection) {
11542 continue;
11543 }
11544 if(configIndex >= 0 && currentSectionIndex != configIndex) {
11545 continue;
11546 }
11547 parents.erase(parents.begin());
11548 inSection = true;
11549 }
11550 auto match = detail::find_matching_config(output, parents, name, allowMultipleDuplicateFields);
11551 if(match != output.end()) {
11552 if((match->inputs.size() > 1 && items_buffer.size() > 1) || allowMultipleDuplicateFields) {
11553 // insert a separator if one is not already present
11554 if(!(match->inputs.back().empty() || items_buffer.front().empty() || match->inputs.back() == "%%" ||
11555 items_buffer.front() == "%%")) {
11556 match->inputs.emplace_back("%%");
11557 match->multiline = true;
11558 }
11559 }
11560 match->inputs.insert(match->inputs.end(), items_buffer.begin(), items_buffer.end());
11561 } else {
11562 output.emplace_back();
11563 output.back().parents = std::move(parents);
11564 output.back().name = std::move(name);
11565 output.back().inputs = std::move(items_buffer);
11566 }
11567 }
11568 if(currentSection != "default") {
11569 // insert a section end which is just an empty items_buffer
11570 std::string ename;
11571 output.emplace_back();
11572 output.back().parents = detail::generate_parents(currentSection, ename, parentSeparatorChar);
11573 output.back().name = "--";
11574 while(output.back().parents.size() > 1) {
11575 output.push_back(output.back());
11576 output.back().parents.pop_back();
11577 }
11578 }
11579 return output;
11580}
11581
11582CLI11_INLINE std::string &clean_name_string(std::string &name, const std::string &keyChars) {
11583 if(name.find_first_of(keyChars) != std::string::npos || (name.front() == '[' && name.back() == ']') ||
11584 (name.find_first_of("'`\"\\") != std::string::npos)) {
11585 if(name.find_first_of('\'') == std::string::npos) {
11586 name.insert(0, 1, '\'');
11587 name.push_back('\'');
11588 } else {
11589 if(detail::has_escapable_character(name)) {
11590 name = detail::add_escaped_characters(name);
11591 }
11592 name.insert(0, 1, '\"');
11593 name.push_back('\"');
11594 }
11595 }
11596 return name;
11597}
11598
11599CLI11_INLINE std::string
11600ConfigBase::to_config(const App *app, bool default_also, bool write_description, std::string prefix) const {
11601 std::stringstream out;
11602 std::string commentLead;
11603 commentLead.push_back(commentChar);
11604 commentLead.push_back(' ');
11605
11606 std::string commentTest = "#;";
11607 commentTest.push_back(commentChar);
11608 commentTest.push_back(parentSeparatorChar);
11609
11610 std::string keyChars = commentTest;
11611 keyChars.push_back(literalQuote);
11612 keyChars.push_back(stringQuote);
11613 keyChars.push_back(arrayStart);
11614 keyChars.push_back(arrayEnd);
11615 keyChars.push_back(valueDelimiter);
11616 keyChars.push_back(arraySeparator);
11617
11618 std::vector<std::string> groups = app->get_groups();
11619 bool defaultUsed = false;
11620 groups.insert(groups.begin(), std::string("OPTIONS"));
11621
11622 for(auto &group : groups) {
11623 if(group == "OPTIONS" || group.empty()) {
11624 if(defaultUsed) {
11625 continue;
11626 }
11627 defaultUsed = true;
11628 }
11629 if(write_description && group != "OPTIONS" && !group.empty()) {
11630 out << '\n' << commentChar << commentLead << group << " Options\n";
11631 }
11632 for(const Option *opt : app->get_options({})) {
11633 // Only process options that are configurable
11634 if(opt->get_configurable()) {
11635 if(opt->get_group() != group) {
11636 if(!(group == "OPTIONS" && opt->get_group().empty())) {
11637 continue;
11638 }
11639 }
11640 std::string single_name = opt->get_single_name();
11641 if(single_name.empty()) {
11642 continue;
11643 }
11644
11645 auto results = opt->reduced_results();
11646 if(results.size() > 1 && opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Reverse) {
11647 std::reverse(results.begin(), results.end());
11648 }
11649 if(opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Sum && opt->count() >= 1 &&
11650 results.size() == 1) {
11651 // if the multi option policy is sum then there is a possibility of incorrect fields being produced
11652 // best to just use the original data for config files
11653 auto pos = opt->_validate(results[0], 0);
11654 if(!pos.empty()) {
11655 results = opt->results();
11656 }
11657 }
11658 if(opt->get_multi_option_policy() == CLI::MultiOptionPolicy::Join && opt->count() > 1) {
11659 char delim = opt->get_delimiter();
11660 if(delim == '\0') {
11661 // this branch deals with a situation where the output would not be readable by a config file
11662 results = opt->results();
11663 } else {
11664 // this branch deals with the case of the strings containing the delimiter itself or empty
11665 // strings which would be interpreted incorrectly
11666 auto delim_count = std::count(results[0].begin(), results[0].end(), delim);
11667 if(results[0].back() == delim ||
11668 static_cast<decltype(delim_count)>(opt->count()) < delim_count - 1 ||
11669 results[0].find(std::string(2, delim)) != std::string::npos) {
11670 results = opt->results();
11671 }
11672 }
11673 }
11674 std::string value;
11675
11676 if(opt->count() == 1 && results.size() == 2 && results.front() == "{}" && results.back() == "%%") {
11677 // there is a catch to allow for {} to used as as string in the output
11678 // it will append a sequence terminator to the output so the lexical conversion handles it
11679 // correctly but that is meant for config files so when outputting for a config file we need to
11680 // makes sure to get the correct output
11681 value = "\"{}\"";
11682 } else {
11683 value = detail::ini_join(results, arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
11684 }
11685
11686 bool isDefault = false;
11687 if(value.empty() && default_also) {
11688 if(!opt->get_default_str().empty()) {
11689 results_t res;
11690 opt->results(res);
11691 value = detail::ini_join(res, arraySeparator, arrayStart, arrayEnd, stringQuote, literalQuote);
11692 } else if(opt->get_expected_min() == 0) {
11693 value = "false";
11694 } else if(opt->get_run_callback_for_default() || !opt->get_required()) {
11695 value = "\"\""; // empty string default value
11696 } else {
11697 value = "\"<REQUIRED>\"";
11698 }
11699 isDefault = true;
11700 }
11701
11702 if(!value.empty()) {
11703 if(!opt->get_fnames().empty()) {
11704 try {
11705 value = opt->get_flag_value(single_name, value);
11706 } catch(const CLI::ArgumentMismatch &) {
11707 bool valid{false};
11708 for(const auto &test_name : opt->get_fnames()) {
11709 try {
11710 value = opt->get_flag_value(test_name, value);
11711 single_name = test_name;
11712 valid = true;
11713 } catch(const CLI::ArgumentMismatch &) {
11714 continue;
11715 }
11716 }
11717 if(!valid) {
11718 value = detail::ini_join(
11720 }
11721 }
11722 }
11723 if(write_description && opt->has_description()) {
11724 if(out.tellp() != std::streampos(0)) {
11725 out << '\n';
11726 }
11727 out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
11728 }
11729 clean_name_string(single_name, keyChars);
11730
11731 std::string name = prefix + single_name;
11732 if(commentDefaultsBool && isDefault) {
11733 name = commentChar + name;
11734 }
11735 out << name << valueDelimiter << value << '\n';
11736 }
11737 }
11738 }
11739 }
11740
11741 auto subcommands = app->get_subcommands({});
11742 for(const App *subcom : subcommands) {
11743 if(subcom->get_name().empty()) {
11744 if(!default_also && (subcom->count_all() == 0)) {
11745 continue;
11746 }
11747 if(write_description && !subcom->get_group().empty()) {
11748 out << '\n' << commentLead << subcom->get_group() << " Options\n";
11749 }
11750 /*if (!prefix.empty() || app->get_parent() == nullptr) {
11751 out << '[' << prefix << "___"<< subcom->get_group() << "]\n";
11752 } else {
11753 std::string subname = app->get_name() + parentSeparatorChar + "___"+subcom->get_group();
11754 const auto *p = app->get_parent();
11755 while(p->get_parent() != nullptr) {
11756 subname = p->get_name() + parentSeparatorChar +subname;
11757 p = p->get_parent();
11758 }
11759 out << '[' << subname << "]\n";
11760 }
11761 */
11762 out << to_config(subcom, default_also, write_description, prefix);
11763 }
11764 }
11765
11766 for(const App *subcom : subcommands) {
11767 if(!subcom->get_name().empty()) {
11768 if(!default_also && (subcom->count_all() == 0)) {
11769 continue;
11770 }
11771 std::string subname = subcom->get_name();
11772 clean_name_string(subname, keyChars);
11773
11774 if(subcom->get_configurable() && (default_also || app->got_subcommand(subcom))) {
11775 if(!prefix.empty() || app->get_parent() == nullptr) {
11776
11777 out << '[' << prefix << subname << "]\n";
11778 } else {
11779 std::string appname = app->get_name();
11780 clean_name_string(appname, keyChars);
11781 subname = appname + parentSeparatorChar + subname;
11782 const auto *p = app->get_parent();
11783 while(p->get_parent() != nullptr) {
11784 std::string pname = p->get_name();
11785 clean_name_string(pname, keyChars);
11786 subname = pname + parentSeparatorChar + subname;
11787 p = p->get_parent();
11788 }
11789 out << '[' << subname << "]\n";
11790 }
11791 out << to_config(subcom, default_also, write_description, "");
11792 } else {
11793 out << to_config(subcom, default_also, write_description, prefix + subname + parentSeparatorChar);
11794 }
11795 }
11796 }
11797
11798 if(write_description && !out.str().empty()) {
11799 std::string outString =
11800 commentChar + commentLead + detail::fix_newlines(commentChar + commentLead, app->get_description()) + '\n';
11801 return outString + out.str();
11802 }
11803 return out.str();
11804}
11805
11806
11807
11808
11809
11810
11811CLI11_INLINE std::string
11812Formatter::make_group(std::string group, bool is_positional, std::vector<const Option *> opts) const {
11813 std::stringstream out;
11814
11815 out << "\n" << group << ":\n";
11816 for(const Option *opt : opts) {
11817 out << make_option(opt, is_positional);
11818 }
11819
11820 return out.str();
11821}
11822
11823CLI11_INLINE std::string Formatter::make_positionals(const App *app) const {
11824 std::vector<const Option *> opts =
11825 app->get_options([](const Option *opt) { return !opt->get_group().empty() && opt->get_positional(); });
11826
11827 if(opts.empty())
11828 return {};
11829
11830 return make_group(get_label("POSITIONALS"), true, opts);
11831}
11832
11833CLI11_INLINE std::string Formatter::make_groups(const App *app, AppFormatMode mode) const {
11834 std::stringstream out;
11835 std::vector<std::string> groups = app->get_groups();
11836
11837 // Options
11838 for(const std::string &group : groups) {
11839 std::vector<const Option *> opts = app->get_options([app, mode, &group](const Option *opt) {
11840 return opt->get_group() == group // Must be in the right group
11841 && opt->nonpositional() // Must not be a positional
11842 && (mode != AppFormatMode::Sub // If mode is Sub, then
11843 || (app->get_help_ptr() != opt // Ignore help pointer
11844 && app->get_help_all_ptr() != opt)); // Ignore help all pointer
11845 });
11846 if(!group.empty() && !opts.empty()) {
11847 out << make_group(group, false, opts);
11848
11849 // Removed double newline between groups for consistency of help text
11850 // if(group != groups.back())
11851 // out << "\n";
11852 }
11853 }
11854
11855 return out.str();
11856}
11857
11858CLI11_INLINE std::string Formatter::make_description(const App *app) const {
11859 std::string desc = app->get_description();
11860 auto min_options = app->get_require_option_min();
11861 auto max_options = app->get_require_option_max();
11862
11863 if(app->get_required()) {
11864 desc += " " + get_label("REQUIRED") + " ";
11865 }
11866
11867 if(min_options > 0) {
11868 if(max_options == min_options) {
11869 desc += " \n[Exactly " + std::to_string(min_options) + " of the following options are required]";
11870 } else if(max_options > 0) {
11871 desc += " \n[Between " + std::to_string(min_options) + " and " + std::to_string(max_options) +
11872 " of the following options are required]";
11873 } else {
11874 desc += " \n[At least " + std::to_string(min_options) + " of the following options are required]";
11875 }
11876 } else if(max_options > 0) {
11877 desc += " \n[At most " + std::to_string(max_options) + " of the following options are allowed]";
11878 }
11879
11880 return (!desc.empty()) ? desc + "\n\n" : std::string{};
11881}
11882
11883CLI11_INLINE std::string Formatter::make_usage(const App *app, std::string name) const {
11884 std::string usage = app->get_usage();
11885 if(!usage.empty()) {
11886 return usage + "\n\n";
11887 }
11888
11889 std::stringstream out;
11890 out << '\n';
11891
11892 if(name.empty())
11893 out << get_label("Usage") << ':';
11894 else
11895 out << name;
11896
11897 std::vector<std::string> groups = app->get_groups();
11898
11899 // Print an Options badge if any options exist
11900 std::vector<const Option *> non_pos_options =
11901 app->get_options([](const Option *opt) { return opt->nonpositional(); });
11902 if(!non_pos_options.empty())
11903 out << " [" << get_label("OPTIONS") << "]";
11904
11905 // Positionals need to be listed here
11906 std::vector<const Option *> positionals = app->get_options([](const Option *opt) { return opt->get_positional(); });
11907
11908 // Print out positionals if any are left
11909 if(!positionals.empty()) {
11910 // Convert to help names
11911 std::vector<std::string> positional_names(positionals.size());
11912 std::transform(positionals.begin(), positionals.end(), positional_names.begin(), [this](const Option *opt) {
11913 return make_option_usage(opt);
11914 });
11915
11916 out << " " << detail::join(positional_names, " ");
11917 }
11918
11919 // Add a marker if subcommands are expected or optional
11920 if(!app->get_subcommands(
11921 [](const CLI::App *subc) { return ((!subc->get_disabled()) && (!subc->get_name().empty())); })
11922 .empty()) {
11923 out << ' ' << (app->get_require_subcommand_min() == 0 ? "[" : "")
11924 << get_label(app->get_require_subcommand_max() == 1 ? "SUBCOMMAND" : "SUBCOMMANDS")
11925 << (app->get_require_subcommand_min() == 0 ? "]" : "");
11926 }
11927
11928 out << "\n\n";
11929
11930 return out.str();
11931}
11932
11933CLI11_INLINE std::string Formatter::make_footer(const App *app) const {
11934 std::string footer = app->get_footer();
11935 if(footer.empty()) {
11936 return std::string{};
11937 }
11938 return '\n' + footer + '\n';
11939}
11940
11941CLI11_INLINE std::string Formatter::make_help(const App *app, std::string name, AppFormatMode mode) const {
11942 // This immediately forwards to the make_expanded method. This is done this way so that subcommands can
11943 // have overridden formatters
11944 if(mode == AppFormatMode::Sub)
11945 return make_expanded(app, mode);
11946
11947 std::stringstream out;
11948 if((app->get_name().empty()) && (app->get_parent() != nullptr)) {
11949 if(app->get_group() != "SUBCOMMANDS") {
11950 out << app->get_group() << ':';
11951 }
11952 }
11954 detail::streamOutAsParagraph(
11955 out, make_description(app), description_paragraph_width_, ""); // Format description as paragraph
11956 } else {
11957 out << make_description(app) << '\n';
11958 }
11959 out << make_usage(app, name);
11960 out << make_positionals(app);
11961 out << make_groups(app, mode);
11962 out << make_subcommands(app, mode);
11963 std::string footer_string = make_footer(app);
11964
11966 detail::streamOutAsParagraph(out, footer_string, footer_paragraph_width_); // Format footer as paragraph
11967 } else {
11968 out << footer_string;
11969 }
11970
11971 return out.str();
11972}
11973
11974CLI11_INLINE std::string Formatter::make_subcommands(const App *app, AppFormatMode mode) const {
11975 std::stringstream out;
11976
11977 std::vector<const App *> subcommands = app->get_subcommands({});
11978
11979 // Make a list in definition order of the groups seen
11980 std::vector<std::string> subcmd_groups_seen;
11981 for(const App *com : subcommands) {
11982 if(com->get_name().empty()) {
11983 if(!com->get_group().empty() && com->get_group().front() != '+') {
11984 out << make_expanded(com, mode);
11985 }
11986 continue;
11987 }
11988 std::string group_key = com->get_group();
11989 if(!group_key.empty() &&
11990 std::find_if(subcmd_groups_seen.begin(), subcmd_groups_seen.end(), [&group_key](std::string a) {
11991 return detail::to_lower(a) == detail::to_lower(group_key);
11992 }) == subcmd_groups_seen.end())
11993 subcmd_groups_seen.push_back(group_key);
11994 }
11995
11996 // For each group, filter out and print subcommands
11997 for(const std::string &group : subcmd_groups_seen) {
11998 out << '\n' << group << ":\n";
11999 std::vector<const App *> subcommands_group = app->get_subcommands(
12000 [&group](const App *sub_app) { return detail::to_lower(sub_app->get_group()) == detail::to_lower(group); });
12001 for(const App *new_com : subcommands_group) {
12002 if(new_com->get_name().empty())
12003 continue;
12004 if(mode != AppFormatMode::All) {
12005 out << make_subcommand(new_com);
12006 } else {
12007 out << new_com->help(new_com->get_name(), AppFormatMode::Sub);
12008 out << '\n';
12009 }
12010 }
12011 }
12012
12013 return out.str();
12014}
12015
12016CLI11_INLINE std::string Formatter::make_subcommand(const App *sub) const {
12017 std::stringstream out;
12018 std::string name = " " + sub->get_display_name(true) + (sub->get_required() ? " " + get_label("REQUIRED") : "");
12019
12020 out << std::setw(static_cast<int>(column_width_)) << std::left << name;
12021 detail::streamOutAsParagraph(
12022 out, sub->get_description(), right_column_width_, std::string(column_width_, ' '), true);
12023 out << '\n';
12024 return out.str();
12025}
12026
12027CLI11_INLINE std::string Formatter::make_expanded(const App *sub, AppFormatMode mode) const {
12028 std::stringstream out;
12029 out << sub->get_display_name(true) << '\n';
12030
12032 detail::streamOutAsParagraph(
12033 out, make_description(sub), description_paragraph_width_, " "); // Format description as paragraph
12034 } else {
12035 out << make_description(sub) << '\n';
12036 }
12037
12038 if(sub->get_name().empty() && !sub->get_aliases().empty()) {
12039 detail::format_aliases(out, sub->get_aliases(), column_width_ + 2);
12040 }
12041
12042 out << make_positionals(sub);
12043 out << make_groups(sub, mode);
12044 out << make_subcommands(sub, mode);
12045 std::string footer_string = make_footer(sub);
12046
12047 if(mode == AppFormatMode::Sub && !footer_string.empty()) {
12048 const auto *parent = sub->get_parent();
12049 std::string parent_footer = (parent != nullptr) ? make_footer(sub->get_parent()) : std::string{};
12050 if(footer_string == parent_footer) {
12051 footer_string = "";
12052 }
12053 }
12054 if(!footer_string.empty()) {
12056 detail::streamOutAsParagraph(out, footer_string, footer_paragraph_width_); // Format footer as paragraph
12057 } else {
12058 out << footer_string;
12059 }
12060 }
12061 return out.str();
12062}
12063
12064CLI11_INLINE std::string Formatter::make_option(const Option *opt, bool is_positional) const {
12065 std::stringstream out;
12066 if(is_positional) {
12067 const std::string left = " " + make_option_name(opt, true) + make_option_opts(opt);
12068 const std::string desc = make_option_desc(opt);
12069 out << std::setw(static_cast<int>(column_width_)) << std::left << left;
12070
12071 if(!desc.empty()) {
12072 bool skipFirstLinePrefix = true;
12073 if(left.length() >= column_width_) {
12074 out << '\n';
12075 skipFirstLinePrefix = false;
12076 }
12077 detail::streamOutAsParagraph(
12078 out, desc, right_column_width_, std::string(column_width_, ' '), skipFirstLinePrefix);
12079 }
12080 } else {
12081 const std::string namesCombined = make_option_name(opt, false);
12082 const std::string opts = make_option_opts(opt);
12083 const std::string desc = make_option_desc(opt);
12084
12085 // Split all names at comma and sort them into short names and long names
12086 const auto names = detail::split(namesCombined, ',');
12087 std::vector<std::string> vshortNames;
12088 std::vector<std::string> vlongNames;
12089 std::for_each(names.begin(), names.end(), [&vshortNames, &vlongNames](const std::string &name) {
12090 if(name.find("--", 0) != std::string::npos)
12091 vlongNames.push_back(name);
12092 else
12093 vshortNames.push_back(name);
12094 });
12095
12096 // Assemble short and long names
12097 std::string shortNames = detail::join(vshortNames, ", ");
12098 std::string longNames = detail::join(vlongNames, ", ");
12099
12100 // Calculate setw sizes
12101 // Short names take enough width to align long names at the desired ratio
12102 const auto shortNamesColumnWidth =
12103 static_cast<int>(static_cast<float>(column_width_) * long_option_alignment_ratio_);
12104 const auto longNamesColumnWidth = static_cast<int>(column_width_) - shortNamesColumnWidth;
12105 int shortNamesOverSize = 0;
12106
12107 // Print short names
12108 if(!shortNames.empty()) {
12109 shortNames = " " + shortNames; // Indent
12110 if(longNames.empty() && !opts.empty())
12111 shortNames += opts; // Add opts if only short names and no long names
12112 if(!longNames.empty())
12113 shortNames += ",";
12114 if(static_cast<int>(shortNames.length()) >= shortNamesColumnWidth) {
12115 shortNames += " ";
12116 shortNamesOverSize = static_cast<int>(shortNames.length()) - shortNamesColumnWidth;
12117 }
12118 out << std::setw(shortNamesColumnWidth) << std::left << shortNames;
12119 } else {
12120 out << std::setw(shortNamesColumnWidth) << std::left << "";
12121 }
12122
12123 // Adjust long name column width in case of short names column reaching into long names column
12124 shortNamesOverSize =
12125 (std::min)(shortNamesOverSize, longNamesColumnWidth); // Prevent negative result with unsigned integers
12126 const auto adjustedLongNamesColumnWidth = longNamesColumnWidth - shortNamesOverSize;
12127
12128 // Print long names
12129 if(!longNames.empty()) {
12130 if(!opts.empty())
12131 longNames += opts;
12132 if(static_cast<int>(longNames.length()) >= adjustedLongNamesColumnWidth)
12133 longNames += " ";
12134
12135 out << std::setw(adjustedLongNamesColumnWidth) << std::left << longNames;
12136 } else {
12137 out << std::setw(adjustedLongNamesColumnWidth) << std::left << "";
12138 }
12139
12140 if(!desc.empty()) {
12141 bool skipFirstLinePrefix = true;
12142 if(out.str().length() > column_width_) {
12143 out << '\n';
12144 skipFirstLinePrefix = false;
12145 }
12146 detail::streamOutAsParagraph(
12147 out, desc, right_column_width_, std::string(column_width_, ' '), skipFirstLinePrefix);
12148 }
12149 }
12150
12151 out << '\n';
12152 return out.str();
12153}
12154
12155CLI11_INLINE std::string Formatter::make_option_name(const Option *opt, bool is_positional) const {
12156 if(is_positional)
12157 return opt->get_name(true, false);
12158
12159 return opt->get_name(false, true, !enable_default_flag_values_);
12160}
12161
12162CLI11_INLINE std::string Formatter::make_option_opts(const Option *opt) const {
12163 std::stringstream out;
12164
12165 if(!opt->get_option_text().empty()) {
12166 out << " " << opt->get_option_text();
12167 } else {
12168 if(opt->get_type_size() != 0) {
12169 if(enable_option_type_names_) {
12170 if(!opt->get_type_name().empty())
12171 out << " " << get_label(opt->get_type_name());
12172 }
12174 if(!opt->get_default_str().empty())
12175 out << " [" << opt->get_default_str() << "] ";
12176 }
12177 if(opt->get_expected_max() == detail::expected_max_vector_size)
12178 out << " ...";
12179 else if(opt->get_expected_min() > 1)
12180 out << " x " << opt->get_expected();
12181
12182 if(opt->get_required())
12183 out << " " << get_label("REQUIRED");
12184 }
12185 if(!opt->get_envname().empty())
12186 out << " (" << get_label("Env") << ":" << opt->get_envname() << ")";
12187 if(!opt->get_needs().empty()) {
12188 out << " " << get_label("Needs") << ":";
12189 for(const Option *op : opt->get_needs())
12190 out << " " << op->get_name();
12191 }
12192 if(!opt->get_excludes().empty()) {
12193 out << " " << get_label("Excludes") << ":";
12194 for(const Option *op : opt->get_excludes())
12195 out << " " << op->get_name();
12196 }
12197 }
12198 return out.str();
12199}
12200
12201CLI11_INLINE std::string Formatter::make_option_desc(const Option *opt) const { return opt->get_description(); }
12202
12203CLI11_INLINE std::string Formatter::make_option_usage(const Option *opt) const {
12204 // Note that these are positionals usages
12205 std::stringstream out;
12206 out << make_option_name(opt, true);
12207 if(opt->get_expected_max() >= detail::expected_max_vector_size)
12208 out << "...";
12209 else if(opt->get_expected_max() > 1)
12210 out << "(" << opt->get_expected() << "x)";
12211
12212 return opt->get_required() ? out.str() : "[" + out.str() + "]";
12213}
12214
12215
12216} // namespace CLI
Creates a command line program, with very few defaults.
Definition CLI11.hpp:7073
CLI11_NODISCARD Option * get_option_no_throw(std::string option_name) noexcept
Get an option by name (noexcept non-const version).
Definition CLI11.hpp:9383
bool subcommand_fallthrough_
Allow subcommands to fallthrough, so that parent commands can trigger other subcommands after subcomm...
Definition CLI11.hpp:7215
int exit(const Error &e, std::ostream &out=std::cout, std::ostream &err=std::cerr) const
Print a nice error message and return the exit code.
Definition CLI11.hpp:9191
CLI11_NODISCARD std::string help(std::string prev="", AppFormatMode mode=AppFormatMode::Normal) const
Definition CLI11.hpp:9287
CLI11_NODISCARD std::size_t remaining_size(bool recurse=false) const
This returns the number of remaining options, minus the – separator.
Definition CLI11.hpp:9529
const Option * operator[](const std::string &option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition CLI11.hpp:8107
CLI11_NODISCARD bool _has_remaining_positionals() const
Count the required remaining positional arguments.
Definition CLI11.hpp:10301
App * configurable(bool value=true)
Specify that the subcommand can be triggered by a config file.
Definition CLI11.hpp:7492
CLI11_NODISCARD bool get_allow_subcommand_prefix_matching() const
Get the status of allowing prefix matching for subcommands.
Definition CLI11.hpp:8183
CLI11_NODISCARD detail::Classifier _recognize(const std::string &current, bool ignore_used_subcommands=true) const
Selects a Classifier enum based on the type of the current argument.
Definition CLI11.hpp:9642
App * immediate_callback(bool immediate=true)
Set the subcommand callback to be executed immediately on subcommand completion.
Definition CLI11.hpp:8609
Option * set_help_flag(std::string flag_name="", const std::string &help_description="")
Set a help flag, replace the existing one if present.
Definition CLI11.hpp:8765
CLI11_NODISCARD std::string config_to_str(bool default_also=false, bool write_description=false) const
Definition CLI11.hpp:8037
bool allow_non_standard_options_
indicator that the subcommand should allow non-standard option arguments, such as -single_dash_flag
Definition CLI11.hpp:7247
App * usage(std::function< std::string()> usage_function)
Set usage.
Definition CLI11.hpp:8021
CLI11_NODISCARD bool get_enabled_by_default() const
Get the status of disabled by default.
Definition CLI11.hpp:8192
Option * config_ptr_
Pointer to the config option.
Definition CLI11.hpp:7281
CLI11_NODISCARD bool get_allow_non_standard_option_names() const
Get the status of allowing non standard option names.
Definition CLI11.hpp:8180
CLI11_NODISCARD bool get_configurable() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8131
Option * add_option_no_stream(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition CLI11.hpp:7576
CLI11_NODISCARD std::string get_usage() const
Generate and return the usage.
Definition CLI11.hpp:8137
CLI11_NODISCARD std::shared_ptr< FormatterBase > get_formatter() const
Access the formatter.
Definition CLI11.hpp:8052
Option * add_option(std::string option_name)
Add option with no description or variable assignment.
Definition CLI11.hpp:7615
App * subcommand_fallthrough(bool value=true)
Set subcommand fallthrough, set to true so that subcommands on parents are recognized.
Definition CLI11.hpp:7867
App * config_formatter(std::shared_ptr< Config > fmt)
Set the config formatter.
Definition CLI11.hpp:7513
App * allow_config_extras(bool allow=true)
ignore extras in config files
Definition CLI11.hpp:7439
App * disabled_by_default(bool disable=true)
Set the subcommand to be disabled by default, so on clear(), at the start of each parse it is disable...
Definition CLI11.hpp:7402
void _move_to_missing(detail::Classifier val_type, const std::string &val)
Helper function to place extra values in the most appropriate position.
Definition CLI11.hpp:10886
CLI11_NODISCARD App * _get_fallthrough_parent() noexcept
Get the appropriate parent to fallthrough to which is the first one that has a name or the main app.
Definition CLI11.hpp:10809
std::size_t require_option_min_
Minimum required options (not inheritable!).
Definition CLI11.hpp:7262
NameMatch
enumeration of matching possibilities
Definition CLI11.hpp:8250
App * silent(bool silence=true)
silence the subcommand from showing up in the processed list
Definition CLI11.hpp:7385
App * clear_aliases()
clear all the aliases of the current App
Definition CLI11.hpp:8237
CLI11_NODISCARD bool get_ignore_underscore() const
Check the status of ignore_underscore.
Definition CLI11.hpp:8116
App * ignore_underscore(bool value=true)
Ignore underscore. Subcommands inherit value.
Definition CLI11.hpp:8635
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7361
App * fallthrough(bool value=true)
Definition CLI11.hpp:7861
std::size_t require_subcommand_max_
Max number of subcommands allowed (parsing stops after this number). 0 is unlimited INHERITABLE.
Definition CLI11.hpp:7259
Option * get_config_ptr()
Get a pointer to the config option.
Definition CLI11.hpp:8213
std::vector< App_p > subcommands_
Storage for subcommand list.
Definition CLI11.hpp:7202
CLI11_NODISCARD std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
Definition CLI11.hpp:9497
CLI11_NODISCARD bool get_allow_extras() const
Get the status of allow extras.
Definition CLI11.hpp:8165
CLI11_NODISCARD std::vector< std::string > remaining_for_passthrough(bool recurse=false) const
This returns the missing options in a form ready for processing by another command line program.
Definition CLI11.hpp:9523
std::uint32_t parsed_
Counts the number of times this command/subcommand was parsed.
Definition CLI11.hpp:7253
CLI11_NODISCARD App * get_option_group(std::string group_name) const
Check to see if an option group is part of this App.
Definition CLI11.hpp:9042
App * require_subcommand()
The argumentless form of require subcommand requires 1 or more subcommands.
Definition CLI11.hpp:7802
std::string usage_
Usage to put after program/subcommand description in the help output INHERITABLE.
Definition CLI11.hpp:7139
OptionDefaults option_defaults_
The default values for options, customizable and changeable INHERITABLE.
Definition CLI11.hpp:7129
CLI11_NODISCARD const Option * get_version_ptr() const
Get a pointer to the version option. (const).
Definition CLI11.hpp:8222
void _process_requirements()
Verify required options and cross requirements. Subcommands too (only if selected).
Definition CLI11.hpp:9811
App * allow_extras(ExtrasMode allow)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7367
CLI11_NODISCARD std::size_t count_all() const
Definition CLI11.hpp:9051
CLI11_NODISCARD bool get_fallthrough() const
Check the status of fallthrough.
Definition CLI11.hpp:8119
bool disabled_
If set to true the subcommand is disabled and cannot be used, ignored for main app.
Definition CLI11.hpp:7106
CLI11_NODISCARD bool get_prefix_command() const
Get the prefix command status.
Definition CLI11.hpp:8159
Option * add_option(std::string option_name, AssignTo &variable, std::string option_description="")
Add option for assigning to a variable.
Definition CLI11.hpp:7552
CLI11_NODISCARD std::size_t get_require_subcommand_max() const
Get the required max subcommand value.
Definition CLI11.hpp:8150
Option * set_version_flag(std::string flag_name="", const std::string &versionString="", const std::string &version_help="Display program version information and exit")
Set a version flag and version display string, replace the existing one if present.
Definition CLI11.hpp:8798
bool required_
If set to true the subcommand is required to be processed and used, ignored for main app.
Definition CLI11.hpp:7103
bool remove_needs(Option *opt)
Removes an option from the needs list of this subcommand.
Definition CLI11.hpp:9269
const Option * operator[](const char *option_name) const
Shortcut bracket operator for getting a pointer to an option.
Definition CLI11.hpp:8110
CLI11_NODISCARD bool get_immediate_callback() const
Get the status of disabled.
Definition CLI11.hpp:8186
Option * get_help_ptr()
Get a pointer to the help flag.
Definition CLI11.hpp:8204
App * require_subcommand(int value)
Definition CLI11.hpp:7811
void _configure()
Definition CLI11.hpp:9578
CLI11_NODISCARD std::size_t _count_remaining_positionals(bool required_only=false) const
Count the required remaining positional arguments.
Definition CLI11.hpp:10289
Option * add_flag_function(std::string flag_name, std::function< void(std::int64_t)> function, std::string flag_description="")
Add option for callback with an integer value.
Definition CLI11.hpp:8874
OptionDefaults * option_defaults()
Get the OptionDefault object, to set option defaults.
Definition CLI11.hpp:7522
void parse(int argc, const char *const *argv)
Definition CLI11.hpp:9081
void _process_config_file()
Read and process a configuration file (main app only).
Definition CLI11.hpp:9699
std::string footer_
Footer to put after all options in the help output INHERITABLE.
Definition CLI11.hpp:7145
void increment_parsed()
Internal function to recursively increment the parsed counter on the current app as well unnamed subc...
Definition CLI11.hpp:9999
CLI11_NODISCARD bool check_name(std::string name_to_check) const
Definition CLI11.hpp:9441
CLI11_NODISCARD std::string get_footer() const
Generate and return the footer.
Definition CLI11.hpp:8142
App * required(bool require=true)
Remove the error when extras are left over on the command line.
Definition CLI11.hpp:7373
Option * version_ptr_
A pointer to a version flag if there is one.
Definition CLI11.hpp:7157
CLI11_NODISCARD const Option * get_help_all_ptr() const
Get a pointer to the help all flag. (const).
Definition CLI11.hpp:8210
bool remove_subcommand(App *subcom)
Removes a subcommand from the App. Takes a subcommand pointer. Returns true if found and removed.
Definition CLI11.hpp:8972
App * parent_
A pointer to the parent if this is a subcommand.
Definition CLI11.hpp:7268
Option * add_flag(std::string flag_name, T &&flag_description)
Definition CLI11.hpp:7659
std::set< Option * > exclude_options_
Definition CLI11.hpp:7187
void _trigger_pre_parse(std::size_t remaining_args)
Trigger the pre_parse callback if needed.
Definition CLI11.hpp:10791
App * group(std::string group_name)
Changes the group membership.
Definition CLI11.hpp:7796
CLI::App_p get_subcommand_ptr(App *subcom) const
Check to see if a subcommand is part of this command and get a shared_ptr to it.
Definition CLI11.hpp:9017
std::function< std::string()> footer_callback_
This is a function that generates a footer to put after all other options in help output.
Definition CLI11.hpp:7148
ExtrasMode allow_extras_
If true, allow extra arguments (ie, don't throw an error). INHERITABLE.
Definition CLI11.hpp:7090
PrefixCommandMode prefix_command_
If true, cease processing on an unrecognized option (implies allow_extras) INHERITABLE.
Definition CLI11.hpp:7097
std::function< void()> parse_complete_callback_
This is a function that runs when parsing has finished.
Definition CLI11.hpp:7119
CLI11_NODISCARD bool get_subcommand_fallthrough() const
Check the status of subcommand fallthrough.
Definition CLI11.hpp:8122
virtual void pre_callback()
Definition CLI11.hpp:7883
T * add_option_group(std::string group_name, std::string group_description="")
creates an option group as part of the given app
Definition CLI11.hpp:7732
App * get_parent()
Get the parent of this subcommand (or nullptr if main app).
Definition CLI11.hpp:8225
Option * add_flag(std::string flag_name)
Add a flag with no description or variable assignment.
Definition CLI11.hpp:7649
void _validate() const
Definition CLI11.hpp:9543
std::string name_
Subcommand name or program name (from parser if name is empty).
Definition CLI11.hpp:7084
std::vector< App * > parsed_subcommands_
This is a list of the subcommands collected, in order.
Definition CLI11.hpp:7180
App(std::string app_description="", std::string app_name="")
Create a new program. Pass in the same arguments as main(), along with a help string.
Definition CLI11.hpp:7304
CLI11_NODISCARD const Option * get_help_ptr() const
Get a pointer to the help flag. (const).
Definition CLI11.hpp:8207
bool ignore_underscore_
If true, the program should ignore underscores INHERITABLE.
Definition CLI11.hpp:7208
App * allow_windows_style_options(bool value=true)
Definition CLI11.hpp:7480
missing_t missing_
Definition CLI11.hpp:7174
CLI11_NODISCARD bool get_validate_positionals() const
Get the status of validating positionals.
Definition CLI11.hpp:8194
Option * add_option_function(std::string option_name, const std::function< void(const ArgType &)> &func, std::string option_description="")
Add option for a callback of a specific type.
Definition CLI11.hpp:7594
void run_callback(bool final_mode=false, bool suppress_final_callback=false)
Internal function to run (App) callback, bottom up.
Definition CLI11.hpp:9598
bool allow_prefix_matching_
indicator to allow subcommands to match with prefix matching
Definition CLI11.hpp:7250
std::size_t require_subcommand_min_
Minimum required subcommands (not inheritable!).
Definition CLI11.hpp:7256
App * usage(std::string usage_string)
Set usage.
Definition CLI11.hpp:8016
CLI11_NODISCARD NameMatch check_name_detail(std::string name_to_check) const
Definition CLI11.hpp:9446
App * allow_subcommand_prefix_matching(bool allowed=true)
allow prefix matching for subcommands
Definition CLI11.hpp:7397
void _process_env()
Get envname options if not yet passed. Runs on all subcommands.
Definition CLI11.hpp:9735
std::function< std::string(const App *, const Error &e)> failure_message_
The error message printing function INHERITABLE.
Definition CLI11.hpp:7163
void _parse_stream(std::istream &input)
Internal function to parse a stream.
Definition CLI11.hpp:10060
CLI11_NODISCARD std::string get_display_name(bool with_aliases=false) const
Get a display name for an app.
Definition CLI11.hpp:9425
void failure_message(std::function< std::string(const App *, const Error &e)> function)
Provide a function to print a help message. The function gets access to the App pointer and error.
Definition CLI11.hpp:7918
bool has_automatic_name_
If set to true the name was automatically generated from the command line vs a user set name.
Definition CLI11.hpp:7100
CLI11_NODISCARD const std::string & _compare_subcommand_names(const App &subcom, const App &base) const
Helper function to run through all possible comparisons of subcommand names to check there is no over...
Definition CLI11.hpp:10831
void clear()
Reset the parsed data.
Definition CLI11.hpp:9065
CLI11_NODISCARD std::size_t get_require_option_max() const
Get the required max option value.
Definition CLI11.hpp:8156
App * enabled_by_default(bool enable=true)
Definition CLI11.hpp:7413
App * footer(std::string footer_string)
Set footer.
Definition CLI11.hpp:8026
App * get_subcommand(const App *subcom) const
Definition CLI11.hpp:8988
App * require_option(int value)
Definition CLI11.hpp:7840
CLI11_NODISCARD std::string version() const
Displays a version string.
Definition CLI11.hpp:9301
virtual ~App()=default
virtual destructor
CLI11_NODISCARD App * get_subcommand_no_throw(std::string subcom) const noexcept
Definition CLI11.hpp:9004
CLI11_NODISCARD std::size_t count(std::string option_name) const
Counts the number of times the given option was passed.
Definition CLI11.hpp:7930
bool _add_flag_like_result(Option *op, const ConfigItem &item, const std::vector< std::string > &inputs)
store the results for a flag like option
Definition CLI11.hpp:10079
std::vector< Option_p > options_
The list of options, stored locally.
Definition CLI11.hpp:7132
Option * help_all_ptr_
A pointer to the help all flag if there is one INHERITABLE.
Definition CLI11.hpp:7154
bool validate_optional_arguments_
If set to true optional vector arguments are validated before assigning INHERITABLE.
Definition CLI11.hpp:7240
std::function< void()> final_callback_
This is a function that runs when all processing has completed.
Definition CLI11.hpp:7122
bool remove_option(Option *opt)
Removes an option from the App. Takes an option pointer. Returns true if found and removed.
Definition CLI11.hpp:8918
App * require_option()
The argumentless form of require option requires 1 or more options be used.
Definition CLI11.hpp:7831
App(std::string app_description, std::string app_name, App *parent)
Special private constructor for subcommand.
Definition CLI11.hpp:8517
std::function< std::string()> usage_callback_
This is a function that generates a usage to put after program/subcommand description in help output.
Definition CLI11.hpp:7142
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
Definition CLI11.hpp:8941
App * preparse_callback(std::function< void(std::size_t)> pp_callback)
Definition CLI11.hpp:7349
Option * add_flag_callback(std::string flag_name, std::function< void(void)> function, std::string flag_description="")
Add option for callback that is triggered with a true flag and takes no arguments.
Definition CLI11.hpp:8857
bool positionals_at_end_
specify that positional arguments come at the end of the argument sequence not inheritable
Definition CLI11.hpp:7226
void _process()
Process callbacks and such.
Definition CLI11.hpp:9939
bool immediate_callback_
Definition CLI11.hpp:7113
bool _parse_single(std::vector< std::string > &args, bool &positional_only)
Definition CLI11.hpp:10240
App * name(std::string app_name="")
Set a name for the app (empty will use parser to set the name).
Definition CLI11.hpp:8574
void _move_option(Option *opt, App *app)
function that could be used by subclasses of App to shift options around into subcommands
Definition CLI11.hpp:10909
CLI11_NODISCARD bool get_required() const
Get the status of required.
Definition CLI11.hpp:8171
void _process_extras()
Throw an error if anything is left over and should not be.
Definition CLI11.hpp:9978
CLI11_NODISCARD bool _valid_subcommand(const std::string &current, bool ignore_used=true) const
Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached.
Definition CLI11.hpp:9625
CLI11_NODISCARD PrefixCommandMode get_prefix_command_mode() const
Get the prefix command status.
Definition CLI11.hpp:8162
CLI11_NODISCARD bool get_ignore_case() const
Check the status of ignore_case.
Definition CLI11.hpp:8113
App * parse_complete_callback(std::function< void()> pc_callback)
Definition CLI11.hpp:7342
bool configurable_
if set to true the subcommand can be triggered via configuration files INHERITABLE
Definition CLI11.hpp:7234
CLI11_NODISCARD std::vector< std::string > get_groups() const
Get the groups available directly from this option (in order).
Definition CLI11.hpp:9484
CLI11_NODISCARD bool got_subcommand(std::string subcommand_name) const noexcept
Check with name instead of pointer to see if subcommand was selected.
Definition CLI11.hpp:7951
App * formatter_fn(std::function< std::string(const App *, std::string, AppFormatMode)> fmt)
Set the help formatter.
Definition CLI11.hpp:7507
CLI11_NODISCARD const std::vector< std::string > & get_aliases() const
Get the aliases of the current app.
Definition CLI11.hpp:8234
void _parse_config(const std::vector< ConfigItem > &args)
Definition CLI11.hpp:10071
App * description(std::string app_description)
Set the description of the app.
Definition CLI11.hpp:8071
CLI11_NODISCARD std::shared_ptr< ConfigBase > get_config_formatter_base() const
Access the config formatter as a configBase pointer.
Definition CLI11.hpp:8058
std::string description_
Description of the current program/subcommand.
Definition CLI11.hpp:7087
App * excludes(App *app)
Sets excluded subcommands for the subcommand.
Definition CLI11.hpp:7966
App * allow_non_standard_option_names(bool allowed=true)
allow non standard option names
Definition CLI11.hpp:7391
CLI11_NODISCARD bool get_positionals_at_end() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8128
Option * get_version_ptr()
Get a pointer to the version option.
Definition CLI11.hpp:8219
CLI11_NODISCARD std::size_t get_require_option_min() const
Get the required min option value.
Definition CLI11.hpp:8153
std::size_t require_option_max_
Max number of options allowed. 0 is unlimited (not inheritable).
Definition CLI11.hpp:7265
CLI11_NODISCARD bool get_disabled() const
Get the status of disabled.
Definition CLI11.hpp:8174
CLI11_NODISCARD bool get_allow_windows_style_options() const
Check the status of the allow windows style options.
Definition CLI11.hpp:8125
std::vector< std::string > aliases_
Alias names for the subcommand.
Definition CLI11.hpp:7274
CLI11_NODISCARD bool parsed() const
Check to see if this subcommand was parsed, true only if received on command line.
Definition CLI11.hpp:7519
std::set< App * > exclude_subcommands_
this is a list of subcommands that are exclusionary to this one
Definition CLI11.hpp:7183
CLI11_NODISCARD bool get_disabled_by_default() const
Get the status of disabled by default.
Definition CLI11.hpp:8189
Option * add_flag(std::string flag_name, std::vector< T > &flag_results, std::string flag_description="")
Vector version to capture multiple flags.
Definition CLI11.hpp:7685
ConfigExtrasMode allow_config_extras_
Definition CLI11.hpp:7094
CLI11_NODISCARD std::size_t count() const
Definition CLI11.hpp:7789
bool _parse_positional(std::vector< std::string > &args, bool haltOnSubcommand)
Definition CLI11.hpp:10311
CLI11_NODISCARD Option * get_option(std::string option_name)
Get an option by name (non-const version).
Definition CLI11.hpp:8098
bool ignore_case_
If true, the program name is not case-sensitive INHERITABLE.
Definition CLI11.hpp:7205
CLI11_NODISCARD const std::string & get_group() const
Get the group of this subcommand.
Definition CLI11.hpp:8134
bool _parse_arg(std::vector< std::string > &args, detail::Classifier current_type, bool local_processing_only)
Definition CLI11.hpp:10525
bool silent_
Definition CLI11.hpp:7244
CLI11_NODISCARD const App * get_parent() const
Get the parent of this subcommand (or nullptr if main app) (const version).
Definition CLI11.hpp:8228
std::function< void(std::size_t)> pre_parse_callback_
This is a function that runs prior to the start of parsing.
Definition CLI11.hpp:7116
App * final_callback(std::function< void()> app_callback)
Definition CLI11.hpp:7335
std::string group_
The group membership INHERITABLE.
Definition CLI11.hpp:7271
App * alias(std::string app_name)
Set an alias for the app.
Definition CLI11.hpp:8591
bool pre_parse_called_
Flag indicating that the pre_parse_callback has been triggered.
Definition CLI11.hpp:7109
CLI11_NODISCARD ExtrasMode get_allow_extras_mode() const
Get the mode of allow_extras.
Definition CLI11.hpp:8168
App * validate_positionals(bool validate=true)
Set the subcommand to validate positional arguments before assigning.
Definition CLI11.hpp:7427
Option * help_ptr_
A pointer to the help flag if there is one INHERITABLE.
Definition CLI11.hpp:7151
Option * set_config(std::string option_name="", std::string default_filename="", const std::string &help_message="Read an ini file", bool config_required=false)
Set a configuration ini file option, or clear it if no name passed.
Definition CLI11.hpp:8889
App * footer(std::function< std::string()> footer_function)
Set footer.
Definition CLI11.hpp:8031
App * ignore_case(bool value=true)
Ignore case. Subcommands inherit value.
Definition CLI11.hpp:8621
App * excludes(Option *opt)
Sets excluded options for the subcommand.
Definition CLI11.hpp:7957
CLI11_NODISCARD std::shared_ptr< Config > get_config_formatter() const
Access the config formatter.
Definition CLI11.hpp:8055
App * prefix_command(PrefixCommandMode mode)
Definition CLI11.hpp:7470
bool remove_excludes(Option *opt)
Removes an option from the excludes list of this subcommand.
Definition CLI11.hpp:9249
CLI11_NODISCARD std::vector< App * > get_subcommands() const
Definition CLI11.hpp:7934
bool got_subcommand(const App *subcom) const
Check to see if given subcommand was selected.
Definition CLI11.hpp:7945
CLI11_NODISCARD config_extras_mode get_allow_config_extras() const
Get the status of allow extras.
Definition CLI11.hpp:8199
App * allow_config_extras(ConfigExtrasMode mode)
ignore extras in config files
Definition CLI11.hpp:7456
bool _parse_subcommand(std::vector< std::string > &args)
Definition CLI11.hpp:10485
App * positionals_at_end(bool value=true)
Specify that the positional arguments are only at the end of the sequence.
Definition CLI11.hpp:7486
bool fallthrough_
Definition CLI11.hpp:7212
std::set< Option * > need_options_
Definition CLI11.hpp:7195
CLI11_NODISCARD bool get_validate_optional_arguments() const
Get the status of validating optional vector arguments.
Definition CLI11.hpp:8196
CLI11_NODISCARD bool get_silent() const
Get the status of silence.
Definition CLI11.hpp:8177
std::vector< const Option * > get_options(const std::function< bool(const Option *)> filter={}) const
Get the list of options (user facing function, so returns raw pointers), has optional filter function...
Definition CLI11.hpp:9319
std::set< App * > need_subcommands_
Definition CLI11.hpp:7191
App * validate_optional_arguments(bool validate=true)
Set the subcommand to validate optional vector arguments before assigning.
Definition CLI11.hpp:7433
Option * add_option(std::string option_name, callback_t option_callback, std::string option_description="", bool defaulted=false, std::function< std::string()> func={})
Definition CLI11.hpp:8649
App * formatter(std::shared_ptr< FormatterBase > fmt)
Set the help formatter.
Definition CLI11.hpp:7501
std::vector< Option * > parse_order_
This is a list of pointers to options with the original parse order.
Definition CLI11.hpp:7177
Option * add_option(std::string option_name, T &option_description)
Add option with description but with no variable assignment or callback.
Definition CLI11.hpp:7623
App * prefix_command(bool is_prefix=true)
Definition CLI11.hpp:7463
CLI11_NODISCARD const std::vector< Option * > & parse_order() const
This gets a vector of pointers with the original parse order.
Definition CLI11.hpp:8261
void _parse(std::vector< std::string > &args)
Internal parse function.
Definition CLI11.hpp:10007
bool validate_positionals_
If set to true positional options are validated before assigning INHERITABLE.
Definition CLI11.hpp:7237
bool _parse_single_config(const ConfigItem &item, std::size_t level=0)
Fill in a single config option.
Definition CLI11.hpp:10140
void _process_help_flags(CallbackPriority priority, bool trigger_help=false, bool trigger_all_help=false) const
Definition CLI11.hpp:9786
startup_mode default_startup
Definition CLI11.hpp:7231
App * allow_config_extras(config_extras_mode mode)
ignore extras in config files
Definition CLI11.hpp:7450
Option * add_flag(std::string flag_name, T &flag_result, std::string flag_description="")
Definition CLI11.hpp:7669
void _process_callbacks(CallbackPriority priority)
Process callbacks. Runs on all subcommands.
Definition CLI11.hpp:9757
CLI11_NODISCARD std::string get_description() const
Get the app or subcommand description.
Definition CLI11.hpp:8068
App * require_option(std::size_t min, std::size_t max)
Definition CLI11.hpp:7853
CLI11_NODISCARD char ** ensure_utf8(char **argv)
Convert the contents of argv to UTF-8. Only does something on Windows, does nothing elsewhere.
Definition CLI11.hpp:8552
CLI11_NODISCARD App * _find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept
Definition CLI11.hpp:10449
CLI11_NODISCARD std::size_t get_require_subcommand_min() const
Get the required min subcommand value.
Definition CLI11.hpp:8147
CLI11_NODISCARD const Option * get_config_ptr() const
Get a pointer to the config option. (const).
Definition CLI11.hpp:8216
CLI11_NODISCARD const std::string & get_name() const
Get the name of the current app.
Definition CLI11.hpp:8231
App * disabled(bool disable=true)
Disable the subcommand or option group.
Definition CLI11.hpp:7379
App * callback(std::function< void()> app_callback)
Definition CLI11.hpp:7324
std::shared_ptr< FormatterBase > formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer).
Definition CLI11.hpp:7160
Option * set_help_all_flag(std::string help_name="", const std::string &help_description="")
Set a help all flag, replaced the existing one if present.
Definition CLI11.hpp:8781
App * require_subcommand(std::size_t min, std::size_t max)
Definition CLI11.hpp:7824
CLI11_NODISCARD const Option * get_option(std::string option_name) const
Get an option by name.
Definition CLI11.hpp:8089
bool allow_windows_style_options_
Allow '/' for options for Windows like options. Defaults to true on Windows, false otherwise....
Definition CLI11.hpp:7218
std::shared_ptr< Config > config_formatter_
This is the formatter for help printing. Default provided. INHERITABLE (same pointer).
Definition CLI11.hpp:7284
Thrown when the wrong number of arguments has been received.
Definition CLI11.hpp:1603
Definition CLI11.hpp:4873
Options
Definition CLI11.hpp:4879
AsSizeValue(bool kb_is_1000)
Definition CLI11.hpp:5092
Thrown on construction of a bad name.
Definition CLI11.hpp:1464
Bound(T min_val, T max_val)
Definition CLI11.hpp:4514
Bound(T max_val)
Range of one value is 0 to value.
Definition CLI11.hpp:4536
Usually something like –help-all on command line.
Definition CLI11.hpp:1518
-h or –help on command line
Definition CLI11.hpp:1512
-v or –version on command line
Definition CLI11.hpp:1525
CheckedTransformer(T mapping)
direct map of std::string to std::string
Definition CLI11.hpp:4781
CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest.
Definition CLI11.hpp:4842
CheckedTransformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition CLI11.hpp:4777
CheckedTransformer(T mapping, F filter_function)
Definition CLI11.hpp:4785
This converter works with INI/TOML files; to write INI files use ConfigINI.
Definition CLI11.hpp:3766
std::vector< ConfigItem > from_config(std::istream &input) const override
Convert a configuration into an app.
Definition CLI11.hpp:11327
std::string configSection
Specify the configuration section that should be used.
Definition CLI11.hpp:3793
ConfigBase * comment(char cchar)
Specify the configuration for comment characters.
Definition CLI11.hpp:3801
ConfigBase * arrayDelimiter(char aSep)
Specify the delimiter character for an array.
Definition CLI11.hpp:3812
ConfigBase * quoteCharacter(char qString, char literalChar)
Specify the quote characters used around strings and literal strings.
Definition CLI11.hpp:3822
char arraySeparator
the character used to separate elements in an array
Definition CLI11.hpp:3775
std::string & sectionRef()
get a reference to the configuration section
Definition CLI11.hpp:3843
ConfigBase * arrayBounds(char aStart, char aEnd)
Specify the start and end characters for an array.
Definition CLI11.hpp:3806
ConfigBase * maxLayers(uint8_t layers)
Specify the maximum number of parents.
Definition CLI11.hpp:3828
ConfigBase * allowDuplicateFields(bool value=true)
specify that multiple duplicate arguments should be merged even if not sequential
Definition CLI11.hpp:3862
CLI11_NODISCARD const std::string & section() const
get the section
Definition CLI11.hpp:3845
ConfigBase * commentDefaults(bool comDef=true)
comment default value options
Definition CLI11.hpp:3838
char stringQuote
the character to use around strings
Definition CLI11.hpp:3779
ConfigBase * section(const std::string &sectionName)
specify a particular section of the configuration file to use
Definition CLI11.hpp:3847
ConfigBase * valueSeparator(char vSep)
Specify the delimiter between a name and value.
Definition CLI11.hpp:3817
uint8_t maximumLayers
the maximum number of layers to allow
Definition CLI11.hpp:3783
char valueDelimiter
the character used separate the name from the value
Definition CLI11.hpp:3777
char arrayStart
the character used to start an array '\0' is a default to not use
Definition CLI11.hpp:3771
char parentSeparatorChar
the separator used to separator parent layers
Definition CLI11.hpp:3785
bool allowMultipleDuplicateFields
specify the config reader should collapse repeated field names to a single vector
Definition CLI11.hpp:3789
CLI11_NODISCARD int16_t index() const
get the section index
Definition CLI11.hpp:3855
char literalQuote
the character to use around single characters and literal strings
Definition CLI11.hpp:3781
ConfigBase * index(int16_t sectionIndex)
specify a particular index in the section to use (-1) for all sections to use
Definition CLI11.hpp:3857
int16_t & indexRef()
get a reference to the configuration index
Definition CLI11.hpp:3853
char arrayEnd
the character used to end an array '\0' is a default to not use
Definition CLI11.hpp:3773
ConfigBase * parentSeparator(char sep)
Specify the separator to use for parent layers.
Definition CLI11.hpp:3833
bool commentDefaultsBool
comment default values
Definition CLI11.hpp:3787
int16_t configIndex
Specify the configuration index to use for arrayed sections.
Definition CLI11.hpp:3791
std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override
Convert an app into a configuration.
Definition CLI11.hpp:11600
char commentChar
the character used for comments
Definition CLI11.hpp:3769
Thrown when extra values are found in an INI file.
Definition CLI11.hpp:1664
This class provides a converter for configuration files.
Definition CLI11.hpp:3725
virtual CLI11_NODISCARD std::string to_flag(const ConfigItem &item) const
Get a flag value.
Definition CLI11.hpp:3737
virtual std::string to_config(const App *, bool, bool, std::string) const =0
Convert an app into a configuration.
CLI11_NODISCARD std::vector< ConfigItem > from_file(const std::string &name) const
Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure.
Definition CLI11.hpp:3748
virtual ~Config()=default
Virtual destructor.
virtual std::vector< ConfigItem > from_config(std::istream &) const =0
Convert a configuration into an app.
Construction errors (not in parsing).
Definition CLI11.hpp:1431
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition CLI11.hpp:1545
All errors derive from this one.
Definition CLI11.hpp:1413
Thrown when an excludes option is present.
Definition CLI11.hpp:1641
Thrown when too many positionals or options are found.
Definition CLI11.hpp:1648
Thrown when parsing an INI file and it is missing.
Definition CLI11.hpp:1538
Definition CLI11.hpp:5207
void footer_paragraph_width(std::size_t val)
Set the footer paragraph width.
Definition CLI11.hpp:5280
std::size_t column_width_
The width of the left column (options/flags/subcommands).
Definition CLI11.hpp:5213
void right_column_width(std::size_t val)
Set the right column width (description of options/flags/subcommands).
Definition CLI11.hpp:5274
std::map< std::string, std::string > labels_
The required help printout labels (user changeable) Values are Needs, Excludes, etc.
Definition CLI11.hpp:5237
std::size_t footer_paragraph_width_
The width of the footer paragraph.
Definition CLI11.hpp:5225
CLI11_NODISCARD std::size_t get_column_width() const
Get the current left column width (options/flags/subcommands).
Definition CLI11.hpp:5304
CLI11_NODISCARD float get_long_option_alignment_ratio() const
Get the current alignment ratio for long options within the left column.
Definition CLI11.hpp:5317
bool enable_option_defaults_
options controlling formatting of options
Definition CLI11.hpp:5232
void enable_default_flag_values(bool value=true)
enable default flag values to be printed
Definition CLI11.hpp:5291
CLI11_NODISCARD bool is_option_defaults_enabled() const
Get the current status of whether option defaults are printed.
Definition CLI11.hpp:5326
CLI11_NODISCARD std::size_t get_footer_paragraph_width() const
Get the current footer paragraph width.
Definition CLI11.hpp:5313
void long_option_alignment_ratio(float ratio)
Definition CLI11.hpp:5268
CLI11_NODISCARD std::string get_label(std::string key) const
Get the current value of a name (REQUIRED, etc.).
Definition CLI11.hpp:5297
CLI11_NODISCARD std::size_t get_description_paragraph_width() const
Get the current description paragraph width at the top of help.
Definition CLI11.hpp:5310
void enable_option_defaults(bool value=true)
enable option defaults to be printed
Definition CLI11.hpp:5287
void enable_description_formatting(bool value=true)
enable formatting for description paragraph
Definition CLI11.hpp:5282
void label(std::string key, std::string val)
Set the "REQUIRED" or other labels.
Definition CLI11.hpp:5261
bool enable_description_formatting_
options controlling formatting for footer and descriptions
Definition CLI11.hpp:5228
void enable_footer_formatting(bool value=true)
disable formatting for footer paragraph
Definition CLI11.hpp:5284
CLI11_NODISCARD bool is_default_flag_values_enabled() const
Get the current status of whether default flag values are printed.
Definition CLI11.hpp:5332
CLI11_NODISCARD bool is_description_paragraph_formatting_enabled() const
Get the current status of description paragraph formatting.
Definition CLI11.hpp:5320
CLI11_NODISCARD std::size_t get_right_column_width() const
Get the current right column width (description of options/flags/subcommands).
Definition CLI11.hpp:5307
virtual ~FormatterBase() noexcept
Adding a destructor in this form to work around bug in GCC 4.7.
Definition CLI11.hpp:5251
virtual std::string make_help(const App *, std::string, AppFormatMode) const =0
This is the key method that puts together help.
void column_width(std::size_t val)
Set the left column width (options/flags/subcommands).
Definition CLI11.hpp:5264
std::size_t right_column_width_
The width of the right column (description of options/flags/subcommands).
Definition CLI11.hpp:5219
void enable_option_type_names(bool value=true)
enable option type names to be printed
Definition CLI11.hpp:5289
float long_option_alignment_ratio_
The alignment ratio for long options within the left column.
Definition CLI11.hpp:5216
std::size_t description_paragraph_width_
The width of the description paragraph at the top of help.
Definition CLI11.hpp:5222
CLI11_NODISCARD bool is_footer_paragraph_formatting_enabled() const
Get the current status of whether footer paragraph formatting is enabled.
Definition CLI11.hpp:5323
void description_paragraph_width(std::size_t val)
Set the description paragraph width at the top of help.
Definition CLI11.hpp:5277
CLI11_NODISCARD bool is_option_type_names_enabled() const
Get the current status of whether option type names are printed.
Definition CLI11.hpp:5329
std::string make_help(const App *app, std::string name, AppFormatMode mode) const override
This will simply call the lambda function.
Definition CLI11.hpp:5352
~FormatterLambda() noexcept override
Adding a destructor (mostly to make GCC 4.7 happy).
Definition CLI11.hpp:5349
FormatterLambda(funct_t funct)
Create a FormatterLambda with a lambda function.
Definition CLI11.hpp:5346
Definition CLI11.hpp:5359
std::string make_groups(const App *app, AppFormatMode mode) const
This prints out all the groups of options.
Definition CLI11.hpp:11833
virtual std::string make_usage(const App *app, std::string name) const
This displays the usage line.
Definition CLI11.hpp:11883
virtual std::string make_option_name(const Option *, bool) const
This is the name part of an option, Default: left column.
Definition CLI11.hpp:12155
virtual std::string make_expanded(const App *sub, AppFormatMode mode) const
This prints out a subcommand in help-all.
Definition CLI11.hpp:12027
std::string make_help(const App *app, std::string, AppFormatMode mode) const override
This puts everything together.
Definition CLI11.hpp:11941
virtual CLI11_NODISCARD std::string make_group(std::string group, bool is_positional, std::vector< const Option * > opts) const
Definition CLI11.hpp:11812
virtual std::string make_option(const Option *, bool) const
This prints out an option help line, either positional or optional form.
Definition CLI11.hpp:12064
virtual std::string make_footer(const App *app) const
This prints out all the groups of options.
Definition CLI11.hpp:11933
virtual std::string make_option_usage(const Option *opt) const
This is used to print the name on the USAGE line.
Definition CLI11.hpp:12203
virtual std::string make_subcommand(const App *sub) const
This prints out a subcommand.
Definition CLI11.hpp:12016
virtual std::string make_positionals(const App *app) const
This prints out just the positionals "group".
Definition CLI11.hpp:11823
virtual std::string make_subcommands(const App *app, AppFormatMode mode) const
This prints out all the subcommands.
Definition CLI11.hpp:11974
virtual std::string make_description(const App *app) const
This displays the description line.
Definition CLI11.hpp:11858
virtual std::string make_option_desc(const Option *) const
This is the description. Default: Right column, on new line if left column too large.
Definition CLI11.hpp:12201
virtual std::string make_option_opts(const Option *) const
This is the options part of the name, Default: combined into left column.
Definition CLI11.hpp:12162
Definition CLI11.hpp:1683
Thrown when an option is set to conflicting values (non-vector and multi args, for example).
Definition CLI11.hpp:1436
Thrown when validation fails before parsing.
Definition CLI11.hpp:1674
IsMember(T &&set)
This checks to see if an item is in a set (empty function).
Definition CLI11.hpp:4652
IsMember(T set, F filter_function)
Definition CLI11.hpp:4656
IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest (string only currently).
Definition CLI11.hpp:4701
IsMember(std::initializer_list< T > values, Args &&...args)
This allows in-place construction using an initializer list.
Definition CLI11.hpp:4648
Thrown when an option already exists.
Definition CLI11.hpp:1484
Definition CLI11.hpp:5463
CRTP * mandatory(bool value=true)
Support Plumbum term.
Definition CLI11.hpp:5520
CRTP * take_all()
Set the multi option policy to take all arguments.
Definition CLI11.hpp:5576
CRTP * group(const std::string &name)
Changes the group membership.
Definition CLI11.hpp:5505
CRTP * join()
Set the multi option policy to join.
Definition CLI11.hpp:5583
bool always_capture_default_
Automatically capture default value.
Definition CLI11.hpp:5490
MultiOptionPolicy multi_option_policy_
Policy for handling multiple arguments beyond the expected Max.
Definition CLI11.hpp:5493
CRTP * join(char delim)
Set the multi option policy to join with a specific delimiter.
Definition CLI11.hpp:5590
CLI11_NODISCARD CallbackPriority get_callback_priority() const
The priority of callback.
Definition CLI11.hpp:5557
CLI11_NODISCARD bool get_always_capture_default() const
Return true if this will automatically capture the default value for help printing.
Definition CLI11.hpp:5551
CLI11_NODISCARD char get_delimiter() const
Get the current delimiter char.
Definition CLI11.hpp:5548
CLI11_NODISCARD bool get_required() const
True if this is a required option.
Definition CLI11.hpp:5533
CRTP * take_first()
Set the multi option policy to take last.
Definition CLI11.hpp:5569
CLI11_NODISCARD bool get_ignore_case() const
The status of ignore case.
Definition CLI11.hpp:5536
bool ignore_case_
Ignore the case when matching (option, not value).
Definition CLI11.hpp:5475
CRTP * configurable(bool value=true)
Allow in a configuration file.
Definition CLI11.hpp:5598
CRTP * delimiter(char value='\0')
Allow in a configuration file.
Definition CLI11.hpp:5604
CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const
The status of the multi option policy.
Definition CLI11.hpp:5554
CLI11_NODISCARD bool get_configurable() const
The status of configurable.
Definition CLI11.hpp:5542
bool configurable_
Allow this option to be given in a configuration file.
Definition CLI11.hpp:5481
CallbackPriority callback_priority_
Priority of callback.
Definition CLI11.hpp:5496
bool disable_flag_override_
Disable overriding flag values with '=value'.
Definition CLI11.hpp:5484
bool required_
True if this is a required option.
Definition CLI11.hpp:5472
CRTP * take_last()
Set the multi option policy to take last.
Definition CLI11.hpp:5562
char delimiter_
Specify a delimiter character for vector arguments.
Definition CLI11.hpp:5487
std::string group_
The group membership.
Definition CLI11.hpp:5469
CLI11_NODISCARD bool get_ignore_underscore() const
The status of ignore_underscore.
Definition CLI11.hpp:5539
bool ignore_underscore_
Ignore underscores when matching (option, not value).
Definition CLI11.hpp:5478
CLI11_NODISCARD bool get_disable_flag_override() const
The status of configurable.
Definition CLI11.hpp:5545
CLI11_NODISCARD const std::string & get_group() const
Get the group of this option.
Definition CLI11.hpp:5530
void copy_to(T *other) const
Copy the contents to another similar class (one based on OptionBase).
Definition CLI11.hpp:6267
CRTP * required(bool value=true)
Set the option as required.
Definition CLI11.hpp:5514
Definition CLI11.hpp:5612
OptionDefaults * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times.
Definition CLI11.hpp:5625
OptionDefaults * ignore_case(bool value=true)
Ignore the case of the option name.
Definition CLI11.hpp:5631
OptionDefaults * ignore_underscore(bool value=true)
Ignore underscores in the option name.
Definition CLI11.hpp:5637
OptionDefaults * callback_priority(CallbackPriority value=CallbackPriority::Normal)
Set the callback priority.
Definition CLI11.hpp:5619
OptionDefaults * delimiter(char value='\0')
set a delimiter character to split up single arguments to treat as multiple inputs
Definition CLI11.hpp:5649
OptionDefaults * disable_flag_override(bool value=true)
Disable overriding flag values with an '=' segment.
Definition CLI11.hpp:5643
Thrown when counting a nonexistent option.
Definition CLI11.hpp:1691
Extension of App to better manage groups of options.
Definition CLI11.hpp:8400
App * add_subcommand(App *subcom)
Add an existing subcommand to be a member of an option_group.
Definition CLI11.hpp:8430
Option * add_option(Option *opt)
Add an existing option to the Option_group.
Definition CLI11.hpp:8414
void add_options(Option *opt, Args... args)
Add a bunch of options to the group.
Definition CLI11.hpp:8424
void add_options(Option *opt)
Add an existing option to the Option_group.
Definition CLI11.hpp:8422
Definition CLI11.hpp:5655
Option * type_size(int option_type_size)
Set a custom option size.
Definition CLI11.hpp:6737
Option * expected(int value)
Set the number of expected arguments.
Definition CLI11.hpp:6280
Option * check(Validator_p validator)
Adds a shared validator.
Definition CLI11.hpp:6320
CLI11_NODISCARD bool get_positional() const
True if the argument can be given directly.
Definition CLI11.hpp:6024
std::string default_str_
A human readable default value, either manually set, captured, or captured by default.
Definition CLI11.hpp:5690
bool run_callback_for_default_
Control option to run the callback to set the default.
Definition CLI11.hpp:5759
CLI11_NODISCARD std::string get_envname() const
The environment variable associated to this value.
Definition CLI11.hpp:5969
CLI11_NODISCARD bool check_name(const std::string &name) const
Check a name. Requires "-" or "--" for short / long, supports positional name.
Definition CLI11.hpp:6624
Option * type_name(std::string typeval)
Set a custom option typestring.
Definition CLI11.hpp:6177
std::function< std::string()> type_name_
Definition CLI11.hpp:5698
option_state
enumeration for the option state machine
Definition CLI11.hpp:5746
@ reduced
a subset of results has been generated
Definition CLI11.hpp:5749
@ callback_run
the callback has been executed
Definition CLI11.hpp:5750
@ validated
the results have been validated
Definition CLI11.hpp:5748
@ parsing
The option is currently collecting parsed results.
Definition CLI11.hpp:5747
option_state current_option_state_
Whether the callback has run (needed for INI parsing).
Definition CLI11.hpp:5753
std::string option_text_
If given, replace the text that describes the option type and usage in the help text.
Definition CLI11.hpp:5693
int type_size_min_
The minimum number of arguments an option should be expecting.
Definition CLI11.hpp:5711
Option * callback_priority(CallbackPriority value=CallbackPriority::Normal)
Definition CLI11.hpp:5844
CLI11_NODISCARD results_t reduced_results() const
Get a copy of the results.
Definition CLI11.hpp:6719
CLI11_NODISCARD std::string get_type_name() const
Get the full typename for this option.
Definition CLI11.hpp:6780
CLI11_NODISCARD bool check_fname(std::string name) const
Requires "--" to be removed from string.
Definition CLI11.hpp:6089
std::string pname_
A positional name.
Definition CLI11.hpp:5677
int expected_min_
The minimum number of expected values.
Definition CLI11.hpp:5714
Option * transform(Validator_p validator)
Adds a shared Validator.
Definition CLI11.hpp:6349
Option * ignore_case(bool value=true)
Definition CLI11.hpp:6445
std::set< Option * > needs_
A list of options that are required with this option.
Definition CLI11.hpp:5722
Option * default_function(const std::function< std::string()> &func)
Set a capture function for the default. Mostly used by App.
Definition CLI11.hpp:6192
CLI11_NODISCARD int get_type_size_min() const
The minimum number of arguments the option expects.
Definition CLI11.hpp:5961
void run_callback()
Process the callback.
Definition CLI11.hpp:6553
CLI11_NODISCARD std::string get_name(bool positional=false, bool all_options=false, bool disable_default_flag_values=false) const
Gets a comma separated list of names. Will include / prefer the positional name if positional is true...
Definition CLI11.hpp:6500
CLI11_NODISCARD bool check_sname(std::string name) const
Requires "-" to be removed from string.
Definition CLI11.hpp:6079
bool trigger_on_result_
flag indicating that the option should trigger the validation and callback chain on each result when ...
Definition CLI11.hpp:5763
bool flag_like_
Specify that the option should act like a flag vs regular option.
Definition CLI11.hpp:5757
std::set< Option * > excludes_
A list of options that are excluded with this option.
Definition CLI11.hpp:5725
bool force_callback_
flag indicating that the option should force the callback regardless if any results present
Definition CLI11.hpp:5765
CLI11_NODISCARD bool get_callback_run() const
See if the callback has been run already.
Definition CLI11.hpp:6164
CLI11_NODISCARD bool get_force_callback() const
The status of force_callback.
Definition CLI11.hpp:5831
std::vector< std::string > fnames_
a list of flag names with specified default values;
Definition CLI11.hpp:5674
Option(std::string option_name, std::string option_description, callback_t callback, App *parent, bool allow_non_standard=false)
Making an option by hand is not defined, it must be made by the App class.
Definition CLI11.hpp:5768
CLI11_NODISCARD bool get_run_callback_for_default() const
Get the current value of run_callback_for_default.
Definition CLI11.hpp:5840
CLI11_NODISCARD std::string get_default_str() const
The default value (for help printing).
Definition CLI11.hpp:5978
CLI11_NODISCARD bool nonpositional() const
True if option has at least one non-positional name.
Definition CLI11.hpp:6027
CLI11_NODISCARD int get_items_expected_min() const
The total min number of expected string values to be used.
Definition CLI11.hpp:6013
CLI11_NODISCARD const std::string & matching_name(const Option &other) const
If options share any of the same names, find it.
Definition CLI11.hpp:6586
CLI11_NODISCARD bool check_lname(std::string name) const
Requires "--" to be removed from string.
Definition CLI11.hpp:6084
CLI11_NODISCARD const results_t & results() const
Get the current complete results set.
Definition CLI11.hpp:6110
Option * disable_flag_override(bool value=true)
Disable flag overrides values, e.g. –flag=is not allowed.
Definition CLI11.hpp:5949
CLI11_NODISCARD int get_items_expected_max() const
Get the maximum number of items expected to be returned and used for the callback.
Definition CLI11.hpp:6016
std::vector< std::string > snames_
A list of the short names (-a) without the leading dashes.
Definition CLI11.hpp:5664
results_t proc_results_
results after reduction
Definition CLI11.hpp:5744
bool remove_excludes(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition CLI11.hpp:6435
CLI11_NODISCARD std::size_t count() const
Count the total number of times an option was passed.
Definition CLI11.hpp:5785
Option * run_callback_for_default(bool value=true)
Definition CLI11.hpp:5835
void inject_separator(bool value=true)
Set the value of the separator injection flag.
Definition CLI11.hpp:6189
Option * allow_extra_args(bool value=true)
Definition CLI11.hpp:5811
Option * multi_option_policy(MultiOptionPolicy value=MultiOptionPolicy::Throw)
Take the last argument if given multiple times (or another policy).
Definition CLI11.hpp:6486
Option * trigger_on_parse(bool value=true)
Set the value of trigger_on_parse which specifies that the option callback should be triggered on eve...
Definition CLI11.hpp:5818
CLI11_NODISCARD callback_t get_callback() const
Get the callback function.
Definition CLI11.hpp:5981
CLI11_NODISCARD bool get_inject_separator() const
Return the inject_separator flag.
Definition CLI11.hpp:5966
std::vector< Validator_p > validators_
A list of Validators to run on each value parsed.
Definition CLI11.hpp:5719
Option * excludes(Option *opt)
Sets excluded options.
Definition CLI11.hpp:6420
App * parent_
link back up to the parent App for fallthrough
Definition CLI11.hpp:5732
CLI11_NODISCARD bool get_trigger_on_parse() const
The status of trigger on parse.
Definition CLI11.hpp:5823
CLI11_NODISCARD const std::vector< std::string > & get_lnames() const
Get the long names.
Definition CLI11.hpp:5984
int expected_max_
The maximum number of expected values.
Definition CLI11.hpp:5716
CLI11_NODISCARD std::set< Option * > get_excludes() const
The set of options excluded.
Definition CLI11.hpp:5975
CLI11_NODISCARD std::string get_flag_value(const std::string &name, std::string input_value) const
Definition CLI11.hpp:6653
Option * excludes(std::string opt_name)
Can find a string if needed.
Definition CLI11.hpp:5910
CLI11_NODISCARD int get_items_expected() const
The total min number of expected string values to be used.
Definition CLI11.hpp:6021
CLI11_NODISCARD std::set< Option * > get_needs() const
The set of options needed.
Definition CLI11.hpp:5972
std::string description_
The description for help strings.
Definition CLI11.hpp:5687
CLI11_NODISCARD const std::vector< std::string > & get_snames() const
Get the short names.
Definition CLI11.hpp:5987
CLI11_NODISCARD int get_type_size_max() const
The maximum number of arguments the option expects.
Definition CLI11.hpp:5963
bool inject_separator_
flag indicating a separator needs to be injected after each argument call
Definition CLI11.hpp:5761
CLI11_NODISCARD const std::string & get_description() const
Get the description.
Definition CLI11.hpp:6033
Validator * get_validator(const std::string &validator_name="")
Get a named Validator.
Definition CLI11.hpp:6390
CLI11_NODISCARD const std::string & get_single_name() const
Get a single name for the option, first of lname, sname, pname, envname.
Definition CLI11.hpp:5992
CLI11_NODISCARD int get_expected() const
The number of times the option expects to be included.
Definition CLI11.hpp:6005
callback_t callback_
Options store a callback to do all the work.
Definition CLI11.hpp:5735
CLI11_NODISCARD bool empty() const
True if the option was not passed.
Definition CLI11.hpp:5788
CLI11_NODISCARD int get_expected_min() const
The number of times the option expects to be included.
Definition CLI11.hpp:6008
void clear()
Clear the parsed results (mostly for testing).
Definition CLI11.hpp:5794
CLI11_NODISCARD int get_expected_max() const
The max number of times the option expects to be included.
Definition CLI11.hpp:6010
Option * capture_default_str()
Capture the default value from the original value (if it can be captured).
Definition CLI11.hpp:6198
void results(T &output) const
Get the results as a specified type.
Definition CLI11.hpp:6116
Option * default_str(std::string val)
Set the default value string representation (does not change the contained value).
Definition CLI11.hpp:6206
CLI11_NODISCARD int get_type_size() const
The number of arguments the option expects.
Definition CLI11.hpp:5958
std::string envname_
If given, check the environment for this option.
Definition CLI11.hpp:5680
std::function< std::string()> default_function_
Run this function to capture a default (ignore if empty).
Definition CLI11.hpp:5701
CLI11_NODISCARD bool get_allow_extra_args() const
Get the current value of allow extra args.
Definition CLI11.hpp:5816
Option * ignore_underscore(bool value=true)
Definition CLI11.hpp:6465
std::vector< std::pair< std::string, std::string > > default_flag_values_
Definition CLI11.hpp:5671
Option * envname(std::string name)
Sets environment variable to read if no option given.
Definition CLI11.hpp:5928
Option * type_name_fn(std::function< std::string()> typefun)
Set the type function to run when displayed on this option.
Definition CLI11.hpp:6171
Option * default_val(const X &val)
Definition CLI11.hpp:6213
Option * needs(Option *opt)
Sets required options.
Definition CLI11.hpp:5881
int type_size_max_
Definition CLI11.hpp:5709
Option * needs(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition CLI11.hpp:5898
bool allow_extra_args_
Specify that extra args beyond type_size_max should be allowed.
Definition CLI11.hpp:5755
Option * description(std::string option_description)
Set the description.
Definition CLI11.hpp:6036
std::vector< std::string > lnames_
A list of the long names (--long) without the leading dashes.
Definition CLI11.hpp:5667
Option * force_callback(bool value=true)
Set the value of force_callback.
Definition CLI11.hpp:5826
Option * add_result(std::string s)
Puts a result at the end.
Definition CLI11.hpp:6699
bool remove_needs(Option *opt)
Remove needs link from an option. Returns true if the option really was in the needs list.
Definition CLI11.hpp:6410
bool operator==(const Option &other) const
If options share any of the same names, they are equal (not counting positional).
Definition CLI11.hpp:6073
Option * each(const std::function< void(std::string)> &func)
Adds a user supplied function to run on each item passed in (communicate though lambda capture).
Definition CLI11.hpp:6379
Option * needs(std::string opt_name)
Can find a string if needed.
Definition CLI11.hpp:5889
CLI11_NODISCARD const std::vector< std::string > & get_fnames() const
Get the flag names with specified default values.
Definition CLI11.hpp:5990
CLI11_NODISCARD bool has_description() const
True if option has description.
Definition CLI11.hpp:6030
results_t results_
complete Results of parsing
Definition CLI11.hpp:5742
CLI11_NODISCARD T as() const
Return the results as the specified type.
Definition CLI11.hpp:6157
Option * excludes(A opt, B opt1, ARG... args)
Any number supported, any mix of string and Opt.
Definition CLI11.hpp:5919
Anything that can error in Parse.
Definition CLI11.hpp:1499
Produce a range (factory). Min and max are inclusive.
Definition CLI11.hpp:4091
Range(T min_val, T max_val, const std::string &validator_name=std::string{})
Definition CLI11.hpp:4098
Range(T max_val, const std::string &validator_name=std::string{})
Range of one value is 0 to value.
Definition CLI11.hpp:4121
Thrown when a required option is missing.
Definition CLI11.hpp:1568
Thrown when a requires option is missing.
Definition CLI11.hpp:1634
This is a successful completion on parsing, supposed to exit.
Definition CLI11.hpp:1506
Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other)
You can pass in as many filter functions as you like, they nest.
Definition CLI11.hpp:4763
Transformer(std::initializer_list< std::pair< std::string, std::string > > values, Args &&...args)
This allows in-place construction.
Definition CLI11.hpp:4718
Transformer(T &&mapping)
direct map of std::string to std::string
Definition CLI11.hpp:4722
Transformer(T mapping, F filter_function)
Definition CLI11.hpp:4726
Validate the input as a particular type.
Definition CLI11.hpp:4490
Thrown when validation of results fails.
Definition CLI11.hpp:1561
Some validators that are provided.
Definition CLI11.hpp:3898
Validator operator&(const Validator &other) const
Definition CLI11.hpp:4207
CLI11_NODISCARD int get_application_index() const
Get the current value of the application index.
Definition CLI11.hpp:3999
int application_index_
A Validator will only apply to an indexed value (-1 is all elements).
Definition CLI11.hpp:3909
Validator & non_modifying(bool no_modify=true)
Specify whether the Validator can be modifying or not.
Definition CLI11.hpp:3983
Validator & description(std::string validator_desc)
Specify the type string.
Definition CLI11.hpp:3943
std::string operator()(const std::string &str) const
Definition CLI11.hpp:3937
CLI11_NODISCARD Validator application_index(int app_index) const
Specify the application index of a validator.
Definition CLI11.hpp:3993
Validator operator|(const Validator &other) const
Definition CLI11.hpp:4229
CLI11_NODISCARD bool get_active() const
Get a boolean if the validator is active.
Definition CLI11.hpp:4001
bool active_
Enable for Validator to allow it to be disabled if need be.
Definition CLI11.hpp:3911
bool non_modifying_
specify that a validator should not modify the input
Definition CLI11.hpp:3913
Validator(std::string validator_desc)
Construct a Validator with just the description string.
Definition CLI11.hpp:3921
Validator & name(std::string validator_name)
Specify the type string.
Definition CLI11.hpp:3958
std::function< std::string()> desc_function_
This is the description function, if empty the description_ will be used.
Definition CLI11.hpp:3901
std::function< std::string(std::string &)> func_
Definition CLI11.hpp:3905
CLI11_NODISCARD std::string get_description() const
Generate type description information for the Validator.
Definition CLI11.hpp:3951
CLI11_NODISCARD Validator active(bool active_val=true) const
Specify whether the Validator is active or not.
Definition CLI11.hpp:3976
CLI11_NODISCARD const std::string & get_name() const
Get the name of the Validator.
Definition CLI11.hpp:3969
Validator & active(bool active_val=true)
Specify whether the Validator is active or not.
Definition CLI11.hpp:3971
std::string name_
The name for search purposes of the Validator.
Definition CLI11.hpp:3907
CLI11_NODISCARD bool get_modifying() const
Get a boolean if the validator is allowed to modify the input returns true if it can modify the input...
Definition CLI11.hpp:4004
CLI11_NODISCARD Validator name(std::string validator_name) const
Specify the type string.
Definition CLI11.hpp:3963
Validator operator!() const
Create a validator that fails when a given validator succeeds.
Definition CLI11.hpp:4251
std::string operator()(std::string &str) const
Definition CLI11.hpp:4188
Validator & application_index(int app_index)
Specify the application index of a validator.
Definition CLI11.hpp:3988
Validator(std::function< std::string(std::string &)> op, std::string validator_desc, std::string validator_name="")
Construct Validator from basic information.
Definition CLI11.hpp:3923
Validator & operation(std::function< std::string(std::string &)> op)
Set the Validator operation function.
Definition CLI11.hpp:3927
Definition CLI11.hpp:1770
Definition CLI11.hpp:4061
Check for an existing directory (returns error message if check fails).
Definition CLI11.hpp:4044
Check for an existing file (returns error message if check fails).
Definition CLI11.hpp:4038
Check for an existing path.
Definition CLI11.hpp:4050
Check for an non-existing path.
Definition CLI11.hpp:4056
Check for complex.
Definition CLI11.hpp:1909
Definition CLI11.hpp:1851
Check for input streamability.
Definition CLI11.hpp:1898
Definition CLI11.hpp:1887
Definition CLI11.hpp:1973
Definition CLI11.hpp:499
std::ostream & operator<<(std::ostream &in, const T &item)
output streaming for enumerations
Definition CLI11.hpp:503
Holds values to load into Options.
Definition CLI11.hpp:3705
std::vector< std::string > inputs
Listing of inputs.
Definition CLI11.hpp:3712
std::string name
This is the name.
Definition CLI11.hpp:3710
CLI11_NODISCARD std::string fullname() const
The list of parents and name joined by ".".
Definition CLI11.hpp:3716
bool multiline
indicator if a multiline vector separator was inserted
Definition CLI11.hpp:3714
std::vector< std::string > parents
This is the list of parents.
Definition CLI11.hpp:3707
This can be specialized to override the type deduction for IsMember.
Definition CLI11.hpp:1755
This class is simply to allow tests access to App's protected functions.
Definition CLI11.hpp:8479
static auto parse_subcommand(App *app, Args &&...args) -> typename std::result_of< decltype(&App::_parse_subcommand)(App, Args...)>::type
Wrap _parse_subcommand, perfectly forward arguments and return.
Definition CLI11.hpp:8501
static App * get_fallthrough_parent(App *app)
Wrap the fallthrough parent function to make sure that is working correctly.
Definition CLI11.hpp:8507
static auto parse_arg(App *app, Args &&...args) -> typename std::result_of< decltype(&App::_parse_arg)(App, Args...)>::type
Wrap _parse_short, perfectly forward arguments and return.
Definition CLI11.hpp:8494
static const App * get_fallthrough_parent(const App *app)
Wrap the const fallthrough parent function to make sure that is working correctly.
Definition CLI11.hpp:8510
not a pointer
Definition CLI11.hpp:1789
Definition CLI11.hpp:1799
Definition CLI11.hpp:4592
Definition CLI11.hpp:1934
Definition CLI11.hpp:1954
Definition CLI11.hpp:1965
static auto first(Q &&pair_value) -> decltype(std::get< 0 >(std::forward< Q >(pair_value)))
Get the first value (really just the underlying value).
Definition CLI11.hpp:1831
static auto second(Q &&pair_value) -> decltype(std::get< 1 >(std::forward< Q >(pair_value)))
Get the second value (really just the underlying value).
Definition CLI11.hpp:1835
Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost ...
Definition CLI11.hpp:1804
static auto second(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the second value (really just the underlying value).
Definition CLI11.hpp:1814
static auto first(Q &&pair_value) -> decltype(std::forward< Q >(pair_value))
Get the first value (really just the underlying value).
Definition CLI11.hpp:1810
forward declare the subtype_count_min structure
Definition CLI11.hpp:2175
Set of overloads to get the type size of an object.
Definition CLI11.hpp:2172
This will only trigger for actual void type.
Definition CLI11.hpp:1985
This will only trigger for actual void type.
Definition CLI11.hpp:2178
template to get the underlying value type if it exists or use a default
Definition CLI11.hpp:2160
Check to see if something is bool (fail check by default).
Definition CLI11.hpp:1735
Check to see if something is copyable pointer.
Definition CLI11.hpp:1750
Check to see if something is a shared pointer.
Definition CLI11.hpp:1741
A copy of std::void_t from C++17 (helper for C++11 and C++14).
Definition CLI11.hpp:1724