32 #include <boost/algorithm/string.hpp> 35 #define ERR_GENERAL LOG_STREAM(err, lg::general()) 36 #define ERR_NG LOG_STREAM(err, log_engine) 42 return c ==
'\r' || c ==
'\n';
50 if (static_cast<unsigned char>(c) >= 128)
52 return isnewline(c) || isspace(static_cast<unsigned char>(c));
64 s.remove_prefix(std::min(s.find_first_not_of(
" \t\r\n"), s.size()));
69 size_t first_to_trim = s.find_last_not_of(
" \t\r\n") + 1;
70 s = s.substr(0, first_to_trim);
82 std::vector<std::string>
split(std::string_view
s,
const char sep,
const int flags)
84 std::vector<std::string> res;
86 res.emplace_back(item);
91 std::set<std::string>
split_set(std::string_view
s,
char sep,
const int flags)
93 std::set<std::string> res;
101 const char separator,
const std::string&
left,
102 const std::string&
right,
const int flags)
104 std::vector< std::string > res;
105 std::vector<char> part;
106 bool in_parenthesis =
false;
107 std::vector<std::string::const_iterator> square_left;
108 std::vector<std::string::const_iterator> square_right;
109 std::vector< std::string > square_expansion;
112 std::string rp=
right;
114 std::string::const_iterator i1 = val.begin();
115 std::string::const_iterator i2;
116 std::string::const_iterator j1;
124 if (i1 == val.end())
return res;
127 ERR_GENERAL <<
"Separator must be specified for square bracket split function." << std::endl;
131 if(left.size()!=right.size()){
132 ERR_GENERAL <<
"Left and Right Parenthesis lists not same length" << std::endl;
137 if(i2 == val.end() || (!in_parenthesis && *i2 == separator)) {
139 std::size_t size_square_exp = 0;
140 for (std::size_t
i=0;
i < square_left.size();
i++) {
141 std::string tmp_val(square_left[
i]+1,square_right[
i]);
142 std::vector< std::string > tmp =
split(tmp_val);
143 for(
const std::string& piece : tmp) {
144 std::size_t found_tilde = piece.find_first_of(
'~');
145 if (found_tilde == std::string::npos) {
146 std::size_t found_asterisk = piece.find_first_of(
'*');
147 if (found_asterisk == std::string::npos) {
148 std::string tmp2(piece);
150 square_expansion.push_back(tmp2);
153 std::string s_begin = piece.substr(0,found_asterisk);
155 std::string s_end = piece.substr(found_asterisk+1);
157 for (
int ast=std::stoi(s_end); ast>0; --ast)
158 square_expansion.push_back(s_begin);
162 std::string s_begin = piece.substr(0,found_tilde);
164 int begin = std::stoi(s_begin);
165 std::size_t padding = 0, padding_end = 0;
166 while (padding<s_begin.size() && s_begin[padding]==
'0') {
169 std::string s_end = piece.substr(found_tilde+1);
171 int end = std::stoi(s_end);
172 while (padding_end<s_end.size() && s_end[padding_end]==
'0') {
175 if (padding*padding_end > 0 && s_begin.size() != s_end.size()) {
176 ERR_GENERAL <<
"Square bracket padding sizes not matching: " 177 << s_begin <<
" and " << s_end <<
".\n";
179 if (padding_end > padding) padding = padding_end;
181 int increment = (end >= begin ? 1 : -1);
183 for (
int k=begin; k!=end; k+=increment) {
184 std::string pb = std::to_string(k);
185 for (std::size_t
p=pb.size();
p<=padding;
p++)
186 pb = std::string(
"0") + pb;
187 square_expansion.push_back(pb);
191 if (i*square_expansion.size() != (i+1)*size_square_exp ) {
192 std::string tmp2(i1, i2);
193 ERR_GENERAL <<
"Square bracket lengths do not match up: " << tmp2 << std::endl;
196 size_square_exp = square_expansion.size();
201 std::size_t j_max = 0;
202 if (!square_left.empty())
203 j_max = square_expansion.size() / square_left.size();
207 for (std::size_t
i=0;
i < square_left.size();
i++) {
208 std::string tmp_val(j1, square_left[
i]);
209 new_val.append(tmp_val);
210 std::size_t k = j+i*j_max;
211 if (k < square_expansion.size())
212 new_val.append(square_expansion[k]);
213 j1 = square_right[
i]+1;
215 std::string tmp_val(j1, i2);
216 new_val.append(tmp_val);
217 if (flags & STRIP_SPACES)
218 boost::trim_right(new_val);
220 res.push_back(new_val);
227 if (flags & STRIP_SPACES) {
233 square_right.clear();
234 square_expansion.clear();
237 if(!part.empty() && *i2 == part.back()) {
239 if (*i2 ==
']') square_right.push_back(i2);
241 in_parenthesis =
false;
246 for(std::size_t
i=0;
i < lp.size();
i++) {
249 square_left.push_back(i2);
251 part.push_back(rp[i]);
259 in_parenthesis =
true;
263 ERR_GENERAL <<
"Mismatched parenthesis:\n"<<val<< std::endl;
270 const std::string& val
274 ,
const std::string& default_value)
277 std::vector< std::string > v =
split(val, major, flags);
280 std::map< std::string, std::string > res;
283 std::size_t pos =
i->find_first_of(minor);
284 std::string key, value;
286 if(pos == std::string::npos) {
288 value = default_value;
290 key =
i->substr(0, pos);
291 value =
i->substr(pos + 1);
301 const char separator,
const std::string&
left,
302 const std::string&
right,
const int flags)
304 std::vector< std::string > res;
305 std::vector<char> part;
306 bool in_parenthesis =
false;
309 std::string rp=
right;
311 std::string::const_iterator i1 = val.begin();
312 std::string::const_iterator i2;
319 if(left.size()!=right.size()){
320 ERR_GENERAL <<
"Left and Right Parenthesis lists not same length" << std::endl;
324 while (i2 != val.end()) {
325 if(!in_parenthesis && separator && *i2 == separator){
326 std::string new_val(i1, i2);
327 if (flags & STRIP_SPACES)
328 boost::trim_right(new_val);
330 res.push_back(new_val);
332 if (flags & STRIP_SPACES) {
339 if(!part.empty() && *i2 == part.back()){
341 if(!separator && part.empty()){
342 std::string new_val(i1, i2);
343 if (flags & STRIP_SPACES)
345 res.push_back(new_val);
350 in_parenthesis =
false;
356 for(std::size_t
i=0;
i < lp.size();
i++){
358 if (!separator && part.empty()){
359 std::string new_val(i1, i2);
360 if (flags & STRIP_SPACES)
362 res.push_back(new_val);
368 part.push_back(rp[i]);
376 in_parenthesis =
true;
379 std::string new_val(i1, i2);
380 if (flags & STRIP_SPACES)
383 res.push_back(std::move(new_val));
386 ERR_GENERAL <<
"Mismatched parenthesis:\n"<<val<< std::endl;
393 int apply_modifier(
const int number,
const std::string &amount,
const int minimum ) {
397 value = std::stoi(amount);
398 }
catch(
const std::invalid_argument&) {}
399 if(amount[amount.size()-1] ==
'%') {
403 if (( minimum > 0 ) && ( value < minimum ))
408 std::string
escape(
const std::string &str,
const char *special_chars)
410 std::string::size_type pos = str.find_first_of(special_chars);
411 if (pos == std::string::npos) {
415 std::string res = str;
417 res.insert(pos, 1,
'\\');
418 pos = res.find_first_of(special_chars, pos + 2);
419 }
while (pos != std::string::npos);
425 std::string::size_type pos = str.find(
'\\');
426 if (pos == std::string::npos) {
430 std::string res = str;
433 pos = res.find(
'\\', pos + 1);
434 }
while (pos != std::string::npos);
440 static const std::string nonresv_str =
443 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 445 "abcdefghijklmnopqrstuvwxyz" 447 static const std::set<char> nonresv(nonresv_str.begin(), nonresv_str.end());
449 std::ostringstream res;
454 if(nonresv.count(
c) != 0) {
461 res << static_cast<int>(
c);
468 if (str.empty())
return def;
471 if (str ==
"yes")
return true;
472 if (str ==
"no"|| str ==
"false" || str ==
"off" || str ==
"0" || str ==
"0.0")
481 std::ostringstream ss;
482 ss << std::boolalpha << value;
489 std::ostringstream oss;
496 std::ostringstream oss;
499 oss << std::abs(val);
504 std::streamsize oldprec = ss.precision();
516 input = std::round(input);
522 if (input >= 999.5) {
529 ss.precision(oldprec);
533 const double multiplier = base2 ? 1024 : 1000;
535 typedef std::array<std::string, 9> strings9;
542 strings9::const_iterator prefix;
544 strings9 tmp { {
"",
"",
"",
"",
"",
"",
"",
"",
"" } };
546 prefix = prefixes.begin();
547 }
else if (input < 1.0) {
560 prefix = prefixes.begin();
561 while (input < 1.0 && *prefix != prefixes.back()) {
582 prefix = prefixes.begin();
583 while (input > multiplier && *prefix != prefixes.back()) {
589 std::stringstream ss;
594 << (base2 && (!(*prefix).empty()) ?
_(
"infix_binary^i") :
"")
600 return ((c ==
'_') || (c ==
'-'));
604 return ((c ==
'?') || (c ==
'*'));
608 const std::size_t alnum = std::count_if(username.begin(), username.end(), isalnum);
609 const std::size_t valid_char =
611 if ((alnum + valid_char != username.size())
612 || valid_char == username.size() || username.empty() )
620 const std::size_t alnum = std::count_if(username.begin(), username.end(), isalnum);
621 const std::size_t valid_char =
623 const std::size_t wild_char =
625 if ((alnum + valid_char + wild_char != username.size())
626 || valid_char == username.size() || username.empty() )
635 std::vector<std::string> matches;
636 const std::size_t last_space = text.rfind(
" ");
638 if (last_space == text.size() -1) {
644 std::string semiword;
645 if (last_space == std::string::npos) {
650 semiword.assign(text, last_space + 1, text.size());
653 std::string best_match = semiword;
654 for (std::vector<std::string>::const_iterator word = wordlist.begin();
655 word != wordlist.end(); ++word)
657 if (word->size() < semiword.size()
658 || !std::equal(semiword.begin(), semiword.end(), word->begin(),
663 if (matches.empty()) {
667 while (toupper(best_match[j]) == toupper((*word)[j])) j++;
668 if (best_match.begin() + j < best_match.end()) {
669 best_match.erase(best_match.begin() + j, best_match.end());
672 matches.push_back(*word);
674 if(!matches.empty()) {
675 text.replace(last_space + 1, best_match.size(), best_match);
682 return (c ==
' ' || c ==
',' || c ==
':' || c ==
'\'' || c ==
'"' || c ==
'-');
685 bool word_match(
const std::string& message,
const std::string& word) {
686 std::size_t first = message.find(word);
687 if (first == std::string::npos)
return false;
689 std::size_t
next = first + word.size();
698 const bool wild_matching = (!match.empty() && (match[0] ==
'*' || match[0] ==
'+'));
699 const std::string::size_type solid_begin = match.find_first_not_of(
"*+");
700 const bool have_solids = (solid_begin != std::string::npos);
703 const std::string::size_type plus_count = std::count(match.begin(), match.end(),
'+');
704 return match.empty() ? str.empty() : str.length() >= plus_count;
705 }
else if(str.empty()) {
709 const std::string::size_type solid_end = match.find_first_of(
"*+", solid_begin);
710 const std::string::size_type solid_len = (solid_end == std::string::npos)
711 ? match.length() - solid_begin : solid_end - solid_begin;
714 std::string::size_type current = match[0] ==
'+' ? 1 : 0;
719 const std::string::size_type test_len = str.length() - current;
720 for(std::string::size_type
i=0;
i < solid_len && matches; ++
i) {
721 char solid_c = match[solid_begin +
i];
722 if(
i > test_len || !(solid_c ==
'?' || solid_c == str[current+
i])) {
728 const std::string consumed_match = (solid_begin+solid_len < match.length())
729 ? match.substr(solid_end) :
"";
730 const std::string consumed_str = (solid_len < test_len)
731 ? str.substr(current+solid_len) :
"";
734 }
while(wild_matching && !matches && ++current < str.length());
738 std::string
indent(
const std::string&
string, std::size_t indent_size)
740 if(indent_size == 0) {
744 const std::string
indent(indent_size,
' ');
750 const std::vector<std::string>& lines =
split(
string,
'\x0A', 0);
753 for(std::size_t lno = 0; lno < lines.size();) {
754 const std::string& line = lines[lno];
757 if(!line.empty() && line !=
"\x0D") {
763 if(++lno < lines.size()) {
773 std::vector<std::string> res;
775 std::string::const_iterator i1 = val.begin();
776 std::string::const_iterator i2 = val.begin();
778 while (i2 != val.end()) {
782 if (i2 != val.end()) ++i2;
783 }
else if (*i2 == c) {
784 std::string new_val(i1, i2);
788 res.push_back(std::move(new_val));
790 if (flags & STRIP_SPACES) {
791 while(i2 != val.end() && *i2 ==
' ')
801 std::string new_val(i1, i2);
805 res.push_back(new_val);
812 const std::string::const_iterator dash = std::find(str.begin(), str.end(),
'-');
813 const std::string
a(str.begin(), dash);
814 const std::string
b = dash != str.end() ? std::string(dash + 1, str.end()) :
a;
815 std::pair<int,int> res {0,0};
817 if (b ==
"infinity") {
818 res = std::pair(std::stoi(
a), std::numeric_limits<int>::max());
820 res = std::pair(std::stoi(
a), std::stoi(b));
823 if (res.second < res.first) {
824 res.second = res.first;
826 }
catch(
const std::invalid_argument&) {
827 ERR_GENERAL <<
"Invalid range: "<< str << std::endl;
835 std::vector<std::pair<int, int>> to_return;
845 const std::size_t prev_size = str.length();
849 if(str.length() != prev_size) {
bool isvalid_wildcard(const std::string &username)
Check if the username pattern contains only valid characters.
std::pair< int, int > parse_range(const std::string &str)
std::string urlencode(const std::string &str)
Percent-escape characters in a UTF-8 string intended to be part of a URL.
bool isvalid_username(const std::string &username)
Check if the username contains only valid characters.
This class represents a single unit of a specific type.
std::set< std::string > split_set(std::string_view s, char sep, const int flags)
REMOVE_EMPTY: remove empty elements.
std::string unescape(const std::string &str)
Remove all escape characters (backslash)
bool wildcard_string_match(const std::string &str, const std::string &match)
Match using '*' as any number of characters (including none), '+' as one or more characters, and '?' as any one character.
void ellipsis_truncate(std::string &str, const std::size_t size)
Truncates a string to a given utf-8 character count and then appends an ellipsis. ...
bool chars_equal_insensitive(char a, char b)
bool notspace(const char c)
static bool is_username_char(char c)
std::map< std::string, std::string > map_split(const std::string &val, char major, char minor, int flags, const std::string &default_value)
Splits a string based on two separators into a map.
static std::string _(const char *str)
std::string quote(const std::string &str)
Surround the string 'str' with double quotes.
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
int div100rounded(int num)
Guarantees portable results for division by 100; round half up, to the nearest integer.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
const std::string unicode_minus
std::vector< std::pair< int, int > > parse_ranges(const std::string &str)
const std::string ellipsis
std::string si_string(double input, bool base2, const std::string &unit)
Convert into a string with an SI-postfix.
static bool is_wildcard_char(char c)
std::string & truncate(std::string &str, const std::size_t size)
Truncates a UTF-8 string to the specified number of characters.
std::string escape(const std::string &str, const char *special_chars)
Prepends a configurable set of characters with a backslash.
static map_location::DIRECTION s
std::vector< std::string > quoted_split(const std::string &val, char c, int flags, char quote)
This function is identical to split(), except it does not split when it otherwise would if the previo...
std::string bool_string(const bool value)
Converts a bool value to 'true' or 'false'.
bool string_bool(const std::string &str, bool def)
Convert no, false, off, 0, 0.0 to false, empty to def, and others to true.
bool isnewline(const char c)
void split_foreach(std::string_view s, char sep, const int flags, const F &f)
static lg::log_domain log_engine("engine")
std::vector< std::string > split(const config_attribute_value &val)
int apply_modifier(const int number, const std::string &amount, const int minimum)
static bool is_word_boundary(char c)
std::string indent(const std::string &string, std::size_t indent_size)
Indent a block of text.
Standard logging facilities (interface).
static const char * match(MatchState *ms, const char *s, const char *p)
void trim(std::string_view &s)
bool portable_isspace(const char c)
std::string signed_value(int val)
Convert into a signed value (using the Unicode "−" and +0 convention.
std::string::const_iterator iterator
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of 'text' with the 'wordlist'.
std::vector< std::string > square_parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Similar to parenthetical_split, but also expands embedded square brackets.
std::pair< std::string, unsigned > item
static void si_string_impl_stream_write(std::stringstream &ss, double input)
bool word_match(const std::string &message, const std::string &word)
Check if a message contains a word.
std::vector< std::string > parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Splits a string based either on a separator, except then the text appears within specified parenthesi...