CLI11  2.1.2
Error.hpp
Go to the documentation of this file.
1 // Copyright (c) 2017-2021, 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 // [CLI11:public_includes:set]
10 #include <exception>
11 #include <stdexcept>
12 #include <string>
13 #include <utility>
14 #include <vector>
15 // [CLI11:public_includes:end]
16 
17 // CLI library includes
18 #include "StringTools.hpp"
19 
20 namespace CLI {
21 // [CLI11:error_hpp:verbatim]
22 
23 // Use one of these on all error classes.
24 // These are temporary and are undef'd at the end of this file.
25 #define CLI11_ERROR_DEF(parent, name) \
26  protected: \
27  name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
28  name(std::string ename, std::string msg, ExitCodes exit_code) \
29  : parent(std::move(ename), std::move(msg), exit_code) {} \
30  \
31  public: \
32  name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
33  name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
34 
35 // This is added after the one above if a class is used directly and builds its own message
36 #define CLI11_ERROR_SIMPLE(name) \
37  explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
38 
41 enum class ExitCodes {
42  Success = 0,
46  FileError,
58  BaseClass = 127
59 };
60 
61 // Error definitions
62 
68 
70 class Error : public std::runtime_error {
71  int actual_exit_code;
72  std::string error_name{"Error"};
73 
74  public:
75  int get_exit_code() const { return actual_exit_code; }
76 
77  std::string get_name() const { return error_name; }
78 
79  Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
80  : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
81 
82  Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
83 };
84 
85 // Note: Using Error::Error constructors does not work on GCC 4.7
86 
88 class ConstructionError : public Error {
90 };
91 
96  static IncorrectConstruction PositionalFlag(std::string name) {
97  return IncorrectConstruction(name + ": Flags cannot be positional");
98  }
99  static IncorrectConstruction Set0Opt(std::string name) {
100  return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
101  }
102  static IncorrectConstruction SetFlag(std::string name) {
103  return IncorrectConstruction(name + ": Cannot set an expected number for flags");
104  }
105  static IncorrectConstruction ChangeNotVector(std::string name) {
106  return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
107  }
108  static IncorrectConstruction AfterMultiOpt(std::string name) {
109  return IncorrectConstruction(
110  name + ": You can't change expected arguments after you've changed the multi option policy!");
111  }
112  static IncorrectConstruction MissingOption(std::string name) {
113  return IncorrectConstruction("Option " + name + " is not defined");
114  }
115  static IncorrectConstruction MultiOptionPolicy(std::string name) {
116  return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
117  }
118 };
119 
124  static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
125  static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
126  static BadNameString DashesOnly(std::string name) {
127  return BadNameString("Must have a name, not just dashes: " + name);
128  }
129  static BadNameString MultiPositionalNames(std::string name) {
130  return BadNameString("Only one positional name allowed, remove: " + name);
131  }
132 };
133 
137  explicit OptionAlreadyAdded(std::string name)
138  : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
139  static OptionAlreadyAdded Requires(std::string name, std::string other) {
140  return OptionAlreadyAdded(name + " requires " + other, ExitCodes::OptionAlreadyAdded);
141  }
142  static OptionAlreadyAdded Excludes(std::string name, std::string other) {
143  return OptionAlreadyAdded(name + " excludes " + other, ExitCodes::OptionAlreadyAdded);
144  }
145 };
146 
147 // Parsing errors
148 
150 class ParseError : public Error {
152 };
153 
154 // Not really "errors"
155 
157 class Success : public ParseError {
159  Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
160 };
161 
163 class CallForHelp : public Success {
165  CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
166 };
167 
169 class CallForAllHelp : public Success {
172  : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
173 };
174 
176 class CallForVersion : public Success {
179  : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
180 };
181 
183 class RuntimeError : public ParseError {
185  explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
186 };
187 
189 class FileError : public ParseError {
192  static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
193 };
194 
196 class ConversionError : public ParseError {
199  ConversionError(std::string member, std::string name)
200  : ConversionError("The value " + member + " is not an allowed value for " + name) {}
201  ConversionError(std::string name, std::vector<std::string> results)
202  : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
203  static ConversionError TooManyInputsFlag(std::string name) {
204  return ConversionError(name + ": too many inputs for a flag");
205  }
206  static ConversionError TrueFalse(std::string name) {
207  return ConversionError(name + ": Should be true/false or a number");
208  }
209 };
210 
212 class ValidationError : public ParseError {
215  explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
216 };
217 
219 class RequiredError : public ParseError {
221  explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
222  static RequiredError Subcommand(std::size_t min_subcom) {
223  if(min_subcom == 1) {
224  return RequiredError("A subcommand");
225  }
226  return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands",
228  }
229  static RequiredError
230  Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) {
231  if((min_option == 1) && (max_option == 1) && (used == 0))
232  return RequiredError("Exactly 1 option from [" + option_list + "]");
233  if((min_option == 1) && (max_option == 1) && (used > 1)) {
234  return RequiredError("Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) +
235  " were given",
237  }
238  if((min_option == 1) && (used == 0))
239  return RequiredError("At least 1 option from [" + option_list + "]");
240  if(used < min_option) {
241  return RequiredError("Requires at least " + std::to_string(min_option) + " options used and only " +
242  std::to_string(used) + "were given from [" + option_list + "]",
244  }
245  if(max_option == 1)
246  return RequiredError("Requires at most 1 options be given from [" + option_list + "]",
248 
249  return RequiredError("Requires at most " + std::to_string(max_option) + " options be used and " +
250  std::to_string(used) + "were given from [" + option_list + "]",
252  }
253 };
254 
256 class ArgumentMismatch : public ParseError {
259  ArgumentMismatch(std::string name, int expected, std::size_t received)
260  : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
261  ", got " + std::to_string(received))
262  : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
263  ", got " + std::to_string(received)),
265 
266  static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) {
267  return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " +
268  std::to_string(received));
269  }
270  static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) {
271  return ArgumentMismatch(name + ": At Most " + std::to_string(num) + " required but received " +
272  std::to_string(received));
273  }
274  static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
275  return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
276  }
277  static ArgumentMismatch FlagOverride(std::string name) {
278  return ArgumentMismatch(name + " was given a disallowed flag override");
279  }
280 };
281 
283 class RequiresError : public ParseError {
285  RequiresError(std::string curname, std::string subname)
286  : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
287 };
288 
290 class ExcludesError : public ParseError {
292  ExcludesError(std::string curname, std::string subname)
293  : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
294 };
295 
297 class ExtrasError : public ParseError {
299  explicit ExtrasError(std::vector<std::string> args)
300  : ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
301  : "The following argument was not expected: ") +
302  detail::rjoin(args, " "),
304  ExtrasError(const std::string &name, std::vector<std::string> args)
305  : ExtrasError(name,
306  (args.size() > 1 ? "The following arguments were not expected: "
307  : "The following argument was not expected: ") +
308  detail::rjoin(args, " "),
310 };
311 
313 class ConfigError : public ParseError {
316  static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); }
317  static ConfigError NotConfigurable(std::string item) {
318  return ConfigError(item + ": This option is not allowed in a configuration file");
319  }
320 };
321 
323 class InvalidError : public ParseError {
325  explicit InvalidError(std::string name)
326  : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
327  }
328 };
329 
332 class HorribleError : public ParseError {
335 };
336 
337 // After parsing
338 
340 class OptionNotFound : public Error {
342  explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
343 };
344 
345 #undef CLI11_ERROR_DEF
346 #undef CLI11_ERROR_SIMPLE
347 
349 
350 // [CLI11:error_hpp:end]
351 } // namespace CLI
#define CLI11_ERROR_SIMPLE(name)
Definition: Error.hpp:36
#define CLI11_ERROR_DEF(parent, name)
Definition: Error.hpp:25
Thrown when the wrong number of arguments has been received.
Definition: Error.hpp:256
Thrown on construction of a bad name.
Definition: Error.hpp:121
Usually something like –help-all on command line.
Definition: Error.hpp:169
-h or –help on command line
Definition: Error.hpp:163
-v or –version on command line
Definition: Error.hpp:176
Thrown when extra values are found in an INI file.
Definition: Error.hpp:313
Construction errors (not in parsing)
Definition: Error.hpp:88
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition: Error.hpp:196
All errors derive from this one.
Definition: Error.hpp:70
int get_exit_code() const
Definition: Error.hpp:75
Error(std::string name, std::string msg, ExitCodes exit_code)
Definition: Error.hpp:82
std::string get_name() const
Definition: Error.hpp:77
Error(std::string name, std::string msg, int exit_code=static_cast< int >(ExitCodes::BaseClass))
Definition: Error.hpp:79
Thrown when an excludes option is present.
Definition: Error.hpp:290
Thrown when too many positionals or options are found.
Definition: Error.hpp:297
Thrown when parsing an INI file and it is missing.
Definition: Error.hpp:189
Definition: Error.hpp:332
Thrown when an option is set to conflicting values (non-vector and multi args, for example)
Definition: Error.hpp:93
Thrown when validation fails before parsing.
Definition: Error.hpp:323
Thrown when an option already exists.
Definition: Error.hpp:135
Thrown when counting a non-existent option.
Definition: Error.hpp:340
Definition: Option.hpp:237
Anything that can error in Parse.
Definition: Error.hpp:150
Thrown when a required option is missing.
Definition: Error.hpp:219
Thrown when a requires option is missing.
Definition: Error.hpp:283
Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code.
Definition: Error.hpp:183
This is a successful completion on parsing, supposed to exit.
Definition: Error.hpp:157
Thrown when validation of results fails.
Definition: Error.hpp:212
auto to_string(T &&value) -> decltype(std::forward< T >(value))
Convert an object to a string (directly forward if this can become a string)
Definition: TypeTools.hpp:269
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition: StringTools.hpp:63
std::string rjoin(const T &v, std::string delim=",")
Join a string in reverse order.
Definition: StringTools.hpp:96
Definition: App.hpp:34
ExitCodes
Definition: Error.hpp:41
MultiOptionPolicy
Enumeration of the multiOption Policy selection.
Definition: Option.hpp:38