CLI11
2.7.1
C++11 Command Line Interface Parser
Toggle main menu visibility
Loading...
Searching...
No Matches
Error.hpp
1
// Copyright (c) 2017-2026, University of Cincinnati, developed by Henry Schreiner
2
// under NSF AWARD 1414736 and by the respective contributors.
3
// All rights reserved.
4
//
5
// SPDX-License-Identifier: BSD-3-Clause
6
7
#pragma once
8
9
// IWYU pragma: private, include "CLI/CLI.hpp"
10
11
// [CLI11:public_includes:set]
12
#include <exception>
13
#include <stdexcept>
14
#include <string>
15
#include <utility>
16
#include <vector>
17
// [CLI11:public_includes:end]
18
19
// CLI library includes
20
#include "Macros.hpp"
21
#include "StringTools.hpp"
22
23
namespace
CLI {
24
// [CLI11:error_hpp:verbatim]
25
26
// Use one of these on all error classes.
27
// These are temporary and are undef'd at the end of this file.
28
#define CLI11_ERROR_DEF(parent, name) \
29
protected: \
30
name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
31
name(std::string ename, std::string msg, ExitCodes exit_code) \
32
: parent(std::move(ename), std::move(msg), exit_code) {} \
33
\
34
public: \
35
name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
36
name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
37
38
// This is added after the one above if a class is used directly and builds its own message
39
#define CLI11_ERROR_SIMPLE(name) \
40
explicit name(std::string msg) : name(#name, std::move(msg), ExitCodes::name) {}
41
44
enum class
ExitCodes :
int
{
45
Success
= 0,
46
IncorrectConstruction
= 100,
47
BadNameString
,
48
OptionAlreadyAdded
,
49
FileError
,
50
ConversionError
,
51
ValidationError
,
52
RequiredError
,
53
RequiresError
,
54
ExcludesError
,
55
ExtrasError
,
56
ConfigError
,
57
InvalidError
,
58
HorribleError
,
59
OptionNotFound
,
60
ArgumentMismatch
,
61
BaseClass = 127
62
};
63
64
// Error definitions
65
71
73
class
Error :
public
std::runtime_error {
74
int
actual_exit_code;
75
std::string error_name{
"Error"
};
76
77
public
:
78
CLI11_NODISCARD
int
get_exit_code()
const
{
return
actual_exit_code; }
79
80
CLI11_NODISCARD std::string get_name()
const
{
return
error_name; }
81
82
Error(std::string name, std::string msg,
int
exit_code =
static_cast<
int
>
(ExitCodes::BaseClass))
83
: runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
84
85
Error(std::string name, std::string msg, ExitCodes exit_code)
86
: Error(std::move(name), std::move(msg),
static_cast<
int
>
(exit_code)) {}
87
};
88
89
// Note: Using Error::Error constructors does not work on GCC 4.7
90
92
class
ConstructionError
:
public
Error {
93
CLI11_ERROR_DEF(Error,
ConstructionError
)
94
};
95
97
class
IncorrectConstruction
:
public
ConstructionError
{
98
CLI11_ERROR_DEF(
ConstructionError
,
IncorrectConstruction
)
99
CLI11_ERROR_SIMPLE(
IncorrectConstruction
)
100
static
IncorrectConstruction
PositionalFlag(std::string name) {
101
return
IncorrectConstruction
(name +
": Flags cannot be positional"
);
102
}
103
static
IncorrectConstruction
Set0Opt(std::string name) {
104
return
IncorrectConstruction
(name +
": Cannot set 0 expected, use a flag instead"
);
105
}
106
static
IncorrectConstruction
SetFlag(std::string name) {
107
return
IncorrectConstruction
(name +
": Cannot set an expected number for flags"
);
108
}
109
static
IncorrectConstruction
ChangeNotVector(std::string name) {
110
return
IncorrectConstruction
(name +
": You can only change the expected arguments for vectors"
);
111
}
112
static
IncorrectConstruction
AfterMultiOpt(std::string name) {
113
return
IncorrectConstruction
(
114
name +
": You can't change expected arguments after you've changed the multi option policy!"
);
115
}
116
static
IncorrectConstruction
MissingOption(std::string name) {
117
return
IncorrectConstruction
(
"Option "
+ name +
" is not defined"
);
118
}
119
static
IncorrectConstruction
MultiOptionPolicy(std::string name) {
120
return
IncorrectConstruction
(name +
": multi_option_policy only works for flags and exact value options"
);
121
}
122
};
123
125
class
BadNameString
:
public
ConstructionError
{
126
CLI11_ERROR_DEF(
ConstructionError
,
BadNameString
)
127
CLI11_ERROR_SIMPLE(
BadNameString
)
128
static
BadNameString
OneCharName(std::string name) {
return
BadNameString
(
"Invalid one char name: "
+ name); }
129
static
BadNameString
MissingDash(std::string name) {
130
return
BadNameString
(
"Long names strings require 2 dashes "
+ name);
131
}
132
static
BadNameString
BadLongName(std::string name) {
return
BadNameString
(
"Bad long name: "
+ name); }
133
static
BadNameString
BadPositionalName(std::string name) {
134
return
BadNameString
(
"Invalid positional Name: "
+ name);
135
}
136
static
BadNameString
ReservedName(std::string name) {
137
return
BadNameString
(
"Names '-','--','++' are reserved and not allowed as option names "
+ name);
138
}
139
static
BadNameString
MultiPositionalNames(std::string name) {
140
return
BadNameString
(
"Only one positional name allowed, remove: "
+ name);
141
}
142
};
143
145
class
OptionAlreadyAdded :
public
ConstructionError
{
146
CLI11_ERROR_DEF(
ConstructionError
, OptionAlreadyAdded)
147
explicit
OptionAlreadyAdded(std::string name)
148
: OptionAlreadyAdded(name +
" is already added"
, ExitCodes::OptionAlreadyAdded) {}
149
static
OptionAlreadyAdded Requires(std::string name, std::string other) {
150
return
{name +
" requires "
+ other, ExitCodes::OptionAlreadyAdded};
151
}
152
static
OptionAlreadyAdded Excludes(std::string name, std::string other) {
153
return
{name +
" excludes "
+ other, ExitCodes::OptionAlreadyAdded};
154
}
155
};
156
157
// Parsing errors
158
160
class
ParseError
:
public
Error {
161
CLI11_ERROR_DEF(Error,
ParseError
)
162
};
163
164
// Not really "errors"
165
167
class
Success :
public
ParseError
{
168
CLI11_ERROR_DEF(
ParseError
, Success)
169
Success() : Success(
"Successfully completed, should be caught and quit"
, ExitCodes::Success) {}
170
};
171
173
class
CallForHelp :
public
Success {
174
CLI11_ERROR_DEF(Success, CallForHelp)
175
CallForHelp() : CallForHelp(
"This should be caught in your main function, see examples"
, ExitCodes::Success) {}
176
};
177
179
class
CallForAllHelp :
public
Success {
180
CLI11_ERROR_DEF(Success, CallForAllHelp)
181
CallForAllHelp()
182
: CallForAllHelp(
"This should be caught in your main function, see examples"
, ExitCodes::Success) {}
183
};
184
186
class
CallForVersion :
public
Success {
187
CLI11_ERROR_DEF(Success, CallForVersion)
188
CallForVersion()
189
: CallForVersion(
"This should be caught in your main function, see examples"
, ExitCodes::Success) {}
190
};
191
193
class
RuntimeError :
public
ParseError
{
194
CLI11_ERROR_DEF(
ParseError
, RuntimeError)
195
explicit
RuntimeError(
int
exit_code = 1) : RuntimeError(
"Runtime error"
, exit_code) {}
196
};
197
199
class
FileError
:
public
ParseError
{
200
CLI11_ERROR_DEF(
ParseError
,
FileError
)
201
CLI11_ERROR_SIMPLE(
FileError
)
202
static
FileError
Missing(std::string name) {
return
FileError
(name +
" was not readable (missing?)"
); }
203
};
204
206
class
ConversionError :
public
ParseError
{
207
CLI11_ERROR_DEF(
ParseError
, ConversionError)
208
CLI11_ERROR_SIMPLE(ConversionError)
209
ConversionError(std::string member, std::string name)
210
: ConversionError(
"The value "
+ member +
" is not an allowed value for "
+ name) {}
211
ConversionError(std::string name, std::vector<std::string> results)
212
: ConversionError(
"Could not convert: "
+ name +
" = "
+ detail::join(results)) {}
213
static
ConversionError TooManyInputsFlag(std::string name) {
214
return
ConversionError(name +
": too many inputs for a flag"
);
215
}
216
static
ConversionError TrueFalse(std::string name) {
217
return
ConversionError(name +
": Should be true/false or a number"
);
218
}
219
};
220
222
class
ValidationError :
public
ParseError
{
223
CLI11_ERROR_DEF(
ParseError
, ValidationError)
224
CLI11_ERROR_SIMPLE(ValidationError)
225
explicit
ValidationError(std::string name, std::string msg) : ValidationError(name +
": "
+ msg) {}
226
};
227
229
class
RequiredError :
public
ParseError
{
230
CLI11_ERROR_DEF(
ParseError
, RequiredError)
231
explicit
RequiredError(std::string name) : RequiredError(name +
" is required"
, ExitCodes::RequiredError) {}
232
static
RequiredError Subcommand(std::size_t min_subcom) {
233
if
(min_subcom == 1) {
234
return
RequiredError(
"A subcommand"
);
235
}
236
return
{
"Requires at least "
+ std::to_string(min_subcom) +
" subcommands"
, ExitCodes::RequiredError};
237
}
238
static
RequiredError
239
Option(std::size_t min_option, std::size_t max_option, std::size_t used,
const
std::string &option_list) {
240
if
((min_option == 1) && (max_option == 1) && (used == 0))
241
return
RequiredError(
"Exactly 1 option from ["
+ option_list +
"]"
);
242
if
((min_option == 1) && (max_option == 1) && (used > 1)) {
243
return
{
"Exactly 1 option from ["
+ option_list +
"] is required but "
+ std::to_string(used) +
244
" were given"
,
245
ExitCodes::RequiredError};
246
}
247
if
((min_option == 1) && (used == 0))
248
return
RequiredError(
"At least 1 option from ["
+ option_list +
"]"
);
249
if
(used < min_option) {
250
return
{
"Requires at least "
+ std::to_string(min_option) +
" options used but only "
+
251
std::to_string(used) +
" were given from ["
+ option_list +
"]"
,
252
ExitCodes::RequiredError};
253
}
254
if
(max_option == 1)
255
return
{
"Requires at most 1 options be given from ["
+ option_list +
"]"
, ExitCodes::RequiredError};
256
257
return
{
"Requires at most "
+ std::to_string(max_option) +
" options be used but "
+ std::to_string(used) +
258
" were given from ["
+ option_list +
"]"
,
259
ExitCodes::RequiredError};
260
}
261
};
262
264
class
ArgumentMismatch :
public
ParseError
{
265
CLI11_ERROR_DEF(
ParseError
, ArgumentMismatch)
266
CLI11_ERROR_SIMPLE(ArgumentMismatch)
267
ArgumentMismatch(std::string name,
int
expected, std::size_t received)
268
: ArgumentMismatch(expected > 0 ? (
"Expected exactly "
+ std::to_string(expected) +
" arguments to "
+ name +
269
", got "
+ std::to_string(received))
270
: (
"Expected at least "
+ std::to_string(-expected) +
" arguments to "
+ name +
271
", got "
+ std::to_string(received)),
272
ExitCodes::ArgumentMismatch) {}
273
274
static
ArgumentMismatch AtLeast(std::string name,
int
num, std::size_t received) {
275
return
ArgumentMismatch(name +
": At least "
+ std::to_string(num) +
" required but received "
+
276
std::to_string(received));
277
}
278
static
ArgumentMismatch AtMost(std::string name,
int
num, std::size_t received) {
279
return
ArgumentMismatch(name +
": At most "
+ std::to_string(num) +
" required but received "
+
280
std::to_string(received));
281
}
282
static
ArgumentMismatch TypedAtLeast(std::string name,
int
num, std::string type) {
283
return
ArgumentMismatch(name +
": "
+ std::to_string(num) +
" required "
+ type +
" missing"
);
284
}
285
static
ArgumentMismatch FlagOverride(std::string name) {
286
return
ArgumentMismatch(name +
" was given a disallowed flag override"
);
287
}
288
static
ArgumentMismatch PartialType(std::string name,
int
num, std::string type) {
289
return
ArgumentMismatch(name +
": "
+ type +
" only partially specified: "
+ std::to_string(num) +
290
" required for each element"
);
291
}
292
};
293
295
class
RequiresError :
public
ParseError
{
296
CLI11_ERROR_DEF(
ParseError
, RequiresError)
297
RequiresError(std::string curname, std::string subname)
298
: RequiresError(curname +
" requires "
+ subname, ExitCodes::RequiresError) {}
299
};
300
302
class
ExcludesError :
public
ParseError
{
303
CLI11_ERROR_DEF(
ParseError
, ExcludesError)
304
ExcludesError(std::string curname, std::string subname)
305
: ExcludesError(curname +
" excludes "
+ subname, ExitCodes::ExcludesError) {}
306
};
307
309
class
ExtrasError :
public
ParseError
{
310
CLI11_ERROR_DEF(
ParseError
, ExtrasError)
311
explicit
ExtrasError(std::vector<std::string> args)
312
: ExtrasError((args.size() > 1 ?
"The following arguments were not expected: "
313
:
"The following argument was not expected: "
) +
314
detail::join(args,
" "
),
315
ExitCodes::ExtrasError) {}
316
ExtrasError(
const
std::string &name, std::vector<std::string> args)
317
: ExtrasError((name.empty() ? std::string{} : name +
": "
) +
318
(args.size() > 1 ?
"The following arguments were not expected: "
319
:
"The following argument was not expected: "
) +
320
detail::join(args,
" "
),
321
ExitCodes::ExtrasError) {}
322
};
323
325
class
ConfigError
:
public
ParseError
{
326
CLI11_ERROR_DEF(
ParseError
,
ConfigError
)
327
CLI11_ERROR_SIMPLE(
ConfigError
)
328
static
ConfigError
Extras(std::string item) {
return
ConfigError
(
"INI was not able to parse "
+ item); }
329
static
ConfigError
NotConfigurable(std::string item) {
330
return
ConfigError
(item +
": This option is not allowed in a configuration file"
);
331
}
332
};
333
335
class
InvalidError :
public
ParseError
{
336
CLI11_ERROR_DEF(
ParseError
, InvalidError)
337
explicit
InvalidError(std::string name)
338
: InvalidError(name +
": Too many positional arguments with unlimited expected args"
, ExitCodes::InvalidError) {
339
}
340
};
341
344
class
HorribleError
:
public
ParseError
{
345
CLI11_ERROR_DEF(
ParseError
,
HorribleError
)
346
CLI11_ERROR_SIMPLE(
HorribleError
)
347
};
348
349
// After parsing
350
352
class
OptionNotFound :
public
Error {
353
CLI11_ERROR_DEF(Error, OptionNotFound)
354
explicit
OptionNotFound(std::string name) : OptionNotFound(name +
" not found"
, ExitCodes::OptionNotFound) {}
355
};
356
357
#undef CLI11_ERROR_DEF
358
#undef CLI11_ERROR_SIMPLE
359
361
362
// [CLI11:error_hpp:end]
363
}
// namespace CLI
CLI::ArgumentMismatch
Thrown when the wrong number of arguments has been received.
Definition
Error.hpp:264
CLI::BadNameString
Thrown on construction of a bad name.
Definition
Error.hpp:125
CLI::ConfigError
Thrown when extra values are found in an INI file.
Definition
Error.hpp:325
CLI::ConstructionError
Construction errors (not in parsing).
Definition
Error.hpp:92
CLI::ConversionError
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition
Error.hpp:206
CLI::ExcludesError
Thrown when an excludes option is present.
Definition
Error.hpp:302
CLI::ExtrasError
Thrown when too many positionals or options are found.
Definition
Error.hpp:309
CLI::FileError
Thrown when parsing an INI file and it is missing.
Definition
Error.hpp:199
CLI::HorribleError
Definition
Error.hpp:344
CLI::IncorrectConstruction
Thrown when an option is set to conflicting values (non-vector and multi args, for example).
Definition
Error.hpp:97
CLI::InvalidError
Thrown when validation fails before parsing.
Definition
Error.hpp:335
CLI::OptionAlreadyAdded
Thrown when an option already exists.
Definition
Error.hpp:145
CLI::OptionNotFound
Thrown when counting a nonexistent option.
Definition
Error.hpp:352
CLI::ParseError
Anything that can error in Parse.
Definition
Error.hpp:160
CLI::RequiredError
Thrown when a required option is missing.
Definition
Error.hpp:229
CLI::RequiresError
Thrown when a requires option is missing.
Definition
Error.hpp:295
CLI::Success
This is a successful completion on parsing, supposed to exit.
Definition
Error.hpp:167
CLI::ValidationError
Thrown when validation of results fails.
Definition
Error.hpp:222
include
CLI
Error.hpp
Generated by
1.17.0