Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:44

0001 // Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner
0002 // under NSF AWARD 1414736 and by the respective contributors.
0003 // All rights reserved.
0004 //
0005 // SPDX-License-Identifier: BSD-3-Clause
0006 
0007 #pragma once
0008 
0009 // [CLI11:public_includes:set]
0010 #include <exception>
0011 #include <stdexcept>
0012 #include <string>
0013 #include <utility>
0014 #include <vector>
0015 // [CLI11:public_includes:end]
0016 
0017 // CLI library includes
0018 #include "Macros.hpp"
0019 #include "StringTools.hpp"
0020 
0021 namespace CLI {
0022 // [CLI11:error_hpp:verbatim]
0023 
0024 // Use one of these on all error classes.
0025 // These are temporary and are undef'd at the end of this file.
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 // This is added after the one above if a class is used directly and builds its own message
0037 #define CLI11_ERROR_SIMPLE(name)                                                                                       \
0038     explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
0039 
0040 /// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut,
0041 /// int values from e.get_error_code().
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 // Error definitions
0063 
0064 /// @defgroup error_group Errors
0065 /// @brief Errors thrown by CLI11
0066 ///
0067 /// These are the errors that can be thrown. Some of them, like CLI::Success, are not really errors.
0068 /// @{
0069 
0070 /// All errors derive from this one
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 // Note: Using Error::Error constructors does not work on GCC 4.7
0087 
0088 /// Construction errors (not in parsing)
0089 class ConstructionError : public Error {
0090     CLI11_ERROR_DEF(Error, ConstructionError)
0091 };
0092 
0093 /// Thrown when an option is set to conflicting values (non-vector and multi args, for example)
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 /// Thrown on construction of a bad name
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 /// Thrown when an option already exists
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 // Parsing errors
0149 
0150 /// Anything that can error in Parse
0151 class ParseError : public Error {
0152     CLI11_ERROR_DEF(Error, ParseError)
0153 };
0154 
0155 // Not really "errors"
0156 
0157 /// This is a successful completion on parsing, supposed to exit
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 /// -h or --help on command line
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 /// Usually something like --help-all on command line
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 /// -v or --version on command line
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 /// Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code.
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 /// Thrown when parsing an INI file and it is missing
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 /// Thrown when conversion call back fails, such as when an int fails to coerce to a string
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 /// Thrown when validation of results fails
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 /// Thrown when a required option is missing
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 /// Thrown when the wrong number of arguments has been received
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 /// Thrown when a requires option is missing
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 /// Thrown when an excludes option is present
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 /// Thrown when too many positionals or options are found
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 /// Thrown when extra values are found in an INI file
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 /// Thrown when validation fails before parsing
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 /// This is just a safety check to verify selection and parsing match - you should not ever see it
0334 /// Strings are directly added to this error, but again, it should never be seen.
0335 class HorribleError : public ParseError {
0336     CLI11_ERROR_DEF(ParseError, HorribleError)
0337     CLI11_ERROR_SIMPLE(HorribleError)
0338 };
0339 
0340 // After parsing
0341 
0342 /// Thrown when counting a non-existent option
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 // [CLI11:error_hpp:end]
0354 }  // namespace CLI