File indexing completed on 2026-09-13 09:06:09
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010 #include "../Validators.hpp"
0011
0012 #include "../Encoding.hpp"
0013 #include "../Macros.hpp"
0014 #include "../StringTools.hpp"
0015 #include "../TypeTools.hpp"
0016
0017
0018 #include <map>
0019 #include <string>
0020 #include <utility>
0021
0022
0023 namespace CLI {
0024
0025
0026 CLI11_INLINE std::string Validator::operator()(std::string &str) const {
0027 std::string retstring;
0028 if(active_) {
0029 if(non_modifying_) {
0030 std::string value = str;
0031 retstring = func_(value);
0032 } else {
0033 retstring = func_(str);
0034 }
0035 }
0036 return retstring;
0037 }
0038
0039 CLI11_NODISCARD CLI11_INLINE Validator Validator::description(std::string validator_desc) const {
0040 Validator newval(*this);
0041 newval.desc_function_ = [validator_desc]() { return validator_desc; };
0042 return newval;
0043 }
0044
0045 CLI11_INLINE Validator Validator::operator&(const Validator &other) const {
0046 Validator newval;
0047
0048 newval._merge_description(*this, other, " AND ");
0049
0050
0051 const std::function<std::string(std::string & filename)> &f1 = func_;
0052 const std::function<std::string(std::string & filename)> &f2 = other.func_;
0053
0054 newval.func_ = [f1, f2](std::string &input) {
0055 std::string s1 = f1(input);
0056 std::string s2 = f2(input);
0057 if(!s1.empty() && !s2.empty())
0058 return std::string("(") + s1 + ") AND (" + s2 + ")";
0059 return s1 + s2;
0060 };
0061
0062 newval.active_ = active_ && other.active_;
0063 newval.application_index_ = application_index_;
0064 return newval;
0065 }
0066
0067 CLI11_INLINE Validator Validator::operator|(const Validator &other) const {
0068 Validator newval;
0069
0070 newval._merge_description(*this, other, " OR ");
0071
0072
0073 const std::function<std::string(std::string &)> &f1 = func_;
0074 const std::function<std::string(std::string &)> &f2 = other.func_;
0075
0076 newval.func_ = [f1, f2](std::string &input) {
0077 std::string s1 = f1(input);
0078 std::string s2 = f2(input);
0079 if(s1.empty() || s2.empty())
0080 return std::string();
0081
0082 return std::string("(") + s1 + ") OR (" + s2 + ")";
0083 };
0084 newval.active_ = active_ && other.active_;
0085 newval.application_index_ = application_index_;
0086 return newval;
0087 }
0088
0089 CLI11_INLINE Validator Validator::operator!() const {
0090 Validator newval;
0091 const std::function<std::string()> &dfunc1 = desc_function_;
0092 newval.desc_function_ = [dfunc1]() {
0093 auto str = dfunc1();
0094 return (!str.empty()) ? std::string("NOT ") + str : std::string{};
0095 };
0096
0097 const std::function<std::string(std::string & res)> &f1 = func_;
0098
0099 newval.func_ = [f1, dfunc1](std::string &test) -> std::string {
0100 std::string s1 = f1(test);
0101 if(s1.empty()) {
0102 return std::string("check ") + dfunc1() + " succeeded improperly";
0103 }
0104 return std::string{};
0105 };
0106 newval.active_ = active_;
0107 newval.application_index_ = application_index_;
0108 return newval;
0109 }
0110
0111 CLI11_INLINE void
0112 Validator::_merge_description(const Validator &val1, const Validator &val2, const std::string &merger) {
0113
0114 const std::function<std::string()> &dfunc1 = val1.desc_function_;
0115 const std::function<std::string()> &dfunc2 = val2.desc_function_;
0116
0117 desc_function_ = [=]() {
0118 std::string f1 = dfunc1();
0119 std::string f2 = dfunc2();
0120 if((f1.empty()) || (f2.empty())) {
0121 return f1 + f2;
0122 }
0123 return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')';
0124 };
0125 }
0126
0127 namespace detail {
0128
0129 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
0130 CLI11_INLINE path_type check_path(const char *file) noexcept {
0131 std::error_code ec;
0132 auto stat = std::filesystem::status(to_path(file), ec);
0133 if(ec) {
0134 return path_type::nonexistent;
0135 }
0136 switch(stat.type()) {
0137 case std::filesystem::file_type::none:
0138 case std::filesystem::file_type::not_found:
0139 return path_type::nonexistent;
0140 case std::filesystem::file_type::directory:
0141 return path_type::directory;
0142 case std::filesystem::file_type::symlink:
0143 case std::filesystem::file_type::block:
0144 case std::filesystem::file_type::character:
0145 case std::filesystem::file_type::fifo:
0146 case std::filesystem::file_type::socket:
0147 case std::filesystem::file_type::regular:
0148 case std::filesystem::file_type::unknown:
0149 default:
0150 return path_type::file;
0151 }
0152 }
0153 #else
0154 CLI11_INLINE path_type check_path(const char *file) noexcept {
0155 #if defined(_MSC_VER)
0156 struct __stat64 buffer;
0157 if(_stat64(file, &buffer) == 0) {
0158 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
0159 }
0160 #else
0161 struct stat buffer;
0162 if(stat(file, &buffer) == 0) {
0163 return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file;
0164 }
0165 #endif
0166 return path_type::nonexistent;
0167 }
0168 #endif
0169
0170 CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator("FILE") {
0171 func_ = [](std::string &filename) {
0172 auto path_result = check_path(filename.c_str());
0173 if(path_result == path_type::nonexistent) {
0174 return "File does not exist: " + filename;
0175 }
0176 if(path_result == path_type::directory) {
0177 return "File is actually a directory: " + filename;
0178 }
0179 return std::string();
0180 };
0181 }
0182
0183 CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator("DIR") {
0184 func_ = [](std::string &filename) {
0185 auto path_result = check_path(filename.c_str());
0186 if(path_result == path_type::nonexistent) {
0187 return "Directory does not exist: " + filename;
0188 }
0189 if(path_result == path_type::file) {
0190 return "Directory is actually a file: " + filename;
0191 }
0192 return std::string();
0193 };
0194 }
0195
0196 CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator("PATH(existing)") {
0197 func_ = [](std::string &filename) {
0198 auto path_result = check_path(filename.c_str());
0199 if(path_result == path_type::nonexistent) {
0200 return "Path does not exist: " + filename;
0201 }
0202 return std::string();
0203 };
0204 }
0205
0206 CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator("PATH(non-existing)") {
0207 func_ = [](std::string &filename) {
0208 auto path_result = check_path(filename.c_str());
0209 if(path_result != path_type::nonexistent) {
0210 return "Path already exists: " + filename;
0211 }
0212 return std::string();
0213 };
0214 }
0215
0216 CLI11_INLINE EscapedStringTransformer::EscapedStringTransformer() {
0217 func_ = [](std::string &str) {
0218 try {
0219 if(str.size() > 1 && (str.front() == '\"' || str.front() == '\'' || str.front() == '`') &&
0220 str.front() == str.back()) {
0221 process_quoted_string(str);
0222 } else if(str.find_first_of('\\') != std::string::npos) {
0223 if(detail::is_binary_escaped_string(str)) {
0224 str = detail::extract_binary_string(str);
0225 } else {
0226 str = remove_escaped_characters(str);
0227 }
0228 }
0229 return std::string{};
0230 } catch(const std::invalid_argument &ia) {
0231 return std::string(ia.what());
0232 }
0233 };
0234 }
0235 }
0236
0237 CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path, bool enableErrorReturn)
0238 : Validator("FILE") {
0239 func_ = [default_path, enableErrorReturn](std::string &filename) {
0240 auto path_result = detail::check_path(filename.c_str());
0241 if(path_result == detail::path_type::nonexistent) {
0242 std::string test_file_path = default_path;
0243 if(default_path.back() != '/' && default_path.back() != '\\') {
0244
0245 test_file_path += '/';
0246 }
0247 test_file_path.append(filename);
0248 path_result = detail::check_path(test_file_path.c_str());
0249 if(path_result == detail::path_type::file) {
0250 filename = test_file_path;
0251 } else {
0252 if(enableErrorReturn) {
0253 return "File does not exist: " + filename;
0254 }
0255 }
0256 }
0257 return std::string{};
0258 };
0259 }
0260
0261 namespace detail {
0262
0263 CLI11_INLINE std::pair<std::string, std::string> split_program_name(std::string commandline) {
0264
0265 std::pair<std::string, std::string> vals;
0266 trim(commandline);
0267 auto esp = commandline.find_first_of(' ', 1);
0268 while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) {
0269 esp = commandline.find_first_of(' ', esp + 1);
0270 if(esp == std::string::npos) {
0271
0272
0273 if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') {
0274 bool embeddedQuote = false;
0275 auto keyChar = commandline[0];
0276 auto end = commandline.find_first_of(keyChar, 1);
0277 while((end != std::string::npos) && (commandline[end - 1] == '\\')) {
0278 end = commandline.find_first_of(keyChar, end + 1);
0279 embeddedQuote = true;
0280 }
0281 if(end != std::string::npos) {
0282 vals.first = commandline.substr(1, end - 1);
0283 esp = end + 1;
0284 if(embeddedQuote) {
0285 vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar));
0286 }
0287 } else {
0288 esp = commandline.find_first_of(' ', 1);
0289 }
0290 } else {
0291 esp = commandline.find_first_of(' ', 1);
0292 }
0293
0294 break;
0295 }
0296 }
0297 if(vals.first.empty()) {
0298 vals.first = commandline.substr(0, esp);
0299 rtrim(vals.first);
0300 }
0301
0302
0303 vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{};
0304 ltrim(vals.second);
0305 return vals;
0306 }
0307
0308 }
0309
0310
0311
0312 }