File indexing completed on 2025-07-15 08:52:29
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010
0011
0012 #include <exception>
0013 #include <stdexcept>
0014 #include <string>
0015 #include <utility>
0016 #include <vector>
0017
0018
0019
0020 #include "Macros.hpp"
0021 #include "StringTools.hpp"
0022
0023 namespace CLI {
0024
0025
0026
0027
0028 #define CLI11_ERROR_DEF(parent, name) \
0029 protected: \
0030 name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
0031 name(std::string ename, std::string msg, ExitCodes exit_code) \
0032 : parent(std::move(ename), std::move(msg), exit_code) {} \
0033 \
0034 public: \
0035 name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
0036 name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
0037
0038
0039 #define CLI11_ERROR_SIMPLE(name) \
0040 explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
0041
0042
0043
0044 enum class ExitCodes {
0045 Success = 0,
0046 IncorrectConstruction = 100,
0047 BadNameString,
0048 OptionAlreadyAdded,
0049 FileError,
0050 ConversionError,
0051 ValidationError,
0052 RequiredError,
0053 RequiresError,
0054 ExcludesError,
0055 ExtrasError,
0056 ConfigError,
0057 InvalidError,
0058 HorribleError,
0059 OptionNotFound,
0060 ArgumentMismatch,
0061 BaseClass = 127
0062 };
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 class Error : public std::runtime_error {
0074 int actual_exit_code;
0075 std::string error_name{"Error"};
0076
0077 public:
0078 CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; }
0079
0080 CLI11_NODISCARD std::string get_name() const { return error_name; }
0081
0082 Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
0083 : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
0084
0085 Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
0086 };
0087
0088
0089
0090
0091 class ConstructionError : public Error {
0092 CLI11_ERROR_DEF(Error, ConstructionError)
0093 };
0094
0095
0096 class IncorrectConstruction : public ConstructionError {
0097 CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
0098 CLI11_ERROR_SIMPLE(IncorrectConstruction)
0099 static IncorrectConstruction PositionalFlag(std::string name) {
0100 return IncorrectConstruction(name + ": Flags cannot be positional");
0101 }
0102 static IncorrectConstruction Set0Opt(std::string name) {
0103 return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
0104 }
0105 static IncorrectConstruction SetFlag(std::string name) {
0106 return IncorrectConstruction(name + ": Cannot set an expected number for flags");
0107 }
0108 static IncorrectConstruction ChangeNotVector(std::string name) {
0109 return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
0110 }
0111 static IncorrectConstruction AfterMultiOpt(std::string name) {
0112 return IncorrectConstruction(
0113 name + ": You can't change expected arguments after you've changed the multi option policy!");
0114 }
0115 static IncorrectConstruction MissingOption(std::string name) {
0116 return IncorrectConstruction("Option " + name + " is not defined");
0117 }
0118 static IncorrectConstruction MultiOptionPolicy(std::string name) {
0119 return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
0120 }
0121 };
0122
0123
0124 class BadNameString : public ConstructionError {
0125 CLI11_ERROR_DEF(ConstructionError, BadNameString)
0126 CLI11_ERROR_SIMPLE(BadNameString)
0127 static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
0128 static BadNameString MissingDash(std::string name) {
0129 return BadNameString("Long names strings require 2 dashes " + name);
0130 }
0131 static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
0132 static BadNameString BadPositionalName(std::string name) {
0133 return BadNameString("Invalid positional Name: " + name);
0134 }
0135 static BadNameString DashesOnly(std::string name) {
0136 return BadNameString("Must have a name, not just dashes: " + name);
0137 }
0138 static BadNameString MultiPositionalNames(std::string name) {
0139 return BadNameString("Only one positional name allowed, remove: " + name);
0140 }
0141 };
0142
0143
0144 class OptionAlreadyAdded : public ConstructionError {
0145 CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
0146 explicit OptionAlreadyAdded(std::string name)
0147 : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
0148 static OptionAlreadyAdded Requires(std::string name, std::string other) {
0149 return {name + " requires " + other, ExitCodes::OptionAlreadyAdded};
0150 }
0151 static OptionAlreadyAdded Excludes(std::string name, std::string other) {
0152 return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded};
0153 }
0154 };
0155
0156
0157
0158
0159 class ParseError : public Error {
0160 CLI11_ERROR_DEF(Error, ParseError)
0161 };
0162
0163
0164
0165
0166 class Success : public ParseError {
0167 CLI11_ERROR_DEF(ParseError, Success)
0168 Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
0169 };
0170
0171
0172 class CallForHelp : public Success {
0173 CLI11_ERROR_DEF(Success, CallForHelp)
0174 CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
0175 };
0176
0177
0178 class CallForAllHelp : public Success {
0179 CLI11_ERROR_DEF(Success, CallForAllHelp)
0180 CallForAllHelp()
0181 : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
0182 };
0183
0184
0185 class CallForVersion : public Success {
0186 CLI11_ERROR_DEF(Success, CallForVersion)
0187 CallForVersion()
0188 : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
0189 };
0190
0191
0192 class RuntimeError : public ParseError {
0193 CLI11_ERROR_DEF(ParseError, RuntimeError)
0194 explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
0195 };
0196
0197
0198 class FileError : public ParseError {
0199 CLI11_ERROR_DEF(ParseError, FileError)
0200 CLI11_ERROR_SIMPLE(FileError)
0201 static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
0202 };
0203
0204
0205 class ConversionError : public ParseError {
0206 CLI11_ERROR_DEF(ParseError, ConversionError)
0207 CLI11_ERROR_SIMPLE(ConversionError)
0208 ConversionError(std::string member, std::string name)
0209 : ConversionError("The value " + member + " is not an allowed value for " + name) {}
0210 ConversionError(std::string name, std::vector<std::string> results)
0211 : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
0212 static ConversionError TooManyInputsFlag(std::string name) {
0213 return ConversionError(name + ": too many inputs for a flag");
0214 }
0215 static ConversionError TrueFalse(std::string name) {
0216 return ConversionError(name + ": Should be true/false or a number");
0217 }
0218 };
0219
0220
0221 class ValidationError : public ParseError {
0222 CLI11_ERROR_DEF(ParseError, ValidationError)
0223 CLI11_ERROR_SIMPLE(ValidationError)
0224 explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
0225 };
0226
0227
0228 class RequiredError : public ParseError {
0229 CLI11_ERROR_DEF(ParseError, RequiredError)
0230 explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
0231 static RequiredError Subcommand(std::size_t min_subcom) {
0232 if(min_subcom == 1) {
0233 return RequiredError("A subcommand");
0234 }
0235 return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError};
0236 }
0237 static RequiredError
0238 Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) {
0239 if((min_option == 1) && (max_option == 1) && (used == 0))
0240 return RequiredError("Exactly 1 option from [" + option_list + "]");
0241 if((min_option == 1) && (max_option == 1) && (used > 1)) {
0242 return {"Exactly 1 option from [" + option_list + "] is required but " + std::to_string(used) +
0243 " were given",
0244 ExitCodes::RequiredError};
0245 }
0246 if((min_option == 1) && (used == 0))
0247 return RequiredError("At least 1 option from [" + option_list + "]");
0248 if(used < min_option) {
0249 return {"Requires at least " + std::to_string(min_option) + " options used but only " +
0250 std::to_string(used) + " were given from [" + option_list + "]",
0251 ExitCodes::RequiredError};
0252 }
0253 if(max_option == 1)
0254 return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError};
0255
0256 return {"Requires at most " + std::to_string(max_option) + " options be used but " + std::to_string(used) +
0257 " were given from [" + option_list + "]",
0258 ExitCodes::RequiredError};
0259 }
0260 };
0261
0262
0263 class ArgumentMismatch : public ParseError {
0264 CLI11_ERROR_DEF(ParseError, ArgumentMismatch)
0265 CLI11_ERROR_SIMPLE(ArgumentMismatch)
0266 ArgumentMismatch(std::string name, int expected, std::size_t received)
0267 : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
0268 ", got " + std::to_string(received))
0269 : ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
0270 ", got " + std::to_string(received)),
0271 ExitCodes::ArgumentMismatch) {}
0272
0273 static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) {
0274 return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " +
0275 std::to_string(received));
0276 }
0277 static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) {
0278 return ArgumentMismatch(name + ": At Most " + std::to_string(num) + " required but received " +
0279 std::to_string(received));
0280 }
0281 static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
0282 return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
0283 }
0284 static ArgumentMismatch FlagOverride(std::string name) {
0285 return ArgumentMismatch(name + " was given a disallowed flag override");
0286 }
0287 static ArgumentMismatch PartialType(std::string name, int num, std::string type) {
0288 return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) +
0289 " required for each element");
0290 }
0291 };
0292
0293
0294 class RequiresError : public ParseError {
0295 CLI11_ERROR_DEF(ParseError, RequiresError)
0296 RequiresError(std::string curname, std::string subname)
0297 : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
0298 };
0299
0300
0301 class ExcludesError : public ParseError {
0302 CLI11_ERROR_DEF(ParseError, ExcludesError)
0303 ExcludesError(std::string curname, std::string subname)
0304 : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
0305 };
0306
0307
0308 class ExtrasError : public ParseError {
0309 CLI11_ERROR_DEF(ParseError, ExtrasError)
0310 explicit ExtrasError(std::vector<std::string> args)
0311 : ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
0312 : "The following argument was not expected: ") +
0313 detail::rjoin(args, " "),
0314 ExitCodes::ExtrasError) {}
0315 ExtrasError(const std::string &name, std::vector<std::string> args)
0316 : ExtrasError(name,
0317 (args.size() > 1 ? "The following arguments were not expected: "
0318 : "The following argument was not expected: ") +
0319 detail::rjoin(args, " "),
0320 ExitCodes::ExtrasError) {}
0321 };
0322
0323
0324 class ConfigError : public ParseError {
0325 CLI11_ERROR_DEF(ParseError, ConfigError)
0326 CLI11_ERROR_SIMPLE(ConfigError)
0327 static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); }
0328 static ConfigError NotConfigurable(std::string item) {
0329 return ConfigError(item + ": This option is not allowed in a configuration file");
0330 }
0331 };
0332
0333
0334 class InvalidError : public ParseError {
0335 CLI11_ERROR_DEF(ParseError, InvalidError)
0336 explicit InvalidError(std::string name)
0337 : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
0338 }
0339 };
0340
0341
0342
0343 class HorribleError : public ParseError {
0344 CLI11_ERROR_DEF(ParseError, HorribleError)
0345 CLI11_ERROR_SIMPLE(HorribleError)
0346 };
0347
0348
0349
0350
0351 class OptionNotFound : public Error {
0352 CLI11_ERROR_DEF(Error, OptionNotFound)
0353 explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
0354 };
0355
0356 #undef CLI11_ERROR_DEF
0357 #undef CLI11_ERROR_SIMPLE
0358
0359
0360
0361
0362 }