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,6 +17,8 @@ | ||
| 17 | #include <vector> | 17 | #include <vector> |
| 18 | // [CLI11:public_includes:end] | 18 | // [CLI11:public_includes:end] |
| 19 | 19 | ||
| 20 | +#include "Macros.hpp" | ||
| 21 | + | ||
| 20 | namespace CLI { | 22 | namespace CLI { |
| 21 | 23 | ||
| 22 | // [CLI11:string_tools_hpp:verbatim] | 24 | // [CLI11:string_tools_hpp:verbatim] |
| @@ -43,21 +45,7 @@ namespace detail { | @@ -43,21 +45,7 @@ namespace detail { | ||
| 43 | constexpr int expected_max_vector_size{1 << 29}; | 45 | constexpr int expected_max_vector_size{1 << 29}; |
| 44 | // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c | 46 | // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c |
| 45 | /// Split a string by a delim | 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 | /// Simple function to join a string | 50 | /// Simple function to join a string |
| 63 | template <typename T> std::string join(const T &v, std::string delim = ",") { | 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,33 +94,16 @@ template <typename T> std::string rjoin(const T &v, std::string delim = ",") { | ||
| 106 | // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string | 94 | // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string |
| 107 | 95 | ||
| 108 | /// Trim whitespace from left of string | 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 | /// Trim anything from left of string | 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 | /// Trim whitespace from right of string | 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 | /// Trim anything from right of string | 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 | /// Trim whitespace from string | 108 | /// Trim whitespace from string |
| 138 | inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); } | 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,31 +118,13 @@ inline std::string trim_copy(const std::string &str) { | ||
| 147 | } | 118 | } |
| 148 | 119 | ||
| 149 | /// remove quotes at the front and back of a string either '"' or '\'' | 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 | /// Add a leader to the beginning of all new lines (nothing is added | 123 | /// Add a leader to the beginning of all new lines (nothing is added |
| 161 | /// at the start of the first line). `"; "` would be for ini files | 124 | /// at the start of the first line). `"; "` would be for ini files |
| 162 | /// | 125 | /// |
| 163 | /// Can't use Regex, or this would be a subs. | 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 | /// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) | 129 | /// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) |
| 177 | inline std::string trim_copy(const std::string &str, const std::string &filter) { | 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,40 +132,11 @@ inline std::string trim_copy(const std::string &str, const std::string &filter) | ||
| 179 | return trim(s, filter); | 132 | return trim(s, filter); |
| 180 | } | 133 | } |
| 181 | /// Print a two part "help" string | 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 | /// Print subcommand aliases | 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 | /// Verify the first character of an option | 141 | /// Verify the first character of an option |
| 218 | /// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with | 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,16 +151,7 @@ template <typename T> bool valid_later_char(T c) { | ||
| 227 | } | 151 | } |
| 228 | 152 | ||
| 229 | /// Verify an option/subcommand name | 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 | /// Verify an app name | 156 | /// Verify an app name |
| 242 | inline bool valid_alias_name_string(const std::string &str) { | 157 | inline bool valid_alias_name_string(const std::string &str) { |
| @@ -270,66 +185,20 @@ inline std::string remove_underscore(std::string str) { | @@ -270,66 +185,20 @@ inline std::string remove_underscore(std::string str) { | ||
| 270 | } | 185 | } |
| 271 | 186 | ||
| 272 | /// Find and replace a substring with another substring | 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 | /// check if the flag definitions has possible false flags | 190 | /// check if the flag definitions has possible false flags |
| 286 | inline bool has_default_flag_values(const std::string &flags) { | 191 | inline bool has_default_flag_values(const std::string &flags) { |
| 287 | return (flags.find_first_of("{!") != std::string::npos); | 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 | /// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores | 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 | /// Find a trigger string and call a modify callable function that takes the current string and starting position of the | 203 | /// Find a trigger string and call a modify callable function that takes the current string and starting position of the |
| 335 | /// trigger and returns the position in the string to search for the next trigger string | 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,88 +212,23 @@ template <typename Callable> inline std::string find_and_modify(std::string str, | ||
| 343 | 212 | ||
| 344 | /// Split a string '"one two" "three"' into 'one two', 'three' | 213 | /// Split a string '"one two" "three"' into 'one two', 'three' |
| 345 | /// Quote characters can be ` ' or " | 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 | /// This function detects an equal or colon followed by an escaped quote after an argument | 217 | /// This function detects an equal or colon followed by an escaped quote after an argument |
| 399 | /// then modifies the string to replace the equality with a space. This is needed | 218 | /// then modifies the string to replace the equality with a space. This is needed |
| 400 | /// to allow the split up function to work properly and is intended to be used with the find_and_modify function | 219 | /// to allow the split up function to work properly and is intended to be used with the find_and_modify function |
| 401 | /// the return value is the offset+1 which is required by the find_and_modify function. | 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 | /// Add quotes if the string contains spaces | 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 | } // namespace detail | 226 | } // namespace detail |
| 427 | 227 | ||
| 428 | // [CLI11:string_tools_hpp:end] | 228 | // [CLI11:string_tools_hpp:end] |
| 429 | 229 | ||
| 430 | } // namespace CLI | 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