Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-11 09:07:22

0001 // Copyright (c) 2017-2025, 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 #include "Error.hpp"
0012 #include "Macros.hpp"
0013 #include "StringTools.hpp"
0014 #include "TypeTools.hpp"
0015 
0016 // [CLI11:public_includes:set]
0017 #include <cmath>
0018 #include <cstdint>
0019 #include <functional>
0020 #include <iostream>
0021 #include <limits>
0022 #include <memory>
0023 #include <string>
0024 #include <utility>
0025 #include <vector>
0026 // [CLI11:public_includes:end]
0027 
0028 // [CLI11:validators_hpp_filesystem:verbatim]
0029 
0030 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
0031 #include <filesystem>  // NOLINT(build/include)
0032 #else
0033 #include <sys/stat.h>
0034 #include <sys/types.h>
0035 #endif
0036 
0037 // [CLI11:validators_hpp_filesystem:end]
0038 
0039 namespace CLI {
0040 // [CLI11:validators_hpp:verbatim]
0041 
0042 class Option;
0043 
0044 /// @defgroup validator_group Validators
0045 
0046 /// @brief Some validators that are provided
0047 ///
0048 /// These are simple `std::string(const std::string&)` validators that are useful. They return
0049 /// a string if the validation fails. A custom struct is provided, as well, with the same user
0050 /// semantics, but with the ability to provide a new type name.
0051 /// @{
0052 
0053 ///
0054 class Validator {
0055   protected:
0056     /// This is the description function, if empty the description_ will be used
0057     std::function<std::string()> desc_function_{[]() { return std::string{}; }};
0058 
0059     /// This is the base function that is to be called.
0060     /// Returns a string error message if validation fails.
0061     std::function<std::string(std::string &)> func_{[](std::string &) { return std::string{}; }};
0062     /// The name for search purposes of the Validator
0063     std::string name_{};
0064     /// A Validator will only apply to an indexed value (-1 is all elements)
0065     int application_index_ = -1;
0066     /// Enable for Validator to allow it to be disabled if need be
0067     bool active_{true};
0068     /// specify that a validator should not modify the input
0069     bool non_modifying_{false};
0070 
0071     Validator(std::string validator_desc, std::function<std::string(std::string &)> func)
0072         : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {}
0073 
0074   public:
0075     Validator() = default;
0076     /// Construct a Validator with just the description string
0077     explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {}
0078     /// Construct Validator from basic information
0079     Validator(std::function<std::string(std::string &)> op, std::string validator_desc, std::string validator_name = "")
0080         : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)),
0081           name_(std::move(validator_name)) {}
0082     /// Set the Validator operation function
0083     Validator &operation(std::function<std::string(std::string &)> op) {
0084         func_ = std::move(op);
0085         return *this;
0086     }
0087     /// This is the required operator for a Validator - provided to help
0088     /// users (CLI11 uses the member `func` directly)
0089     std::string operator()(std::string &str) const;
0090 
0091     /// This is the required operator for a Validator - provided to help
0092     /// users (CLI11 uses the member `func` directly)
0093     std::string operator()(const std::string &str) const {
0094         std::string value = str;
0095         return (active_) ? func_(value) : std::string{};
0096     }
0097 
0098     /// Specify the type string
0099     Validator &description(std::string validator_desc) {
0100         desc_function_ = [validator_desc]() { return validator_desc; };
0101         return *this;
0102     }
0103     /// Specify the type string
0104     CLI11_NODISCARD Validator description(std::string validator_desc) const;
0105 
0106     /// Generate type description information for the Validator
0107     CLI11_NODISCARD std::string get_description() const {
0108         if(active_) {
0109             return desc_function_();
0110         }
0111         return std::string{};
0112     }
0113     /// Specify the type string
0114     Validator &name(std::string validator_name) {
0115         name_ = std::move(validator_name);
0116         return *this;
0117     }
0118     /// Specify the type string
0119     CLI11_NODISCARD Validator name(std::string validator_name) const {
0120         Validator newval(*this);
0121         newval.name_ = std::move(validator_name);
0122         return newval;
0123     }
0124     /// Get the name of the Validator
0125     CLI11_NODISCARD const std::string &get_name() const { return name_; }
0126     /// Specify whether the Validator is active or not
0127     Validator &active(bool active_val = true) {
0128         active_ = active_val;
0129         return *this;
0130     }
0131     /// Specify whether the Validator is active or not
0132     CLI11_NODISCARD Validator active(bool active_val = true) const {
0133         Validator newval(*this);
0134         newval.active_ = active_val;
0135         return newval;
0136     }
0137 
0138     /// Specify whether the Validator can be modifying or not
0139     Validator &non_modifying(bool no_modify = true) {
0140         non_modifying_ = no_modify;
0141         return *this;
0142     }
0143     /// Specify the application index of a validator
0144     Validator &application_index(int app_index) {
0145         application_index_ = app_index;
0146         return *this;
0147     }
0148     /// Specify the application index of a validator
0149     CLI11_NODISCARD Validator application_index(int app_index) const {
0150         Validator newval(*this);
0151         newval.application_index_ = app_index;
0152         return newval;
0153     }
0154     /// Get the current value of the application index
0155     CLI11_NODISCARD int get_application_index() const { return application_index_; }
0156     /// Get a boolean if the validator is active
0157     CLI11_NODISCARD bool get_active() const { return active_; }
0158 
0159     /// Get a boolean if the validator is allowed to modify the input returns true if it can modify the input
0160     CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; }
0161 
0162     /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the
0163     /// same.
0164     Validator operator&(const Validator &other) const;
0165 
0166     /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the
0167     /// same.
0168     Validator operator|(const Validator &other) const;
0169 
0170     /// Create a validator that fails when a given validator succeeds
0171     Validator operator!() const;
0172 
0173   private:
0174     void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger);
0175 };
0176 
0177 /// Alias for Validator for custom Validator for clarity
0178 using CustomValidator = Validator;
0179 
0180 // The implementation of the built in validators is using the Validator class;
0181 // the user is only expected to use the const (static) versions (since there's no setup).
0182 // Therefore, this is in detail.
0183 namespace detail {
0184 
0185 /// CLI enumeration of different file types
0186 enum class path_type : std::uint8_t { nonexistent, file, directory };
0187 
0188 /// get the type of the path from a file name
0189 CLI11_INLINE path_type check_path(const char *file) noexcept;
0190 
0191 // Static is not needed here, because global const implies static.
0192 
0193 /// Check for an existing file (returns error message if check fails)
0194 class ExistingFileValidator : public Validator {
0195   public:
0196     ExistingFileValidator();
0197 };
0198 
0199 /// Check for an existing directory (returns error message if check fails)
0200 class ExistingDirectoryValidator : public Validator {
0201   public:
0202     ExistingDirectoryValidator();
0203 };
0204 
0205 /// Check for an existing path
0206 class ExistingPathValidator : public Validator {
0207   public:
0208     ExistingPathValidator();
0209 };
0210 
0211 /// Check for an non-existing path
0212 class NonexistentPathValidator : public Validator {
0213   public:
0214     NonexistentPathValidator();
0215 };
0216 
0217 class EscapedStringTransformer : public Validator {
0218   public:
0219     EscapedStringTransformer();
0220 };
0221 
0222 }  // namespace detail
0223 
0224 /// Check for existing file (returns error message if check fails)
0225 const detail::ExistingFileValidator ExistingFile;
0226 
0227 /// Check for an existing directory (returns error message if check fails)
0228 const detail::ExistingDirectoryValidator ExistingDirectory;
0229 
0230 /// Check for an existing path
0231 const detail::ExistingPathValidator ExistingPath;
0232 
0233 /// Check for an non-existing path
0234 const detail::NonexistentPathValidator NonexistentPath;
0235 
0236 /// convert escaped characters into their associated values
0237 const detail::EscapedStringTransformer EscapedString;
0238 
0239 /// Modify a path if the file is a particular default location, can be used as Check or transform
0240 /// with the error return optionally disabled
0241 class FileOnDefaultPath : public Validator {
0242   public:
0243     explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true);
0244 };
0245 
0246 /// Produce a range (factory). Min and max are inclusive.
0247 class Range : public Validator {
0248   public:
0249     /// This produces a range with min and max inclusive.
0250     ///
0251     /// Note that the constructor is templated, but the struct is not, so C++17 is not
0252     /// needed to provide nice syntax for Range(a,b).
0253     template <typename T>
0254     Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) {
0255         if(validator_name.empty()) {
0256             std::stringstream out;
0257             out << detail::type_name<T>() << " in [" << min_val << " - " << max_val << "]";
0258             description(out.str());
0259         }
0260 
0261         func_ = [min_val, max_val](std::string &input) {
0262             using CLI::detail::lexical_cast;
0263             T val;
0264             bool converted = lexical_cast(input, val);
0265             if((!converted) || (val < min_val || val > max_val)) {
0266                 std::stringstream out;
0267                 out << "Value " << input << " not in range [";
0268                 out << min_val << " - " << max_val << "]";
0269                 return out.str();
0270             }
0271             return std::string{};
0272         };
0273     }
0274 
0275     /// Range of one value is 0 to value
0276     template <typename T>
0277     explicit Range(T max_val, const std::string &validator_name = std::string{})
0278         : Range(static_cast<T>(0), max_val, validator_name) {}
0279 };
0280 
0281 /// Check for a non negative number
0282 const Range NonNegativeNumber((std::numeric_limits<double>::max)(), "NONNEGATIVE");
0283 
0284 /// Check for a positive valued number (val>0.0), <double>::min  here is the smallest positive number
0285 const Range PositiveNumber((std::numeric_limits<double>::min)(), (std::numeric_limits<double>::max)(), "POSITIVE");
0286 
0287 namespace detail {
0288 // the following suggestion was made by Nikita Ofitserov(@himikof)
0289 // done in templates to prevent compiler warnings on negation of unsigned numbers
0290 
0291 /// Do a check for overflow on signed numbers
0292 template <typename T>
0293 inline typename std::enable_if<std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
0294     if((a > 0) == (b > 0)) {
0295         return ((std::numeric_limits<T>::max)() / (std::abs)(a) < (std::abs)(b));
0296     }
0297     return ((std::numeric_limits<T>::min)() / (std::abs)(a) > -(std::abs)(b));
0298 }
0299 /// Do a check for overflow on unsigned numbers
0300 template <typename T>
0301 inline typename std::enable_if<!std::is_signed<T>::value, T>::type overflowCheck(const T &a, const T &b) {
0302     return ((std::numeric_limits<T>::max)() / a < b);
0303 }
0304 
0305 /// Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.
0306 template <typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type checked_multiply(T &a, T b) {
0307     if(a == 0 || b == 0 || a == 1 || b == 1) {
0308         a *= b;
0309         return true;
0310     }
0311     if(a == (std::numeric_limits<T>::min)() || b == (std::numeric_limits<T>::min)()) {
0312         return false;
0313     }
0314     if(overflowCheck(a, b)) {
0315         return false;
0316     }
0317     a *= b;
0318     return true;
0319 }
0320 
0321 /// Performs a *= b; if it doesn't equal infinity. Returns false otherwise.
0322 template <typename T>
0323 typename std::enable_if<std::is_floating_point<T>::value, bool>::type checked_multiply(T &a, T b) {
0324     T c = a * b;
0325     if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) {
0326         return false;
0327     }
0328     a = c;
0329     return true;
0330 }
0331 /// Split a string into a program name and command line arguments
0332 /// the string is assumed to contain a file name followed by other arguments
0333 /// the return value contains is a pair with the first argument containing the program name and the second
0334 /// everything else.
0335 CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline);
0336 
0337 }  // namespace detail
0338 /// @}
0339 
0340 // [CLI11:validators_hpp:end]
0341 }  // namespace CLI
0342 
0343 #ifndef CLI11_COMPILE
0344 #include "impl/Validators_inl.hpp"  // IWYU pragma: export
0345 #endif