Commit 4048596250fa8eddbc96b8c49de5a4a8664c67f1
Committed by
Henry Schreiner
1 parent
d1f0f483
[precompile] Split StringTools.hpp
Showing
4 changed files
with
297 additions
and
222 deletions
CLI11.hpp.in
include/CLI/StringTools.hpp
| ... | ... | @@ -17,6 +17,8 @@ |
| 17 | 17 | #include <vector> |
| 18 | 18 | // [CLI11:public_includes:end] |
| 19 | 19 | |
| 20 | +#include "Macros.hpp" | |
| 21 | + | |
| 20 | 22 | namespace CLI { |
| 21 | 23 | |
| 22 | 24 | // [CLI11:string_tools_hpp:verbatim] |
| ... | ... | @@ -43,21 +45,7 @@ namespace detail { |
| 43 | 45 | constexpr int expected_max_vector_size{1 << 29}; |
| 44 | 46 | // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c |
| 45 | 47 | /// Split a string by a delim |
| 46 | -inline std::vector<std::string> split(const std::string &s, char delim) { | |
| 47 | - std::vector<std::string> elems; | |
| 48 | - // Check to see if empty string, give consistent result | |
| 49 | - if(s.empty()) { | |
| 50 | - elems.emplace_back(); | |
| 51 | - } else { | |
| 52 | - std::stringstream ss; | |
| 53 | - ss.str(s); | |
| 54 | - std::string item; | |
| 55 | - while(std::getline(ss, item, delim)) { | |
| 56 | - elems.push_back(item); | |
| 57 | - } | |
| 58 | - } | |
| 59 | - return elems; | |
| 60 | -} | |
| 48 | +CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim); | |
| 61 | 49 | |
| 62 | 50 | /// Simple function to join a string |
| 63 | 51 | template <typename T> std::string join(const T &v, std::string delim = ",") { |
| ... | ... | @@ -106,33 +94,16 @@ template <typename T> std::string rjoin(const T &v, std::string delim = ",") { |
| 106 | 94 | // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string |
| 107 | 95 | |
| 108 | 96 | /// Trim whitespace from left of string |
| 109 | -inline std::string <rim(std::string &str) { | |
| 110 | - auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); }); | |
| 111 | - str.erase(str.begin(), it); | |
| 112 | - return str; | |
| 113 | -} | |
| 97 | +CLI11_INLINE std::string <rim(std::string &str); | |
| 114 | 98 | |
| 115 | 99 | /// Trim anything from left of string |
| 116 | -inline std::string <rim(std::string &str, const std::string &filter) { | |
| 117 | - auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); | |
| 118 | - str.erase(str.begin(), it); | |
| 119 | - return str; | |
| 120 | -} | |
| 100 | +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter); | |
| 121 | 101 | |
| 122 | 102 | /// Trim whitespace from right of string |
| 123 | -inline std::string &rtrim(std::string &str) { | |
| 124 | - auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); }); | |
| 125 | - str.erase(it.base(), str.end()); | |
| 126 | - return str; | |
| 127 | -} | |
| 103 | +CLI11_INLINE std::string &rtrim(std::string &str); | |
| 128 | 104 | |
| 129 | 105 | /// Trim anything from right of string |
| 130 | -inline std::string &rtrim(std::string &str, const std::string &filter) { | |
| 131 | - auto it = | |
| 132 | - std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); | |
| 133 | - str.erase(it.base(), str.end()); | |
| 134 | - return str; | |
| 135 | -} | |
| 106 | +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter); | |
| 136 | 107 | |
| 137 | 108 | /// Trim whitespace from string |
| 138 | 109 | inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); } |
| ... | ... | @@ -147,31 +118,13 @@ inline std::string trim_copy(const std::string &str) { |
| 147 | 118 | } |
| 148 | 119 | |
| 149 | 120 | /// remove quotes at the front and back of a string either '"' or '\'' |
| 150 | -inline std::string &remove_quotes(std::string &str) { | |
| 151 | - if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) { | |
| 152 | - if(str.front() == str.back()) { | |
| 153 | - str.pop_back(); | |
| 154 | - str.erase(str.begin(), str.begin() + 1); | |
| 155 | - } | |
| 156 | - } | |
| 157 | - return str; | |
| 158 | -} | |
| 121 | +CLI11_INLINE std::string &remove_quotes(std::string &str); | |
| 159 | 122 | |
| 160 | 123 | /// Add a leader to the beginning of all new lines (nothing is added |
| 161 | 124 | /// at the start of the first line). `"; "` would be for ini files |
| 162 | 125 | /// |
| 163 | 126 | /// Can't use Regex, or this would be a subs. |
| 164 | -inline std::string fix_newlines(const std::string &leader, std::string input) { | |
| 165 | - std::string::size_type n = 0; | |
| 166 | - while(n != std::string::npos && n < input.size()) { | |
| 167 | - n = input.find('\n', n); | |
| 168 | - if(n != std::string::npos) { | |
| 169 | - input = input.substr(0, n + 1) + leader + input.substr(n + 1); | |
| 170 | - n += leader.size(); | |
| 171 | - } | |
| 172 | - } | |
| 173 | - return input; | |
| 174 | -} | |
| 127 | +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input); | |
| 175 | 128 | |
| 176 | 129 | /// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) |
| 177 | 130 | inline std::string trim_copy(const std::string &str, const std::string &filter) { |
| ... | ... | @@ -179,40 +132,11 @@ inline std::string trim_copy(const std::string &str, const std::string &filter) |
| 179 | 132 | return trim(s, filter); |
| 180 | 133 | } |
| 181 | 134 | /// Print a two part "help" string |
| 182 | -inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { | |
| 183 | - name = " " + name; | |
| 184 | - out << std::setw(static_cast<int>(wid)) << std::left << name; | |
| 185 | - if(!description.empty()) { | |
| 186 | - if(name.length() >= wid) | |
| 187 | - out << "\n" << std::setw(static_cast<int>(wid)) << ""; | |
| 188 | - for(const char c : description) { | |
| 189 | - out.put(c); | |
| 190 | - if(c == '\n') { | |
| 191 | - out << std::setw(static_cast<int>(wid)) << ""; | |
| 192 | - } | |
| 193 | - } | |
| 194 | - } | |
| 195 | - out << "\n"; | |
| 196 | - return out; | |
| 197 | -} | |
| 135 | +CLI11_INLINE std::ostream & | |
| 136 | +format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid); | |
| 198 | 137 | |
| 199 | 138 | /// Print subcommand aliases |
| 200 | -inline std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) { | |
| 201 | - if(!aliases.empty()) { | |
| 202 | - out << std::setw(static_cast<int>(wid)) << " aliases: "; | |
| 203 | - bool front = true; | |
| 204 | - for(const auto &alias : aliases) { | |
| 205 | - if(!front) { | |
| 206 | - out << ", "; | |
| 207 | - } else { | |
| 208 | - front = false; | |
| 209 | - } | |
| 210 | - out << detail::fix_newlines(" ", alias); | |
| 211 | - } | |
| 212 | - out << "\n"; | |
| 213 | - } | |
| 214 | - return out; | |
| 215 | -} | |
| 139 | +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid); | |
| 216 | 140 | |
| 217 | 141 | /// Verify the first character of an option |
| 218 | 142 | /// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with |
| ... | ... | @@ -227,16 +151,7 @@ template <typename T> bool valid_later_char(T c) { |
| 227 | 151 | } |
| 228 | 152 | |
| 229 | 153 | /// Verify an option/subcommand name |
| 230 | -inline bool valid_name_string(const std::string &str) { | |
| 231 | - if(str.empty() || !valid_first_char(str[0])) { | |
| 232 | - return false; | |
| 233 | - } | |
| 234 | - auto e = str.end(); | |
| 235 | - for(auto c = str.begin() + 1; c != e; ++c) | |
| 236 | - if(!valid_later_char(*c)) | |
| 237 | - return false; | |
| 238 | - return true; | |
| 239 | -} | |
| 154 | +CLI11_INLINE bool valid_name_string(const std::string &str); | |
| 240 | 155 | |
| 241 | 156 | /// Verify an app name |
| 242 | 157 | inline bool valid_alias_name_string(const std::string &str) { |
| ... | ... | @@ -270,66 +185,20 @@ inline std::string remove_underscore(std::string str) { |
| 270 | 185 | } |
| 271 | 186 | |
| 272 | 187 | /// Find and replace a substring with another substring |
| 273 | -inline std::string find_and_replace(std::string str, std::string from, std::string to) { | |
| 274 | - | |
| 275 | - std::size_t start_pos = 0; | |
| 276 | - | |
| 277 | - while((start_pos = str.find(from, start_pos)) != std::string::npos) { | |
| 278 | - str.replace(start_pos, from.length(), to); | |
| 279 | - start_pos += to.length(); | |
| 280 | - } | |
| 281 | - | |
| 282 | - return str; | |
| 283 | -} | |
| 188 | +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to); | |
| 284 | 189 | |
| 285 | 190 | /// check if the flag definitions has possible false flags |
| 286 | 191 | inline bool has_default_flag_values(const std::string &flags) { |
| 287 | 192 | return (flags.find_first_of("{!") != std::string::npos); |
| 288 | 193 | } |
| 289 | 194 | |
| 290 | -inline void remove_default_flag_values(std::string &flags) { | |
| 291 | - auto loc = flags.find_first_of('{', 2); | |
| 292 | - while(loc != std::string::npos) { | |
| 293 | - auto finish = flags.find_first_of("},", loc + 1); | |
| 294 | - if((finish != std::string::npos) && (flags[finish] == '}')) { | |
| 295 | - flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc), | |
| 296 | - flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1); | |
| 297 | - } | |
| 298 | - loc = flags.find_first_of('{', loc + 1); | |
| 299 | - } | |
| 300 | - flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end()); | |
| 301 | -} | |
| 195 | +CLI11_INLINE void remove_default_flag_values(std::string &flags); | |
| 302 | 196 | |
| 303 | 197 | /// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores |
| 304 | -inline std::ptrdiff_t find_member(std::string name, | |
| 305 | - const std::vector<std::string> names, | |
| 306 | - bool ignore_case = false, | |
| 307 | - bool ignore_underscore = false) { | |
| 308 | - auto it = std::end(names); | |
| 309 | - if(ignore_case) { | |
| 310 | - if(ignore_underscore) { | |
| 311 | - name = detail::to_lower(detail::remove_underscore(name)); | |
| 312 | - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 313 | - return detail::to_lower(detail::remove_underscore(local_name)) == name; | |
| 314 | - }); | |
| 315 | - } else { | |
| 316 | - name = detail::to_lower(name); | |
| 317 | - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 318 | - return detail::to_lower(local_name) == name; | |
| 319 | - }); | |
| 320 | - } | |
| 321 | - | |
| 322 | - } else if(ignore_underscore) { | |
| 323 | - name = detail::remove_underscore(name); | |
| 324 | - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 325 | - return detail::remove_underscore(local_name) == name; | |
| 326 | - }); | |
| 327 | - } else { | |
| 328 | - it = std::find(std::begin(names), std::end(names), name); | |
| 329 | - } | |
| 330 | - | |
| 331 | - return (it != std::end(names)) ? (it - std::begin(names)) : (-1); | |
| 332 | -} | |
| 198 | +CLI11_INLINE std::ptrdiff_t find_member(std::string name, | |
| 199 | + const std::vector<std::string> names, | |
| 200 | + bool ignore_case = false, | |
| 201 | + bool ignore_underscore = false); | |
| 333 | 202 | |
| 334 | 203 | /// Find a trigger string and call a modify callable function that takes the current string and starting position of the |
| 335 | 204 | /// trigger and returns the position in the string to search for the next trigger string |
| ... | ... | @@ -343,88 +212,23 @@ template <typename Callable> inline std::string find_and_modify(std::string str, |
| 343 | 212 | |
| 344 | 213 | /// Split a string '"one two" "three"' into 'one two', 'three' |
| 345 | 214 | /// Quote characters can be ` ' or " |
| 346 | -inline std::vector<std::string> split_up(std::string str, char delimiter = '\0') { | |
| 347 | - | |
| 348 | - const std::string delims("\'\"`"); | |
| 349 | - auto find_ws = [delimiter](char ch) { | |
| 350 | - return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter); | |
| 351 | - }; | |
| 352 | - trim(str); | |
| 353 | - | |
| 354 | - std::vector<std::string> output; | |
| 355 | - bool embeddedQuote = false; | |
| 356 | - char keyChar = ' '; | |
| 357 | - while(!str.empty()) { | |
| 358 | - if(delims.find_first_of(str[0]) != std::string::npos) { | |
| 359 | - keyChar = str[0]; | |
| 360 | - auto end = str.find_first_of(keyChar, 1); | |
| 361 | - while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes | |
| 362 | - end = str.find_first_of(keyChar, end + 1); | |
| 363 | - embeddedQuote = true; | |
| 364 | - } | |
| 365 | - if(end != std::string::npos) { | |
| 366 | - output.push_back(str.substr(1, end - 1)); | |
| 367 | - if(end + 2 < str.size()) { | |
| 368 | - str = str.substr(end + 2); | |
| 369 | - } else { | |
| 370 | - str.clear(); | |
| 371 | - } | |
| 372 | - | |
| 373 | - } else { | |
| 374 | - output.push_back(str.substr(1)); | |
| 375 | - str = ""; | |
| 376 | - } | |
| 377 | - } else { | |
| 378 | - auto it = std::find_if(std::begin(str), std::end(str), find_ws); | |
| 379 | - if(it != std::end(str)) { | |
| 380 | - std::string value = std::string(str.begin(), it); | |
| 381 | - output.push_back(value); | |
| 382 | - str = std::string(it + 1, str.end()); | |
| 383 | - } else { | |
| 384 | - output.push_back(str); | |
| 385 | - str = ""; | |
| 386 | - } | |
| 387 | - } | |
| 388 | - // transform any embedded quotes into the regular character | |
| 389 | - if(embeddedQuote) { | |
| 390 | - output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar)); | |
| 391 | - embeddedQuote = false; | |
| 392 | - } | |
| 393 | - trim(str); | |
| 394 | - } | |
| 395 | - return output; | |
| 396 | -} | |
| 215 | +CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0'); | |
| 397 | 216 | |
| 398 | 217 | /// This function detects an equal or colon followed by an escaped quote after an argument |
| 399 | 218 | /// then modifies the string to replace the equality with a space. This is needed |
| 400 | 219 | /// to allow the split up function to work properly and is intended to be used with the find_and_modify function |
| 401 | 220 | /// the return value is the offset+1 which is required by the find_and_modify function. |
| 402 | -inline std::size_t escape_detect(std::string &str, std::size_t offset) { | |
| 403 | - auto next = str[offset + 1]; | |
| 404 | - if((next == '\"') || (next == '\'') || (next == '`')) { | |
| 405 | - auto astart = str.find_last_of("-/ \"\'`", offset - 1); | |
| 406 | - if(astart != std::string::npos) { | |
| 407 | - if(str[astart] == ((str[offset] == '=') ? '-' : '/')) | |
| 408 | - str[offset] = ' '; // interpret this as a space so the split_up works properly | |
| 409 | - } | |
| 410 | - } | |
| 411 | - return offset + 1; | |
| 412 | -} | |
| 221 | +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset); | |
| 413 | 222 | |
| 414 | 223 | /// Add quotes if the string contains spaces |
| 415 | -inline std::string &add_quotes_if_needed(std::string &str) { | |
| 416 | - if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) { | |
| 417 | - char quote = str.find('"') < str.find('\'') ? '\'' : '"'; | |
| 418 | - if(str.find(' ') != std::string::npos) { | |
| 419 | - str.insert(0, 1, quote); | |
| 420 | - str.append(1, quote); | |
| 421 | - } | |
| 422 | - } | |
| 423 | - return str; | |
| 424 | -} | |
| 224 | +CLI11_INLINE std::string &add_quotes_if_needed(std::string &str); | |
| 425 | 225 | |
| 426 | 226 | } // namespace detail |
| 427 | 227 | |
| 428 | 228 | // [CLI11:string_tools_hpp:end] |
| 429 | 229 | |
| 430 | 230 | } // namespace CLI |
| 231 | + | |
| 232 | +#ifndef CLI11_COMPILE | |
| 233 | +#include "impl/StringTools_inl.hpp" | |
| 234 | +#endif | ... | ... |
include/CLI/impl/StringTools_inl.hpp
0 → 100644
| 1 | +// Copyright (c) 2017-2022, University of Cincinnati, developed by Henry Schreiner | |
| 2 | +// under NSF AWARD 1414736 and by the respective contributors. | |
| 3 | +// All rights reserved. | |
| 4 | +// | |
| 5 | +// SPDX-License-Identifier: BSD-3-Clause | |
| 6 | + | |
| 7 | +#pragma once | |
| 8 | + | |
| 9 | +// This include is only needed for IDEs to discover symbols | |
| 10 | +#include <CLI/StringTools.hpp> | |
| 11 | + | |
| 12 | +// [CLI11:public_includes:set] | |
| 13 | +#include <string> | |
| 14 | +#include <vector> | |
| 15 | +// [CLI11:public_includes:end] | |
| 16 | + | |
| 17 | +namespace CLI { | |
| 18 | +// [CLI11:string_tools_inl_hpp:verbatim] | |
| 19 | + | |
| 20 | +namespace detail { | |
| 21 | +CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim) { | |
| 22 | + std::vector<std::string> elems; | |
| 23 | + // Check to see if empty string, give consistent result | |
| 24 | + if(s.empty()) { | |
| 25 | + elems.emplace_back(); | |
| 26 | + } else { | |
| 27 | + std::stringstream ss; | |
| 28 | + ss.str(s); | |
| 29 | + std::string item; | |
| 30 | + while(std::getline(ss, item, delim)) { | |
| 31 | + elems.push_back(item); | |
| 32 | + } | |
| 33 | + } | |
| 34 | + return elems; | |
| 35 | +} | |
| 36 | + | |
| 37 | +CLI11_INLINE std::string <rim(std::string &str) { | |
| 38 | + auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); }); | |
| 39 | + str.erase(str.begin(), it); | |
| 40 | + return str; | |
| 41 | +} | |
| 42 | + | |
| 43 | +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter) { | |
| 44 | + auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); | |
| 45 | + str.erase(str.begin(), it); | |
| 46 | + return str; | |
| 47 | +} | |
| 48 | + | |
| 49 | +CLI11_INLINE std::string &rtrim(std::string &str) { | |
| 50 | + auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); }); | |
| 51 | + str.erase(it.base(), str.end()); | |
| 52 | + return str; | |
| 53 | +} | |
| 54 | + | |
| 55 | +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) { | |
| 56 | + auto it = | |
| 57 | + std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); | |
| 58 | + str.erase(it.base(), str.end()); | |
| 59 | + return str; | |
| 60 | +} | |
| 61 | + | |
| 62 | +CLI11_INLINE std::string &remove_quotes(std::string &str) { | |
| 63 | + if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) { | |
| 64 | + if(str.front() == str.back()) { | |
| 65 | + str.pop_back(); | |
| 66 | + str.erase(str.begin(), str.begin() + 1); | |
| 67 | + } | |
| 68 | + } | |
| 69 | + return str; | |
| 70 | +} | |
| 71 | + | |
| 72 | +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) { | |
| 73 | + std::string::size_type n = 0; | |
| 74 | + while(n != std::string::npos && n < input.size()) { | |
| 75 | + n = input.find('\n', n); | |
| 76 | + if(n != std::string::npos) { | |
| 77 | + input = input.substr(0, n + 1) + leader + input.substr(n + 1); | |
| 78 | + n += leader.size(); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + return input; | |
| 82 | +} | |
| 83 | + | |
| 84 | +CLI11_INLINE std::ostream & | |
| 85 | +format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { | |
| 86 | + name = " " + name; | |
| 87 | + out << std::setw(static_cast<int>(wid)) << std::left << name; | |
| 88 | + if(!description.empty()) { | |
| 89 | + if(name.length() >= wid) | |
| 90 | + out << "\n" << std::setw(static_cast<int>(wid)) << ""; | |
| 91 | + for(const char c : description) { | |
| 92 | + out.put(c); | |
| 93 | + if(c == '\n') { | |
| 94 | + out << std::setw(static_cast<int>(wid)) << ""; | |
| 95 | + } | |
| 96 | + } | |
| 97 | + } | |
| 98 | + out << "\n"; | |
| 99 | + return out; | |
| 100 | +} | |
| 101 | + | |
| 102 | +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) { | |
| 103 | + if(!aliases.empty()) { | |
| 104 | + out << std::setw(static_cast<int>(wid)) << " aliases: "; | |
| 105 | + bool front = true; | |
| 106 | + for(const auto &alias : aliases) { | |
| 107 | + if(!front) { | |
| 108 | + out << ", "; | |
| 109 | + } else { | |
| 110 | + front = false; | |
| 111 | + } | |
| 112 | + out << detail::fix_newlines(" ", alias); | |
| 113 | + } | |
| 114 | + out << "\n"; | |
| 115 | + } | |
| 116 | + return out; | |
| 117 | +} | |
| 118 | + | |
| 119 | +CLI11_INLINE bool valid_name_string(const std::string &str) { | |
| 120 | + if(str.empty() || !valid_first_char(str[0])) { | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + auto e = str.end(); | |
| 124 | + for(auto c = str.begin() + 1; c != e; ++c) | |
| 125 | + if(!valid_later_char(*c)) | |
| 126 | + return false; | |
| 127 | + return true; | |
| 128 | +} | |
| 129 | + | |
| 130 | +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) { | |
| 131 | + | |
| 132 | + std::size_t start_pos = 0; | |
| 133 | + | |
| 134 | + while((start_pos = str.find(from, start_pos)) != std::string::npos) { | |
| 135 | + str.replace(start_pos, from.length(), to); | |
| 136 | + start_pos += to.length(); | |
| 137 | + } | |
| 138 | + | |
| 139 | + return str; | |
| 140 | +} | |
| 141 | + | |
| 142 | +CLI11_INLINE void remove_default_flag_values(std::string &flags) { | |
| 143 | + auto loc = flags.find_first_of('{', 2); | |
| 144 | + while(loc != std::string::npos) { | |
| 145 | + auto finish = flags.find_first_of("},", loc + 1); | |
| 146 | + if((finish != std::string::npos) && (flags[finish] == '}')) { | |
| 147 | + flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc), | |
| 148 | + flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1); | |
| 149 | + } | |
| 150 | + loc = flags.find_first_of('{', loc + 1); | |
| 151 | + } | |
| 152 | + flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end()); | |
| 153 | +} | |
| 154 | + | |
| 155 | +CLI11_INLINE std::ptrdiff_t find_member(std::string name, | |
| 156 | + const std::vector<std::string> names, | |
| 157 | + bool ignore_case, | |
| 158 | + bool ignore_underscore) { | |
| 159 | + auto it = std::end(names); | |
| 160 | + if(ignore_case) { | |
| 161 | + if(ignore_underscore) { | |
| 162 | + name = detail::to_lower(detail::remove_underscore(name)); | |
| 163 | + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 164 | + return detail::to_lower(detail::remove_underscore(local_name)) == name; | |
| 165 | + }); | |
| 166 | + } else { | |
| 167 | + name = detail::to_lower(name); | |
| 168 | + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 169 | + return detail::to_lower(local_name) == name; | |
| 170 | + }); | |
| 171 | + } | |
| 172 | + | |
| 173 | + } else if(ignore_underscore) { | |
| 174 | + name = detail::remove_underscore(name); | |
| 175 | + it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { | |
| 176 | + return detail::remove_underscore(local_name) == name; | |
| 177 | + }); | |
| 178 | + } else { | |
| 179 | + it = std::find(std::begin(names), std::end(names), name); | |
| 180 | + } | |
| 181 | + | |
| 182 | + return (it != std::end(names)) ? (it - std::begin(names)) : (-1); | |
| 183 | +} | |
| 184 | + | |
| 185 | +CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter) { | |
| 186 | + | |
| 187 | + const std::string delims("\'\"`"); | |
| 188 | + auto find_ws = [delimiter](char ch) { | |
| 189 | + return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter); | |
| 190 | + }; | |
| 191 | + trim(str); | |
| 192 | + | |
| 193 | + std::vector<std::string> output; | |
| 194 | + bool embeddedQuote = false; | |
| 195 | + char keyChar = ' '; | |
| 196 | + while(!str.empty()) { | |
| 197 | + if(delims.find_first_of(str[0]) != std::string::npos) { | |
| 198 | + keyChar = str[0]; | |
| 199 | + auto end = str.find_first_of(keyChar, 1); | |
| 200 | + while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes | |
| 201 | + end = str.find_first_of(keyChar, end + 1); | |
| 202 | + embeddedQuote = true; | |
| 203 | + } | |
| 204 | + if(end != std::string::npos) { | |
| 205 | + output.push_back(str.substr(1, end - 1)); | |
| 206 | + if(end + 2 < str.size()) { | |
| 207 | + str = str.substr(end + 2); | |
| 208 | + } else { | |
| 209 | + str.clear(); | |
| 210 | + } | |
| 211 | + | |
| 212 | + } else { | |
| 213 | + output.push_back(str.substr(1)); | |
| 214 | + str = ""; | |
| 215 | + } | |
| 216 | + } else { | |
| 217 | + auto it = std::find_if(std::begin(str), std::end(str), find_ws); | |
| 218 | + if(it != std::end(str)) { | |
| 219 | + std::string value = std::string(str.begin(), it); | |
| 220 | + output.push_back(value); | |
| 221 | + str = std::string(it + 1, str.end()); | |
| 222 | + } else { | |
| 223 | + output.push_back(str); | |
| 224 | + str = ""; | |
| 225 | + } | |
| 226 | + } | |
| 227 | + // transform any embedded quotes into the regular character | |
| 228 | + if(embeddedQuote) { | |
| 229 | + output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar)); | |
| 230 | + embeddedQuote = false; | |
| 231 | + } | |
| 232 | + trim(str); | |
| 233 | + } | |
| 234 | + return output; | |
| 235 | +} | |
| 236 | + | |
| 237 | +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { | |
| 238 | + auto next = str[offset + 1]; | |
| 239 | + if((next == '\"') || (next == '\'') || (next == '`')) { | |
| 240 | + auto astart = str.find_last_of("-/ \"\'`", offset - 1); | |
| 241 | + if(astart != std::string::npos) { | |
| 242 | + if(str[astart] == ((str[offset] == '=') ? '-' : '/')) | |
| 243 | + str[offset] = ' '; // interpret this as a space so the split_up works properly | |
| 244 | + } | |
| 245 | + } | |
| 246 | + return offset + 1; | |
| 247 | +} | |
| 248 | + | |
| 249 | +CLI11_INLINE std::string &add_quotes_if_needed(std::string &str) { | |
| 250 | + if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) { | |
| 251 | + char quote = str.find('"') < str.find('\'') ? '\'' : '"'; | |
| 252 | + if(str.find(' ') != std::string::npos) { | |
| 253 | + str.insert(0, 1, quote); | |
| 254 | + str.append(1, quote); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + return str; | |
| 258 | +} | |
| 259 | + | |
| 260 | +} // namespace detail | |
| 261 | +// [CLI11:string_tools_inl_hpp:end] | |
| 262 | +} // namespace CLI | ... | ... |
src/StringTools.cpp
0 → 100644