mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-05 14:43:52 +00:00
[precompile] Split StringTools.hpp
This commit is contained in:
parent
d1f0f483da
commit
4048596250
@ -46,6 +46,8 @@ namespace {namespace} {{
|
|||||||
|
|
||||||
{string_tools_hpp}
|
{string_tools_hpp}
|
||||||
|
|
||||||
|
{string_tools_inl_hpp}
|
||||||
|
|
||||||
{error_hpp}
|
{error_hpp}
|
||||||
|
|
||||||
{type_tools_hpp}
|
{type_tools_hpp}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
// [CLI11:public_includes:end]
|
// [CLI11:public_includes:end]
|
||||||
|
|
||||||
|
#include "Macros.hpp"
|
||||||
|
|
||||||
namespace CLI {
|
namespace CLI {
|
||||||
|
|
||||||
// [CLI11:string_tools_hpp:verbatim]
|
// [CLI11:string_tools_hpp:verbatim]
|
||||||
@ -43,21 +45,7 @@ namespace detail {
|
|||||||
constexpr int expected_max_vector_size{1 << 29};
|
constexpr int expected_max_vector_size{1 << 29};
|
||||||
// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
|
// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
|
||||||
/// Split a string by a delim
|
/// Split a string by a delim
|
||||||
inline std::vector<std::string> split(const std::string &s, char delim) {
|
CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
|
||||||
std::vector<std::string> elems;
|
|
||||||
// Check to see if empty string, give consistent result
|
|
||||||
if(s.empty()) {
|
|
||||||
elems.emplace_back();
|
|
||||||
} else {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss.str(s);
|
|
||||||
std::string item;
|
|
||||||
while(std::getline(ss, item, delim)) {
|
|
||||||
elems.push_back(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simple function to join a string
|
/// Simple function to join a string
|
||||||
template <typename T> std::string join(const T &v, std::string delim = ",") {
|
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 = ",") {
|
|||||||
// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
|
// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
|
||||||
|
|
||||||
/// Trim whitespace from left of string
|
/// Trim whitespace from left of string
|
||||||
inline std::string <rim(std::string &str) {
|
CLI11_INLINE std::string <rim(std::string &str);
|
||||||
auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
|
|
||||||
str.erase(str.begin(), it);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trim anything from left of string
|
/// Trim anything from left of string
|
||||||
inline std::string <rim(std::string &str, const std::string &filter) {
|
CLI11_INLINE std::string <rim(std::string &str, const std::string &filter);
|
||||||
auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
|
|
||||||
str.erase(str.begin(), it);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trim whitespace from right of string
|
/// Trim whitespace from right of string
|
||||||
inline std::string &rtrim(std::string &str) {
|
CLI11_INLINE std::string &rtrim(std::string &str);
|
||||||
auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
|
|
||||||
str.erase(it.base(), str.end());
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trim anything from right of string
|
/// Trim anything from right of string
|
||||||
inline std::string &rtrim(std::string &str, const std::string &filter) {
|
CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter);
|
||||||
auto it =
|
|
||||||
std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
|
|
||||||
str.erase(it.base(), str.end());
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trim whitespace from string
|
/// Trim whitespace from string
|
||||||
inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
|
inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
|
||||||
@ -147,31 +118,13 @@ inline std::string trim_copy(const std::string &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// remove quotes at the front and back of a string either '"' or '\''
|
/// remove quotes at the front and back of a string either '"' or '\''
|
||||||
inline std::string &remove_quotes(std::string &str) {
|
CLI11_INLINE std::string &remove_quotes(std::string &str);
|
||||||
if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) {
|
|
||||||
if(str.front() == str.back()) {
|
|
||||||
str.pop_back();
|
|
||||||
str.erase(str.begin(), str.begin() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a leader to the beginning of all new lines (nothing is added
|
/// Add a leader to the beginning of all new lines (nothing is added
|
||||||
/// at the start of the first line). `"; "` would be for ini files
|
/// at the start of the first line). `"; "` would be for ini files
|
||||||
///
|
///
|
||||||
/// Can't use Regex, or this would be a subs.
|
/// Can't use Regex, or this would be a subs.
|
||||||
inline std::string fix_newlines(const std::string &leader, std::string input) {
|
CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input);
|
||||||
std::string::size_type n = 0;
|
|
||||||
while(n != std::string::npos && n < input.size()) {
|
|
||||||
n = input.find('\n', n);
|
|
||||||
if(n != std::string::npos) {
|
|
||||||
input = input.substr(0, n + 1) + leader + input.substr(n + 1);
|
|
||||||
n += leader.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered)
|
/// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered)
|
||||||
inline std::string trim_copy(const std::string &str, const std::string &filter) {
|
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)
|
|||||||
return trim(s, filter);
|
return trim(s, filter);
|
||||||
}
|
}
|
||||||
/// Print a two part "help" string
|
/// Print a two part "help" string
|
||||||
inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) {
|
CLI11_INLINE std::ostream &
|
||||||
name = " " + name;
|
format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid);
|
||||||
out << std::setw(static_cast<int>(wid)) << std::left << name;
|
|
||||||
if(!description.empty()) {
|
|
||||||
if(name.length() >= wid)
|
|
||||||
out << "\n" << std::setw(static_cast<int>(wid)) << "";
|
|
||||||
for(const char c : description) {
|
|
||||||
out.put(c);
|
|
||||||
if(c == '\n') {
|
|
||||||
out << std::setw(static_cast<int>(wid)) << "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << "\n";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print subcommand aliases
|
/// Print subcommand aliases
|
||||||
inline std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
|
CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid);
|
||||||
if(!aliases.empty()) {
|
|
||||||
out << std::setw(static_cast<int>(wid)) << " aliases: ";
|
|
||||||
bool front = true;
|
|
||||||
for(const auto &alias : aliases) {
|
|
||||||
if(!front) {
|
|
||||||
out << ", ";
|
|
||||||
} else {
|
|
||||||
front = false;
|
|
||||||
}
|
|
||||||
out << detail::fix_newlines(" ", alias);
|
|
||||||
}
|
|
||||||
out << "\n";
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify the first character of an option
|
/// Verify the first character of an option
|
||||||
/// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with
|
/// - 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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify an option/subcommand name
|
/// Verify an option/subcommand name
|
||||||
inline bool valid_name_string(const std::string &str) {
|
CLI11_INLINE bool valid_name_string(const std::string &str);
|
||||||
if(str.empty() || !valid_first_char(str[0])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto e = str.end();
|
|
||||||
for(auto c = str.begin() + 1; c != e; ++c)
|
|
||||||
if(!valid_later_char(*c))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify an app name
|
/// Verify an app name
|
||||||
inline bool valid_alias_name_string(const std::string &str) {
|
inline bool valid_alias_name_string(const std::string &str) {
|
||||||
@ -270,66 +185,20 @@ inline std::string remove_underscore(std::string str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find and replace a substring with another substring
|
/// Find and replace a substring with another substring
|
||||||
inline std::string find_and_replace(std::string str, std::string from, std::string to) {
|
CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to);
|
||||||
|
|
||||||
std::size_t start_pos = 0;
|
|
||||||
|
|
||||||
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
|
||||||
str.replace(start_pos, from.length(), to);
|
|
||||||
start_pos += to.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// check if the flag definitions has possible false flags
|
/// check if the flag definitions has possible false flags
|
||||||
inline bool has_default_flag_values(const std::string &flags) {
|
inline bool has_default_flag_values(const std::string &flags) {
|
||||||
return (flags.find_first_of("{!") != std::string::npos);
|
return (flags.find_first_of("{!") != std::string::npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void remove_default_flag_values(std::string &flags) {
|
CLI11_INLINE void remove_default_flag_values(std::string &flags);
|
||||||
auto loc = flags.find_first_of('{', 2);
|
|
||||||
while(loc != std::string::npos) {
|
|
||||||
auto finish = flags.find_first_of("},", loc + 1);
|
|
||||||
if((finish != std::string::npos) && (flags[finish] == '}')) {
|
|
||||||
flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
|
|
||||||
flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
|
|
||||||
}
|
|
||||||
loc = flags.find_first_of('{', loc + 1);
|
|
||||||
}
|
|
||||||
flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores
|
/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores
|
||||||
inline std::ptrdiff_t find_member(std::string name,
|
CLI11_INLINE std::ptrdiff_t find_member(std::string name,
|
||||||
const std::vector<std::string> names,
|
const std::vector<std::string> names,
|
||||||
bool ignore_case = false,
|
bool ignore_case = false,
|
||||||
bool ignore_underscore = false) {
|
bool ignore_underscore = false);
|
||||||
auto it = std::end(names);
|
|
||||||
if(ignore_case) {
|
|
||||||
if(ignore_underscore) {
|
|
||||||
name = detail::to_lower(detail::remove_underscore(name));
|
|
||||||
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
|
||||||
return detail::to_lower(detail::remove_underscore(local_name)) == name;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
name = detail::to_lower(name);
|
|
||||||
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
|
||||||
return detail::to_lower(local_name) == name;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(ignore_underscore) {
|
|
||||||
name = detail::remove_underscore(name);
|
|
||||||
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
|
||||||
return detail::remove_underscore(local_name) == name;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
it = std::find(std::begin(names), std::end(names), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find a trigger string and call a modify callable function that takes the current string and starting position of the
|
/// Find a trigger string and call a modify callable function that takes the current string and starting position of the
|
||||||
/// trigger and returns the position in the string to search for the next trigger string
|
/// 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,
|
|||||||
|
|
||||||
/// Split a string '"one two" "three"' into 'one two', 'three'
|
/// Split a string '"one two" "three"' into 'one two', 'three'
|
||||||
/// Quote characters can be ` ' or "
|
/// Quote characters can be ` ' or "
|
||||||
inline std::vector<std::string> split_up(std::string str, char delimiter = '\0') {
|
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter = '\0');
|
||||||
|
|
||||||
const std::string delims("\'\"`");
|
|
||||||
auto find_ws = [delimiter](char ch) {
|
|
||||||
return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
|
|
||||||
};
|
|
||||||
trim(str);
|
|
||||||
|
|
||||||
std::vector<std::string> output;
|
|
||||||
bool embeddedQuote = false;
|
|
||||||
char keyChar = ' ';
|
|
||||||
while(!str.empty()) {
|
|
||||||
if(delims.find_first_of(str[0]) != std::string::npos) {
|
|
||||||
keyChar = str[0];
|
|
||||||
auto end = str.find_first_of(keyChar, 1);
|
|
||||||
while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
|
|
||||||
end = str.find_first_of(keyChar, end + 1);
|
|
||||||
embeddedQuote = true;
|
|
||||||
}
|
|
||||||
if(end != std::string::npos) {
|
|
||||||
output.push_back(str.substr(1, end - 1));
|
|
||||||
if(end + 2 < str.size()) {
|
|
||||||
str = str.substr(end + 2);
|
|
||||||
} else {
|
|
||||||
str.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
output.push_back(str.substr(1));
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto it = std::find_if(std::begin(str), std::end(str), find_ws);
|
|
||||||
if(it != std::end(str)) {
|
|
||||||
std::string value = std::string(str.begin(), it);
|
|
||||||
output.push_back(value);
|
|
||||||
str = std::string(it + 1, str.end());
|
|
||||||
} else {
|
|
||||||
output.push_back(str);
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// transform any embedded quotes into the regular character
|
|
||||||
if(embeddedQuote) {
|
|
||||||
output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar));
|
|
||||||
embeddedQuote = false;
|
|
||||||
}
|
|
||||||
trim(str);
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function detects an equal or colon followed by an escaped quote after an argument
|
/// This function detects an equal or colon followed by an escaped quote after an argument
|
||||||
/// then modifies the string to replace the equality with a space. This is needed
|
/// then modifies the string to replace the equality with a space. This is needed
|
||||||
/// to allow the split up function to work properly and is intended to be used with the find_and_modify function
|
/// to allow the split up function to work properly and is intended to be used with the find_and_modify function
|
||||||
/// the return value is the offset+1 which is required by the find_and_modify function.
|
/// the return value is the offset+1 which is required by the find_and_modify function.
|
||||||
inline std::size_t escape_detect(std::string &str, std::size_t offset) {
|
CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset);
|
||||||
auto next = str[offset + 1];
|
|
||||||
if((next == '\"') || (next == '\'') || (next == '`')) {
|
|
||||||
auto astart = str.find_last_of("-/ \"\'`", offset - 1);
|
|
||||||
if(astart != std::string::npos) {
|
|
||||||
if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
|
|
||||||
str[offset] = ' '; // interpret this as a space so the split_up works properly
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add quotes if the string contains spaces
|
/// Add quotes if the string contains spaces
|
||||||
inline std::string &add_quotes_if_needed(std::string &str) {
|
CLI11_INLINE std::string &add_quotes_if_needed(std::string &str);
|
||||||
if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) {
|
|
||||||
char quote = str.find('"') < str.find('\'') ? '\'' : '"';
|
|
||||||
if(str.find(' ') != std::string::npos) {
|
|
||||||
str.insert(0, 1, quote);
|
|
||||||
str.append(1, quote);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// [CLI11:string_tools_hpp:end]
|
// [CLI11:string_tools_hpp:end]
|
||||||
|
|
||||||
} // namespace CLI
|
} // namespace CLI
|
||||||
|
|
||||||
|
#ifndef CLI11_COMPILE
|
||||||
|
#include "impl/StringTools_inl.hpp"
|
||||||
|
#endif
|
||||||
|
262
include/CLI/impl/StringTools_inl.hpp
Normal file
262
include/CLI/impl/StringTools_inl.hpp
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
// Copyright (c) 2017-2022, 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
|
||||||
|
|
||||||
|
// This include is only needed for IDEs to discover symbols
|
||||||
|
#include <CLI/StringTools.hpp>
|
||||||
|
|
||||||
|
// [CLI11:public_includes:set]
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
// [CLI11:public_includes:end]
|
||||||
|
|
||||||
|
namespace CLI {
|
||||||
|
// [CLI11:string_tools_inl_hpp:verbatim]
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim) {
|
||||||
|
std::vector<std::string> elems;
|
||||||
|
// Check to see if empty string, give consistent result
|
||||||
|
if(s.empty()) {
|
||||||
|
elems.emplace_back();
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.str(s);
|
||||||
|
std::string item;
|
||||||
|
while(std::getline(ss, item, delim)) {
|
||||||
|
elems.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string <rim(std::string &str) {
|
||||||
|
auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
|
||||||
|
str.erase(str.begin(), it);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string <rim(std::string &str, const std::string &filter) {
|
||||||
|
auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
|
||||||
|
str.erase(str.begin(), it);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string &rtrim(std::string &str) {
|
||||||
|
auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
|
||||||
|
str.erase(it.base(), str.end());
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) {
|
||||||
|
auto it =
|
||||||
|
std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
|
||||||
|
str.erase(it.base(), str.end());
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string &remove_quotes(std::string &str) {
|
||||||
|
if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) {
|
||||||
|
if(str.front() == str.back()) {
|
||||||
|
str.pop_back();
|
||||||
|
str.erase(str.begin(), str.begin() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) {
|
||||||
|
std::string::size_type n = 0;
|
||||||
|
while(n != std::string::npos && n < input.size()) {
|
||||||
|
n = input.find('\n', n);
|
||||||
|
if(n != std::string::npos) {
|
||||||
|
input = input.substr(0, n + 1) + leader + input.substr(n + 1);
|
||||||
|
n += leader.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::ostream &
|
||||||
|
format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) {
|
||||||
|
name = " " + name;
|
||||||
|
out << std::setw(static_cast<int>(wid)) << std::left << name;
|
||||||
|
if(!description.empty()) {
|
||||||
|
if(name.length() >= wid)
|
||||||
|
out << "\n" << std::setw(static_cast<int>(wid)) << "";
|
||||||
|
for(const char c : description) {
|
||||||
|
out.put(c);
|
||||||
|
if(c == '\n') {
|
||||||
|
out << std::setw(static_cast<int>(wid)) << "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
|
||||||
|
if(!aliases.empty()) {
|
||||||
|
out << std::setw(static_cast<int>(wid)) << " aliases: ";
|
||||||
|
bool front = true;
|
||||||
|
for(const auto &alias : aliases) {
|
||||||
|
if(!front) {
|
||||||
|
out << ", ";
|
||||||
|
} else {
|
||||||
|
front = false;
|
||||||
|
}
|
||||||
|
out << detail::fix_newlines(" ", alias);
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE bool valid_name_string(const std::string &str) {
|
||||||
|
if(str.empty() || !valid_first_char(str[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto e = str.end();
|
||||||
|
for(auto c = str.begin() + 1; c != e; ++c)
|
||||||
|
if(!valid_later_char(*c))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) {
|
||||||
|
|
||||||
|
std::size_t start_pos = 0;
|
||||||
|
|
||||||
|
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||||
|
str.replace(start_pos, from.length(), to);
|
||||||
|
start_pos += to.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE void remove_default_flag_values(std::string &flags) {
|
||||||
|
auto loc = flags.find_first_of('{', 2);
|
||||||
|
while(loc != std::string::npos) {
|
||||||
|
auto finish = flags.find_first_of("},", loc + 1);
|
||||||
|
if((finish != std::string::npos) && (flags[finish] == '}')) {
|
||||||
|
flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
|
||||||
|
flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
|
||||||
|
}
|
||||||
|
loc = flags.find_first_of('{', loc + 1);
|
||||||
|
}
|
||||||
|
flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::ptrdiff_t find_member(std::string name,
|
||||||
|
const std::vector<std::string> names,
|
||||||
|
bool ignore_case,
|
||||||
|
bool ignore_underscore) {
|
||||||
|
auto it = std::end(names);
|
||||||
|
if(ignore_case) {
|
||||||
|
if(ignore_underscore) {
|
||||||
|
name = detail::to_lower(detail::remove_underscore(name));
|
||||||
|
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
||||||
|
return detail::to_lower(detail::remove_underscore(local_name)) == name;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
name = detail::to_lower(name);
|
||||||
|
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
||||||
|
return detail::to_lower(local_name) == name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(ignore_underscore) {
|
||||||
|
name = detail::remove_underscore(name);
|
||||||
|
it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
|
||||||
|
return detail::remove_underscore(local_name) == name;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
it = std::find(std::begin(names), std::end(names), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::vector<std::string> split_up(std::string str, char delimiter) {
|
||||||
|
|
||||||
|
const std::string delims("\'\"`");
|
||||||
|
auto find_ws = [delimiter](char ch) {
|
||||||
|
return (delimiter == '\0') ? std::isspace<char>(ch, std::locale()) : (ch == delimiter);
|
||||||
|
};
|
||||||
|
trim(str);
|
||||||
|
|
||||||
|
std::vector<std::string> output;
|
||||||
|
bool embeddedQuote = false;
|
||||||
|
char keyChar = ' ';
|
||||||
|
while(!str.empty()) {
|
||||||
|
if(delims.find_first_of(str[0]) != std::string::npos) {
|
||||||
|
keyChar = str[0];
|
||||||
|
auto end = str.find_first_of(keyChar, 1);
|
||||||
|
while((end != std::string::npos) && (str[end - 1] == '\\')) { // deal with escaped quotes
|
||||||
|
end = str.find_first_of(keyChar, end + 1);
|
||||||
|
embeddedQuote = true;
|
||||||
|
}
|
||||||
|
if(end != std::string::npos) {
|
||||||
|
output.push_back(str.substr(1, end - 1));
|
||||||
|
if(end + 2 < str.size()) {
|
||||||
|
str = str.substr(end + 2);
|
||||||
|
} else {
|
||||||
|
str.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
output.push_back(str.substr(1));
|
||||||
|
str = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto it = std::find_if(std::begin(str), std::end(str), find_ws);
|
||||||
|
if(it != std::end(str)) {
|
||||||
|
std::string value = std::string(str.begin(), it);
|
||||||
|
output.push_back(value);
|
||||||
|
str = std::string(it + 1, str.end());
|
||||||
|
} else {
|
||||||
|
output.push_back(str);
|
||||||
|
str = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// transform any embedded quotes into the regular character
|
||||||
|
if(embeddedQuote) {
|
||||||
|
output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar));
|
||||||
|
embeddedQuote = false;
|
||||||
|
}
|
||||||
|
trim(str);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) {
|
||||||
|
auto next = str[offset + 1];
|
||||||
|
if((next == '\"') || (next == '\'') || (next == '`')) {
|
||||||
|
auto astart = str.find_last_of("-/ \"\'`", offset - 1);
|
||||||
|
if(astart != std::string::npos) {
|
||||||
|
if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
|
||||||
|
str[offset] = ' '; // interpret this as a space so the split_up works properly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI11_INLINE std::string &add_quotes_if_needed(std::string &str) {
|
||||||
|
if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) {
|
||||||
|
char quote = str.find('"') < str.find('\'') ? '\'' : '"';
|
||||||
|
if(str.find(' ') != std::string::npos) {
|
||||||
|
str.insert(0, 1, quote);
|
||||||
|
str.append(1, quote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
// [CLI11:string_tools_inl_hpp:end]
|
||||||
|
} // namespace CLI
|
7
src/StringTools.cpp
Normal file
7
src/StringTools.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Copyright (c) 2017-2022, 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
|
||||||
|
|
||||||
|
#include <CLI/impl/StringTools_inl.hpp>
|
Loading…
x
Reference in New Issue
Block a user