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