File indexing completed on 2024-09-28 07:02:18
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010 #include <algorithm>
0011 #include <iomanip>
0012 #include <locale>
0013 #include <sstream>
0014 #include <stdexcept>
0015 #include <string>
0016 #include <type_traits>
0017 #include <vector>
0018
0019
0020 namespace CLI {
0021
0022
0023
0024
0025
0026 namespace enums {
0027
0028
0029 template <typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
0030 std::ostream &operator<<(std::ostream &in, const T &item) {
0031
0032 return in << static_cast<typename std::underlying_type<T>::type>(item);
0033 }
0034
0035 }
0036
0037
0038 using enums::operator<<;
0039
0040 namespace detail {
0041
0042
0043 constexpr int expected_max_vector_size{1 << 29};
0044
0045
0046 inline std::vector<std::string> split(const std::string &s, char delim) {
0047 std::vector<std::string> elems;
0048
0049 if(s.empty()) {
0050 elems.emplace_back();
0051 } else {
0052 std::stringstream ss;
0053 ss.str(s);
0054 std::string item;
0055 while(std::getline(ss, item, delim)) {
0056 elems.push_back(item);
0057 }
0058 }
0059 return elems;
0060 }
0061
0062
0063 template <typename T> std::string join(const T &v, std::string delim = ",") {
0064 std::ostringstream s;
0065 auto beg = std::begin(v);
0066 auto end = std::end(v);
0067 if(beg != end)
0068 s << *beg++;
0069 while(beg != end) {
0070 s << delim << *beg++;
0071 }
0072 return s.str();
0073 }
0074
0075
0076 template <typename T,
0077 typename Callable,
0078 typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
0079 std::string join(const T &v, Callable func, std::string delim = ",") {
0080 std::ostringstream s;
0081 auto beg = std::begin(v);
0082 auto end = std::end(v);
0083 auto loc = s.tellp();
0084 while(beg != end) {
0085 auto nloc = s.tellp();
0086 if(nloc > loc) {
0087 s << delim;
0088 loc = nloc;
0089 }
0090 s << func(*beg++);
0091 }
0092 return s.str();
0093 }
0094
0095
0096 template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
0097 std::ostringstream s;
0098 for(std::size_t start = 0; start < v.size(); start++) {
0099 if(start > 0)
0100 s << delim;
0101 s << v[v.size() - start - 1];
0102 }
0103 return s.str();
0104 }
0105
0106
0107
0108
0109 inline std::string <rim(std::string &str) {
0110 auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
0111 str.erase(str.begin(), it);
0112 return str;
0113 }
0114
0115
0116 inline std::string <rim(std::string &str, const std::string &filter) {
0117 auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
0118 str.erase(str.begin(), it);
0119 return str;
0120 }
0121
0122
0123 inline std::string &rtrim(std::string &str) {
0124 auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace<char>(ch, std::locale()); });
0125 str.erase(it.base(), str.end());
0126 return str;
0127 }
0128
0129
0130 inline std::string &rtrim(std::string &str, const std::string &filter) {
0131 auto it =
0132 std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; });
0133 str.erase(it.base(), str.end());
0134 return str;
0135 }
0136
0137
0138 inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); }
0139
0140
0141 inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); }
0142
0143
0144 inline std::string trim_copy(const std::string &str) {
0145 std::string s = str;
0146 return trim(s);
0147 }
0148
0149
0150 inline std::string &remove_quotes(std::string &str) {
0151 if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) {
0152 if(str.front() == str.back()) {
0153 str.pop_back();
0154 str.erase(str.begin(), str.begin() + 1);
0155 }
0156 }
0157 return str;
0158 }
0159
0160
0161 inline std::string trim_copy(const std::string &str, const std::string &filter) {
0162 std::string s = str;
0163 return trim(s, filter);
0164 }
0165
0166 inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) {
0167 name = " " + name;
0168 out << std::setw(static_cast<int>(wid)) << std::left << name;
0169 if(!description.empty()) {
0170 if(name.length() >= wid)
0171 out << "\n" << std::setw(static_cast<int>(wid)) << "";
0172 for(const char c : description) {
0173 out.put(c);
0174 if(c == '\n') {
0175 out << std::setw(static_cast<int>(wid)) << "";
0176 }
0177 }
0178 }
0179 out << "\n";
0180 return out;
0181 }
0182
0183
0184 inline std::ostream &format_aliases(std::ostream &out, const std::vector<std::string> &aliases, std::size_t wid) {
0185 if(!aliases.empty()) {
0186 out << std::setw(static_cast<int>(wid)) << " aliases: ";
0187 bool front = true;
0188 for(const auto &alias : aliases) {
0189 if(!front) {
0190 out << ", ";
0191 } else {
0192 front = false;
0193 }
0194 out << alias;
0195 }
0196 out << "\n";
0197 }
0198 return out;
0199 }
0200
0201
0202 template <typename T> bool valid_first_char(T c) {
0203 return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@';
0204 }
0205
0206
0207 template <typename T> bool valid_later_char(T c) { return valid_first_char(c) || c == '.' || c == '-'; }
0208
0209
0210 inline bool valid_name_string(const std::string &str) {
0211 if(str.empty() || !valid_first_char(str[0]))
0212 return false;
0213 for(auto c : str.substr(1))
0214 if(!valid_later_char(c))
0215 return false;
0216 return true;
0217 }
0218
0219
0220 inline bool is_separator(const std::string &str) {
0221 static const std::string sep("%%");
0222 return (str.empty() || str == sep);
0223 }
0224
0225
0226 inline bool isalpha(const std::string &str) {
0227 return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); });
0228 }
0229
0230
0231 inline std::string to_lower(std::string str) {
0232 std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) {
0233 return std::tolower(x, std::locale());
0234 });
0235 return str;
0236 }
0237
0238
0239 inline std::string remove_underscore(std::string str) {
0240 str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str));
0241 return str;
0242 }
0243
0244
0245 inline std::string find_and_replace(std::string str, std::string from, std::string to) {
0246
0247 std::size_t start_pos = 0;
0248
0249 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
0250 str.replace(start_pos, from.length(), to);
0251 start_pos += to.length();
0252 }
0253
0254 return str;
0255 }
0256
0257
0258 inline bool has_default_flag_values(const std::string &flags) {
0259 return (flags.find_first_of("{!") != std::string::npos);
0260 }
0261
0262 inline void remove_default_flag_values(std::string &flags) {
0263 auto loc = flags.find_first_of('{');
0264 while(loc != std::string::npos) {
0265 auto finish = flags.find_first_of("},", loc + 1);
0266 if((finish != std::string::npos) && (flags[finish] == '}')) {
0267 flags.erase(flags.begin() + static_cast<std::ptrdiff_t>(loc),
0268 flags.begin() + static_cast<std::ptrdiff_t>(finish) + 1);
0269 }
0270 loc = flags.find_first_of('{', loc + 1);
0271 }
0272 flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end());
0273 }
0274
0275
0276 inline std::ptrdiff_t find_member(std::string name,
0277 const std::vector<std::string> names,
0278 bool ignore_case = false,
0279 bool ignore_underscore = false) {
0280 auto it = std::end(names);
0281 if(ignore_case) {
0282 if(ignore_underscore) {
0283 name = detail::to_lower(detail::remove_underscore(name));
0284 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0285 return detail::to_lower(detail::remove_underscore(local_name)) == name;
0286 });
0287 } else {
0288 name = detail::to_lower(name);
0289 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0290 return detail::to_lower(local_name) == name;
0291 });
0292 }
0293
0294 } else if(ignore_underscore) {
0295 name = detail::remove_underscore(name);
0296 it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) {
0297 return detail::remove_underscore(local_name) == name;
0298 });
0299 } else {
0300 it = std::find(std::begin(names), std::end(names), name);
0301 }
0302
0303 return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
0304 }
0305
0306
0307
0308 template <typename Callable> inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) {
0309 std::size_t start_pos = 0;
0310 while((start_pos = str.find(trigger, start_pos)) != std::string::npos) {
0311 start_pos = modify(str, start_pos);
0312 }
0313 return str;
0314 }
0315
0316
0317
0318 inline std::vector<std::string> split_up(std::string str, char delimiter = '\0') {
0319
0320 const std::string delims("\'\"`");
0321 auto find_ws = [delimiter](char ch) {
0322 return (delimiter == '\0') ? (std::isspace<char>(ch, std::locale()) != 0) : (ch == delimiter);
0323 };
0324 trim(str);
0325
0326 std::vector<std::string> output;
0327 bool embeddedQuote = false;
0328 char keyChar = ' ';
0329 while(!str.empty()) {
0330 if(delims.find_first_of(str[0]) != std::string::npos) {
0331 keyChar = str[0];
0332 auto end = str.find_first_of(keyChar, 1);
0333 while((end != std::string::npos) && (str[end - 1] == '\\')) {
0334 end = str.find_first_of(keyChar, end + 1);
0335 embeddedQuote = true;
0336 }
0337 if(end != std::string::npos) {
0338 output.push_back(str.substr(1, end - 1));
0339 if(end + 2 < str.size()) {
0340 str = str.substr(end + 2);
0341 } else {
0342 str.clear();
0343 }
0344
0345 } else {
0346 output.push_back(str.substr(1));
0347 str = "";
0348 }
0349 } else {
0350 auto it = std::find_if(std::begin(str), std::end(str), find_ws);
0351 if(it != std::end(str)) {
0352 std::string value = std::string(str.begin(), it);
0353 output.push_back(value);
0354 str = std::string(it + 1, str.end());
0355 } else {
0356 output.push_back(str);
0357 str = "";
0358 }
0359 }
0360
0361 if(embeddedQuote) {
0362 output.back() = find_and_replace(output.back(), std::string("\\") + keyChar, std::string(1, keyChar));
0363 embeddedQuote = false;
0364 }
0365 trim(str);
0366 }
0367 return output;
0368 }
0369
0370
0371
0372
0373
0374 inline std::string fix_newlines(const std::string &leader, std::string input) {
0375 std::string::size_type n = 0;
0376 while(n != std::string::npos && n < input.size()) {
0377 n = input.find('\n', n);
0378 if(n != std::string::npos) {
0379 input = input.substr(0, n + 1) + leader + input.substr(n + 1);
0380 n += leader.size();
0381 }
0382 }
0383 return input;
0384 }
0385
0386
0387
0388
0389
0390 inline std::size_t escape_detect(std::string &str, std::size_t offset) {
0391 auto next = str[offset + 1];
0392 if((next == '\"') || (next == '\'') || (next == '`')) {
0393 auto astart = str.find_last_of("-/ \"\'`", offset - 1);
0394 if(astart != std::string::npos) {
0395 if(str[astart] == ((str[offset] == '=') ? '-' : '/'))
0396 str[offset] = ' ';
0397 }
0398 }
0399 return offset + 1;
0400 }
0401
0402
0403 inline std::string &add_quotes_if_needed(std::string &str) {
0404 if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) {
0405 char quote = str.find('"') < str.find('\'') ? '\'' : '"';
0406 if(str.find(' ') != std::string::npos) {
0407 str.insert(0, 1, quote);
0408 str.append(1, quote);
0409 }
0410 }
0411 return str;
0412 }
0413
0414 }
0415
0416
0417
0418 }