Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:52:29

0001 // Copyright (c) 2017-2024, 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 // IWYU pragma: private, include "CLI/CLI.hpp"
0010 
0011 // [CLI11:public_includes:set]
0012 #include <exception>
0013 #include <stdexcept>
0014 #include <string>
0015 #include <utility>
0016 #include <vector>
0017 // [CLI11:public_includes:end]
0018 
0019 // CLI library includes
0020 #include "Macros.hpp"
0021 #include "StringTools.hpp"
0022 
0023 namespace CLI {
0024 // [CLI11:error_hpp:verbatim]
0025 
0026 // Use one of these on all error classes.
0027 // These are temporary and are undef'd at the end of this file.
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 // This is added after the one above if a class is used directly and builds its own message
0039 #define CLI11_ERROR_SIMPLE(name)                                                                                       \
0040     explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
0041 
0042 /// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut,
0043 /// int values from e.get_error_code().
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 // Error definitions
0065 
0066 /// @defgroup error_group Errors
0067 /// @brief Errors thrown by CLI11
0068 ///
0069 /// These are the errors that can be thrown. Some of them, like CLI::Success, are not really errors.
0070 /// @{
0071 
0072 /// All errors derive from this one
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 // Note: Using Error::Error constructors does not work on GCC 4.7
0089 
0090 /// Construction errors (not in parsing)
0091 class ConstructionError : public Error {
0092     CLI11_ERROR_DEF(Error, ConstructionError)
0093 };
0094 
0095 /// Thrown when an option is set to conflicting values (non-vector and multi args, for example)
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 /// Thrown on construction of a bad name
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 /// Thrown when an option already exists
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 // Parsing errors
0157 
0158 /// Anything that can error in Parse
0159 class ParseError : public Error {
0160     CLI11_ERROR_DEF(Error, ParseError)
0161 };
0162 
0163 // Not really "errors"
0164 
0165 /// This is a successful completion on parsing, supposed to exit
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 /// -h or --help on command line
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 /// Usually something like --help-all on command line
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 /// -v or --version on command line
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 /// Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code.
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 /// Thrown when parsing an INI file and it is missing
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 /// Thrown when conversion call back fails, such as when an int fails to coerce to a string
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 /// Thrown when validation of results fails
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 /// Thrown when a required option is missing
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 /// Thrown when the wrong number of arguments has been received
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 /// Thrown when a requires option is missing
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 /// Thrown when an excludes option is present
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 /// Thrown when too many positionals or options are found
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 /// Thrown when extra values are found in an INI file
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 /// Thrown when validation fails before parsing
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 /// This is just a safety check to verify selection and parsing match - you should not ever see it
0342 /// Strings are directly added to this error, but again, it should never be seen.
0343 class HorribleError : public ParseError {
0344     CLI11_ERROR_DEF(ParseError, HorribleError)
0345     CLI11_ERROR_SIMPLE(HorribleError)
0346 };
0347 
0348 // After parsing
0349 
0350 /// Thrown when counting a non-existent option
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 // [CLI11:error_hpp:end]
0362 }  // namespace CLI