Loading...
Searching...
No Matches
Error.hpp
Go to the documentation of this file.
// Copyright (c) 2017-2025, University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
// IWYU pragma: private, include "CLI/CLI.hpp"
// [CLI11:public_includes:set]
#include <exception>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
// [CLI11:public_includes:end]
// CLI library includes
#include "Macros.hpp"
#include "StringTools.hpp"
namespace CLI {
// [CLI11:error_hpp:verbatim]
// Use one of these on all error classes.
// These are temporary and are undef'd at the end of this file.
#define CLI11_ERROR_DEF(parent, name) \
protected: \
name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \
name(std::string ename, std::string msg, ExitCodes exit_code) \
: parent(std::move(ename), std::move(msg), exit_code) {} \
\
public: \
name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \
name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {}
// This is added after the one above if a class is used directly and builds its own message
#define CLI11_ERROR_SIMPLE(name) \
explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {}
enum class ExitCodes : int {
Success = 0,
IncorrectConstruction = 100,
BadNameString,
OptionAlreadyAdded,
FileError,
ConversionError,
ValidationError,
RequiredError,
RequiresError,
ExcludesError,
ExtrasError,
ConfigError,
InvalidError,
HorribleError,
OptionNotFound,
ArgumentMismatch,
BaseClass = 127
};
// Error definitions
class Error : public std::runtime_error {
int actual_exit_code;
std::string error_name{"Error"};
public:
CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; }
CLI11_NODISCARD std::string get_name() const { return error_name; }
Error(std::string name, std::string msg, int exit_code = static_cast<int>(ExitCodes::BaseClass))
: runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {}
Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast<int>(exit_code)) {}
};
// Note: Using Error::Error constructors does not work on GCC 4.7
class ConstructionError : public Error {
CLI11_ERROR_DEF(Error, ConstructionError)
};
class IncorrectConstruction : public ConstructionError {
CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction)
CLI11_ERROR_SIMPLE(IncorrectConstruction)
static IncorrectConstruction PositionalFlag(std::string name) {
return IncorrectConstruction(name + ": Flags cannot be positional");
}
static IncorrectConstruction Set0Opt(std::string name) {
return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
}
static IncorrectConstruction SetFlag(std::string name) {
return IncorrectConstruction(name + ": Cannot set an expected number for flags");
}
static IncorrectConstruction ChangeNotVector(std::string name) {
return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
}
static IncorrectConstruction AfterMultiOpt(std::string name) {
return IncorrectConstruction(
name + ": You can't change expected arguments after you've changed the multi option policy!");
}
static IncorrectConstruction MissingOption(std::string name) {
return IncorrectConstruction("Option " + name + " is not defined");
}
static IncorrectConstruction MultiOptionPolicy(std::string name) {
return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
}
};
class BadNameString : public ConstructionError {
CLI11_ERROR_DEF(ConstructionError, BadNameString)
CLI11_ERROR_SIMPLE(BadNameString)
static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); }
static BadNameString MissingDash(std::string name) {
return BadNameString("Long names strings require 2 dashes " + name);
}
static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); }
static BadNameString BadPositionalName(std::string name) {
return BadNameString("Invalid positional Name: " + name);
}
static BadNameString ReservedName(std::string name) {
return BadNameString("Names '-','--','++' are reserved and not allowed as option names " + name);
}
static BadNameString MultiPositionalNames(std::string name) {
return BadNameString("Only one positional name allowed, remove: " + name);
}
};
class OptionAlreadyAdded : public ConstructionError {
CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded)
explicit OptionAlreadyAdded(std::string name)
: OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {}
static OptionAlreadyAdded Requires(std::string name, std::string other) {
return {name + " requires " + other, ExitCodes::OptionAlreadyAdded};
}
static OptionAlreadyAdded Excludes(std::string name, std::string other) {
return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded};
}
};
// Parsing errors
class ParseError : public Error {
CLI11_ERROR_DEF(Error, ParseError)
};
// Not really "errors"
class Success : public ParseError {
CLI11_ERROR_DEF(ParseError, Success)
Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {}
};
class CallForHelp : public Success {
CLI11_ERROR_DEF(Success, CallForHelp)
CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
};
class CallForAllHelp : public Success {
CLI11_ERROR_DEF(Success, CallForAllHelp)
CallForAllHelp()
: CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {}
};
class CallForVersion : public Success {
CLI11_ERROR_DEF(Success, CallForVersion)
CallForVersion()
: CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {}
};
class RuntimeError : public ParseError {
CLI11_ERROR_DEF(ParseError, RuntimeError)
explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {}
};
class FileError : public ParseError {
CLI11_ERROR_DEF(ParseError, FileError)
CLI11_ERROR_SIMPLE(FileError)
static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); }
};
class ConversionError : public ParseError {
CLI11_ERROR_DEF(ParseError, ConversionError)
CLI11_ERROR_SIMPLE(ConversionError)
ConversionError(std::string member, std::string name)
: ConversionError("The value " + member + " is not an allowed value for " + name) {}
ConversionError(std::string name, std::vector<std::string> results)
: ConversionError("Could not convert: " + name + " = " + detail::join(results)) {}
static ConversionError TooManyInputsFlag(std::string name) {
return ConversionError(name + ": too many inputs for a flag");
}
static ConversionError TrueFalse(std::string name) {
return ConversionError(name + ": Should be true/false or a number");
}
};
class ValidationError : public ParseError {
CLI11_ERROR_DEF(ParseError, ValidationError)
CLI11_ERROR_SIMPLE(ValidationError)
explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {}
};
class RequiredError : public ParseError {
CLI11_ERROR_DEF(ParseError, RequiredError)
explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {}
static RequiredError Subcommand(std::size_t min_subcom) {
if(min_subcom == 1) {
return RequiredError("A subcommand");
}
return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError};
}
static RequiredError
Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) {
if((min_option == 1) && (max_option == 1) && (used == 0))
return RequiredError("Exactly 1 option from [" + option_list + "]");
if((min_option == 1) && (max_option == 1) && (used > 1)) {
return {"Exactly 1 option from [" + option_list + "] is required but " + std::to_string(used) +
" were given",
ExitCodes::RequiredError};
}
if((min_option == 1) && (used == 0))
return RequiredError("At least 1 option from [" + option_list + "]");
if(used < min_option) {
return {"Requires at least " + std::to_string(min_option) + " options used but only " +
std::to_string(used) + " were given from [" + option_list + "]",
ExitCodes::RequiredError};
}
if(max_option == 1)
return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError};
return {"Requires at most " + std::to_string(max_option) + " options be used but " + std::to_string(used) +
" were given from [" + option_list + "]",
ExitCodes::RequiredError};
}
};
class ArgumentMismatch : public ParseError {
CLI11_ERROR_DEF(ParseError, ArgumentMismatch)
CLI11_ERROR_SIMPLE(ArgumentMismatch)
ArgumentMismatch(std::string name, int expected, std::size_t received)
: ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name +
", got " + std::to_string(received))
: ("Expected at least " + std::to_string(-expected) + " arguments to " + name +
", got " + std::to_string(received)),
ExitCodes::ArgumentMismatch) {}
static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) {
return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " +
std::to_string(received));
}
static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) {
return ArgumentMismatch(name + ": At most " + std::to_string(num) + " required but received " +
std::to_string(received));
}
static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) {
return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing");
}
static ArgumentMismatch FlagOverride(std::string name) {
return ArgumentMismatch(name + " was given a disallowed flag override");
}
static ArgumentMismatch PartialType(std::string name, int num, std::string type) {
return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) +
" required for each element");
}
};
class RequiresError : public ParseError {
CLI11_ERROR_DEF(ParseError, RequiresError)
RequiresError(std::string curname, std::string subname)
: RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {}
};
class ExcludesError : public ParseError {
CLI11_ERROR_DEF(ParseError, ExcludesError)
ExcludesError(std::string curname, std::string subname)
: ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {}
};
class ExtrasError : public ParseError {
CLI11_ERROR_DEF(ParseError, ExtrasError)
explicit ExtrasError(std::vector<std::string> args)
: ExtrasError((args.size() > 1 ? "The following arguments were not expected: "
: "The following argument was not expected: ") +
detail::join(args, " "),
ExitCodes::ExtrasError) {}
ExtrasError(const std::string &name, std::vector<std::string> args)
: ExtrasError(name,
(args.size() > 1 ? "The following arguments were not expected: "
: "The following argument was not expected: ") +
detail::join(args, " "),
ExitCodes::ExtrasError) {}
};
class ConfigError : public ParseError {
CLI11_ERROR_DEF(ParseError, ConfigError)
CLI11_ERROR_SIMPLE(ConfigError)
static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); }
static ConfigError NotConfigurable(std::string item) {
return ConfigError(item + ": This option is not allowed in a configuration file");
}
};
class InvalidError : public ParseError {
CLI11_ERROR_DEF(ParseError, InvalidError)
explicit InvalidError(std::string name)
: InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) {
}
};
class HorribleError : public ParseError {
CLI11_ERROR_DEF(ParseError, HorribleError)
CLI11_ERROR_SIMPLE(HorribleError)
};
// After parsing
class OptionNotFound : public Error {
CLI11_ERROR_DEF(Error, OptionNotFound)
explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {}
};
#undef CLI11_ERROR_DEF
#undef CLI11_ERROR_SIMPLE
// [CLI11:error_hpp:end]
} // namespace CLI
CLI11_ERROR_SIMPLE
#define CLI11_ERROR_SIMPLE(name)
Definition Error.hpp:39
CLI11_ERROR_DEF
#define CLI11_ERROR_DEF(parent, name)
Definition Error.hpp:28
Macros.hpp
CLI11_NODISCARD
#define CLI11_NODISCARD
Definition Macros.hpp:58
StringTools.hpp
CLI::ArgumentMismatch
Thrown when the wrong number of arguments has been received.
Definition Error.hpp:263
CLI::BadNameString
Thrown on construction of a bad name.
Definition Error.hpp:124
CLI::ConfigError
Thrown when extra values are found in an INI file.
Definition Error.hpp:324
CLI::ConstructionError
Construction errors (not in parsing).
Definition Error.hpp:91
CLI::ConversionError
Thrown when conversion call back fails, such as when an int fails to coerce to a string.
Definition Error.hpp:205
CLI::Error::get_exit_code
CLI11_NODISCARD int get_exit_code() const
Definition Error.hpp:78
CLI::Error::Error
Error(std::string name, std::string msg, ExitCodes exit_code)
Definition Error.hpp:85
CLI::Error::get_name
CLI11_NODISCARD std::string get_name() const
Definition Error.hpp:80
CLI::Error::Error
Error(std::string name, std::string msg, int exit_code=static_cast< int >(ExitCodes::BaseClass))
Definition Error.hpp:82
CLI::ExcludesError
Thrown when an excludes option is present.
Definition Error.hpp:301
CLI::ExtrasError
Thrown when too many positionals or options are found.
Definition Error.hpp:308
CLI::FileError
Thrown when parsing an INI file and it is missing.
Definition Error.hpp:198
CLI::HorribleError
Definition Error.hpp:343
CLI::IncorrectConstruction
Thrown when an option is set to conflicting values (non-vector and multi args, for example).
Definition Error.hpp:96
CLI::InvalidError
Thrown when validation fails before parsing.
Definition Error.hpp:334
CLI::OptionAlreadyAdded
Thrown when an option already exists.
Definition Error.hpp:144
CLI::OptionNotFound
Thrown when counting a nonexistent option.
Definition Error.hpp:351
CLI::ParseError
Anything that can error in Parse.
Definition Error.hpp:159
CLI::RequiredError
Thrown when a required option is missing.
Definition Error.hpp:228
CLI::RequiresError
Thrown when a requires option is missing.
Definition Error.hpp:294
CLI::Success
This is a successful completion on parsing, supposed to exit.
Definition Error.hpp:166
CLI::ValidationError
Thrown when validation of results fails.
Definition Error.hpp:221
CLI::detail::join
std::string join(const T &v, std::string delim=",")
Simple function to join a string.
Definition StringTools.hpp:54
CLI
Definition App.hpp:36
CLI::ExitCodes
ExitCodes
Definition Error.hpp:44
CLI::ExitCodes::FileError
@ FileError
Definition Error.hpp:49
CLI::ExitCodes::ConfigError
@ ConfigError
Definition Error.hpp:56
CLI::ExitCodes::ExtrasError
@ ExtrasError
Definition Error.hpp:55
CLI::ExitCodes::ExcludesError
@ ExcludesError
Definition Error.hpp:54
CLI::ExitCodes::ArgumentMismatch
@ ArgumentMismatch
Definition Error.hpp:60
CLI::ExitCodes::BaseClass
@ BaseClass
Definition Error.hpp:61
CLI::ExitCodes::Success
@ Success
Definition Error.hpp:45
CLI::ExitCodes::RequiresError
@ RequiresError
Definition Error.hpp:53
CLI::ExitCodes::IncorrectConstruction
@ IncorrectConstruction
Definition Error.hpp:46
CLI::ExitCodes::RequiredError
@ RequiredError
Definition Error.hpp:52
CLI::ExitCodes::OptionNotFound
@ OptionNotFound
Definition Error.hpp:59
CLI::ExitCodes::BadNameString
@ BadNameString
Definition Error.hpp:47
CLI::ExitCodes::OptionAlreadyAdded
@ OptionAlreadyAdded
Definition Error.hpp:48
CLI::ExitCodes::InvalidError
@ InvalidError
Definition Error.hpp:57
CLI::MultiOptionPolicy
MultiOptionPolicy
Enumeration of the multiOption Policy selection.
Definition Option.hpp:43