Skip to content

Commit 4048596

Browse files
dherrera-metahenryiii
authored andcommitted
[precompile] Split StringTools.hpp
1 parent d1f0f48 commit 4048596

File tree

4 files changed

+297
-222
lines changed

4 files changed

+297
-222
lines changed

CLI11.hpp.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ namespace {namespace} {{
4646

4747
{string_tools_hpp}
4848

49+
{string_tools_inl_hpp}
50+
4951
{error_hpp}
5052

5153
{type_tools_hpp}

include/CLI/StringTools.hpp

Lines changed: 26 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <vector>
1818
// [CLI11:public_includes:end]
1919

20+
#include "Macros.hpp"
21+
2022
namespace CLI {
2123

2224
// [CLI11:string_tools_hpp:verbatim]
@@ -43,21 +45,7 @@ namespace detail {
4345
constexpr int expected_max_vector_size{1 << 29};
4446
// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
4547
/// 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);
6149

6250
/// Simple function to join a string
6351
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 = ",") {
10694
// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string
10795

10896
/// Trim whitespace from left of string
109-
inline std::string &ltrim(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 &ltrim(std::string &str);
11498

11599
/// Trim anything from left of string
116-
inline std::string &ltrim(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 &ltrim(std::string &str, const std::string &filter);
121101

122102
/// 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);
128104

129105
/// 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);
136107

137108
/// Trim whitespace from string
138109
inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
@@ -147,72 +118,25 @@ inline std::string trim_copy(const std::string &str) {
147118
}
148119

149120
/// 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);
159122

160123
/// Add a leader to the beginning of all new lines (nothing is added
161124
/// at the start of the first line). `"; "` would be for ini files
162125
///
163126
/// 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);
175128

176129
/// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered)
177130
inline std::string trim_copy(const std::string &str, const std::string &filter) {
178131
std::string s = str;
179132
return trim(s, filter);
180133
}
181134
/// 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);
198137

199138
/// 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);
216140

217141
/// Verify the first character of an option
218142
/// - 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) {
227151
}
228152

229153
/// 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);
240155

241156
/// Verify an app name
242157
inline bool valid_alias_name_string(const std::string &str) {
@@ -270,66 +185,20 @@ inline std::string remove_underscore(std::string str) {
270185
}
271186

272187
/// 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);
284189

285190
/// check if the flag definitions has possible false flags
286191
inline bool has_default_flag_values(const std::string &flags) {
287192
return (flags.find_first_of("{!") != std::string::npos);
288193
}
289194

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);
302196

303197
/// 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);
333202

334203
/// Find a trigger string and call a modify callable function that takes the current string and starting position of the
335204
/// 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,
343212

344213
/// Split a string '"one two" "three"' into 'one two', 'three'
345214
/// 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');
397216

398217
/// This function detects an equal or colon followed by an escaped quote after an argument
399218
/// then modifies the string to replace the equality with a space. This is needed
400219
/// to allow the split up function to work properly and is intended to be used with the find_and_modify function
401220
/// 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);
413222

414223
/// 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);
425225

426226
} // namespace detail
427227

428228
// [CLI11:string_tools_hpp:end]
429229

430230
} // namespace CLI
231+
232+
#ifndef CLI11_COMPILE
233+
#include "impl/StringTools_inl.hpp"
234+
#endif

0 commit comments

Comments
 (0)