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