The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
string_utils.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  Copyright (C) 2005 by Guillaume Melquiond <[email protected]>
4  Copyright (C) 2005 - 2016 by Philippe Plantier <[email protected]>
5  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 /**
18  * @file
19  * Various string-routines.
20  */
21 
22 #include "global.hpp"
23 
24 #include "gettext.hpp"
25 #include "log.hpp"
28 #include "util.hpp"
29 #include <cassert>
30 #include <boost/array.hpp>
31 #include <boost/lexical_cast.hpp>
32 
33 static lg::log_domain log_engine("engine");
34 #define ERR_GENERAL LOG_STREAM(err, lg::general())
35 #define ERR_NG LOG_STREAM(err, log_engine)
36 
37 namespace utils {
38 
39 const std::string ellipsis = "...";
40 
41 const std::string unicode_minus = "−";
47 
48 bool isnewline(const char c)
49 {
50  return c == '\r' || c == '\n';
51 }
52 
53 // Make sure that we can use Mac, DOS, or Unix style text files on any system
54 // and they will work, by making sure the definition of whitespace is consistent
55 bool portable_isspace(const char c)
56 {
57  // returns true only on ASCII spaces
58  if (static_cast<unsigned char>(c) >= 128)
59  return false;
60  return isnewline(c) || isspace(c);
61 }
62 
63 // Make sure we regard '\r' and '\n' as a space, since Mac, Unix, and DOS
64 // all consider these differently.
65 bool notspace(const char c)
66 {
67  return !portable_isspace(c);
68 }
69 
71 {
72  std::string::size_type pos = 0;
73  while ( (pos = str.find(src, pos)) != std::string::npos ) {
74  str.replace( pos, src.size(), dst );
75  pos++;
76  }
77  return str;
78 }
79 
81 {
82  // If all the string contains is whitespace,
83  // then the whitespace may have meaning, so don't strip it
84  std::string::iterator it = std::find_if(str.begin(), str.end(), notspace);
85  if (it == str.end())
86  return str;
87 
88  str.erase(str.begin(), it);
89  str.erase(std::find_if(str.rbegin(), str.rend(), notspace).base(), str.end());
90 
91  return str;
92 }
93 
95 {
96  str.erase(std::find_if(str.rbegin(), str.rend(), notspace).base(), str.end());
97 
98  return str;
99 }
100 
101 /**
102  * Splits a (comma-)separated string into a vector of pieces.
103  * @param[in] val A (comma-)separated string.
104  * @param[in] c The separator character (usually a comma).
105  * @param[in] flags Flags controlling how the split is done.
106  * This is a bit field with two settings (both on by default):
107  * REMOVE_EMPTY causes empty pieces to be skipped/removed.
108  * STRIP_SPACES causes the leading and trailing spaces of each piece to be ignored/stripped.
109  */
110 std::vector< std::string > split(std::string const &val, const char c, const int flags)
111 {
112  std::vector< std::string > res;
113 
114  std::string::const_iterator i1 = val.begin();
115  std::string::const_iterator i2;
116  if (flags & STRIP_SPACES) {
117  while (i1 != val.end() && portable_isspace(*i1))
118  ++i1;
119  }
120  i2=i1;
121 
122  while (i2 != val.end()) {
123  if (*i2 == c) {
124  std::string new_val(i1, i2);
125  if (flags & STRIP_SPACES)
126  strip_end(new_val);
127  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
128  res.push_back(new_val);
129  ++i2;
130  if (flags & STRIP_SPACES) {
131  while (i2 != val.end() && portable_isspace(*i2))
132  ++i2;
133  }
134 
135  i1 = i2;
136  } else {
137  ++i2;
138  }
139  }
140 
141  std::string new_val(i1, i2);
142  if (flags & STRIP_SPACES)
143  strip_end(new_val);
144  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
145  res.push_back(new_val);
146 
147  return res;
148 }
149 
150 std::vector< std::string > square_parenthetical_split(std::string const &val,
151  const char separator, std::string const &left,
152  std::string const &right,const int flags)
153 {
154  std::vector< std::string > res;
155  std::vector<char> part;
156  bool in_parenthesis = false;
157  std::vector<std::string::const_iterator> square_left;
158  std::vector<std::string::const_iterator> square_right;
159  std::vector< std::string > square_expansion;
160 
161  std::string lp=left;
162  std::string rp=right;
163 
164  std::string::const_iterator i1 = val.begin();
165  std::string::const_iterator i2;
166  std::string::const_iterator j1;
167  if (flags & STRIP_SPACES) {
168  while (i1 != val.end() && portable_isspace(*i1))
169  ++i1;
170  }
171  i2=i1;
172  j1=i1;
173 
174  if (i1 == val.end()) return res;
175 
176  if (!separator) {
177  ERR_GENERAL << "Separator must be specified for square bracket split funtion." << std::endl;
178  return res;
179  }
180 
181  if(left.size()!=right.size()){
182  ERR_GENERAL << "Left and Right Parenthesis lists not same length" << std::endl;
183  return res;
184  }
185 
186  while (true) {
187  if(i2 == val.end() || (!in_parenthesis && *i2 == separator)) {
188  //push back square contents
189  size_t size_square_exp = 0;
190  for (size_t i=0; i < square_left.size(); i++) {
191  std::string tmp_val(square_left[i]+1,square_right[i]);
192  std::vector< std::string > tmp = split(tmp_val);
193  std::vector<std::string>::const_iterator itor = tmp.begin();
194  for(; itor != tmp.end(); ++itor) {
195  size_t found_tilde = (*itor).find_first_of('~');
196  if (found_tilde == std::string::npos) {
197  size_t found_asterisk = (*itor).find_first_of('*');
198  if (found_asterisk == std::string::npos) {
199  std::string tmp = (*itor);
200  square_expansion.push_back(strip(tmp));
201  }
202  else { //'*' multiple expansion
203  std::string s_begin = (*itor).substr(0,found_asterisk);
204  s_begin = strip(s_begin);
205  std::string s_end = (*itor).substr(found_asterisk+1);
206  s_end = strip(s_end);
207  for (int ast=std::stoi(s_end); ast>0; --ast)
208  square_expansion.push_back(s_begin);
209  }
210  }
211  else { //expand number range
212  std::string s_begin = (*itor).substr(0,found_tilde);
213  s_begin = strip(s_begin);
214  int begin = std::stoi(s_begin);
215  size_t padding = 0, padding_end = 0;
216  while (padding<s_begin.size() && s_begin[padding]=='0') {
217  padding++;
218  }
219  std::string s_end = (*itor).substr(found_tilde+1);
220  s_end = strip(s_end);
221  int end = std::stoi(s_end);
222  while (padding_end<s_end.size() && s_end[padding_end]=='0') {
223  padding_end++;
224  }
225  if (padding*padding_end > 0 && s_begin.size() != s_end.size()) {
226  ERR_GENERAL << "Square bracket padding sizes not matching: "
227  << s_begin << " and " << s_end <<".\n";
228  }
229  if (padding_end > padding) padding = padding_end;
230 
231  int increment = (end >= begin ? 1 : -1);
232  end+=increment; //include end in expansion
233  for (int k=begin; k!=end; k+=increment) {
234  std::string pb = std::to_string(k);
235  for (size_t p=pb.size(); p<=padding; p++)
236  pb = std::string("0") + pb;
237  square_expansion.push_back(pb);
238  }
239  }
240  }
241  if (i*square_expansion.size() != (i+1)*size_square_exp ) {
242  std::string tmp(i1, i2);
243  ERR_GENERAL << "Square bracket lengths do not match up: "+tmp+"" << std::endl;
244  return res;
245  }
246  size_square_exp = square_expansion.size();
247  }
248 
249  //combine square contents and rest of string for comma zone block
250  size_t j = 0;
251  size_t j_max = 0;
252  if (square_left.size() != 0)
253  j_max = square_expansion.size() / square_left.size();
254  do {
255  j1 = i1;
256  std::string new_val;
257  for (size_t i=0; i < square_left.size(); i++) {
258  std::string tmp_val(j1, square_left[i]);
259  new_val.append(tmp_val);
260  size_t k = j+i*j_max;
261  if (k < square_expansion.size())
262  new_val.append(square_expansion[k]);
263  j1 = square_right[i]+1;
264  }
265  std::string tmp_val(j1, i2);
266  new_val.append(tmp_val);
267  if (flags & STRIP_SPACES)
268  strip_end(new_val);
269  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
270  res.push_back(new_val);
271  j++;
272  } while (j<j_max);
273 
274  if (i2 == val.end()) //escape loop
275  break;
276  ++i2;
277  if (flags & STRIP_SPACES) { //strip leading spaces
278  while (i2 != val.end() && portable_isspace(*i2))
279  ++i2;
280  }
281  i1=i2;
282  square_left.clear();
283  square_right.clear();
284  square_expansion.clear();
285  continue;
286  }
287  if(!part.empty() && *i2 == part.back()) {
288  part.pop_back();
289  if (*i2 == ']') square_right.push_back(i2);
290  if (part.empty())
291  in_parenthesis = false;
292  ++i2;
293  continue;
294  }
295  bool found=false;
296  for(size_t i=0; i < lp.size(); i++) {
297  if (*i2 == lp[i]){
298  if (*i2 == '[')
299  square_left.push_back(i2);
300  ++i2;
301  part.push_back(rp[i]);
302  found=true;
303  break;
304  }
305  }
306  if(!found){
307  ++i2;
308  } else
309  in_parenthesis = true;
310  }
311 
312  if(!part.empty()){
313  ERR_GENERAL << "Mismatched parenthesis:\n"<<val<< std::endl;;
314  }
315 
316  return res;
317 }
318 
319 std::map< std::string, std::string > map_split(
320  std::string const &val
321  , char major
322  , char minor
323  , int flags
324  , std::string const& default_value)
325 {
326  //first split by major so that we get a vector with the key-value pairs
327  std::vector< std::string > v = split(val, major, flags);
328 
329  //now split by minor to extract keys and values
330  std::map< std::string, std::string > res;
331 
332  for( std::vector< std::string >::iterator i = v.begin(); i != v.end(); ++i) {
333  size_t pos = i->find_first_of(minor);
334  std::string key, value;
335 
336  if(pos == std::string::npos) {
337  key = (*i);
338  value = default_value;
339  } else {
340  key = i->substr(0, pos);
341  value = i->substr(pos + 1);
342  }
343 
344  res[key] = value;
345  }
346 
347  return res;
348 }
349 
350 std::vector< std::string > parenthetical_split(std::string const &val,
351  const char separator, std::string const &left,
352  std::string const &right,const int flags)
353 {
354  std::vector< std::string > res;
355  std::vector<char> part;
356  bool in_parenthesis = false;
357 
358  std::string lp=left;
359  std::string rp=right;
360 
361  std::string::const_iterator i1 = val.begin();
362  std::string::const_iterator i2;
363  if (flags & STRIP_SPACES) {
364  while (i1 != val.end() && portable_isspace(*i1))
365  ++i1;
366  }
367  i2=i1;
368 
369  if(left.size()!=right.size()){
370  ERR_GENERAL << "Left and Right Parenthesis lists not same length" << std::endl;
371  return res;
372  }
373 
374  while (i2 != val.end()) {
375  if(!in_parenthesis && separator && *i2 == separator){
376  std::string new_val(i1, i2);
377  if (flags & STRIP_SPACES)
378  strip_end(new_val);
379  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
380  res.push_back(new_val);
381  ++i2;
382  if (flags & STRIP_SPACES) {
383  while (i2 != val.end() && portable_isspace(*i2))
384  ++i2;
385  }
386  i1=i2;
387  continue;
388  }
389  if(!part.empty() && *i2 == part.back()){
390  part.pop_back();
391  if(!separator && part.empty()){
392  std::string new_val(i1, i2);
393  if (flags & STRIP_SPACES)
394  strip(new_val);
395  res.push_back(new_val);
396  ++i2;
397  i1=i2;
398  }else{
399  if (part.empty())
400  in_parenthesis = false;
401  ++i2;
402  }
403  continue;
404  }
405  bool found=false;
406  for(size_t i=0; i < lp.size(); i++){
407  if (*i2 == lp[i]){
408  if (!separator && part.empty()){
409  std::string new_val(i1, i2);
410  if (flags & STRIP_SPACES)
411  strip(new_val);
412  res.push_back(new_val);
413  ++i2;
414  i1=i2;
415  }else{
416  ++i2;
417  }
418  part.push_back(rp[i]);
419  found=true;
420  break;
421  }
422  }
423  if(!found){
424  ++i2;
425  } else
426  in_parenthesis = true;
427  }
428 
429  std::string new_val(i1, i2);
430  if (flags & STRIP_SPACES)
431  strip(new_val);
432  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
433  res.push_back(new_val);
434 
435  if(!part.empty()){
436  ERR_GENERAL << "Mismatched parenthesis:\n"<<val<< std::endl;;
437  }
438 
439  return res;
440 }
441 
442 // Modify a number by string representing integer difference, or optionally %
443 int apply_modifier( const int number, const std::string &amount, const int minimum ) {
444  // wassert( amount.empty() == false );
445  int value = std::stoi(amount);
446  if(amount[amount.size()-1] == '%') {
447  value = div100rounded(number * value);
448  }
449  value += number;
450  if (( minimum > 0 ) && ( value < minimum ))
451  value = minimum;
452  return value;
453 }
454 
455 std::string escape(const std::string &str, const char *special_chars)
456 {
457  std::string::size_type pos = str.find_first_of(special_chars);
458  if (pos == std::string::npos) {
459  // Fast path, possibly involving only reference counting.
460  return str;
461  }
462  std::string res = str;
463  do {
464  res.insert(pos, 1, '\\');
465  pos = res.find_first_of(special_chars, pos + 2);
466  } while (pos != std::string::npos);
467  return res;
468 }
469 
471 {
472  std::string::size_type pos = str.find('\\');
473  if (pos == std::string::npos) {
474  // Fast path, possibly involving only reference counting.
475  return str;
476  }
477  std::string res = str;
478  do {
479  res.erase(pos, 1);
480  pos = res.find('\\', pos + 1);
481  } while (pos != std::string::npos);
482  return str;
483 }
484 
486 {
487  static std::string nonresv =
488  "-."
489  "0123456789"
490  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
491  "_"
492  "abcdefghijklmnopqrstuvwxyz"
493  "~";
494 
496 
497  for(size_t n = 0; n < str.length(); ++n) {
498  const char& c = str[n];
499 
500  if(nonresv.find(c) != std::string::npos) {
501  res += c;
502  continue;
503  }
504 
505  char buf[4];
506  snprintf(buf, sizeof(buf), "%%%02X", c);
507  res += buf;
508  }
509 
510  return res;
511 }
512 
513 bool string_bool(const std::string& str, bool def) {
514  if (str.empty()) return def;
515 
516  // yes/no is the standard, test it first
517  if (str == "yes") return true;
518  if (str == "no"|| str == "false" || str == "off" || str == "0" || str == "0.0")
519  return false;
520 
521  // all other non-empty string are considered as true
522  return true;
523 }
524 
526 {
527  std::ostringstream oss;
528  oss << (val >= 0 ? "+" : unicode_minus) << abs(val);
529  return oss.str();
530 }
531 
533 {
534  std::ostringstream oss;
535  if (val < 0)
536  oss << unicode_minus;
537  oss << abs(val);
538  return oss.str();
539 }
540 
541 static void si_string_impl_stream_write(std::stringstream &ss, double input) {
542  std::streamsize oldprec = ss.precision();
543 #ifdef _MSC_VER
544  // Visual C++ makes 'precision' set the number of decimal places.
545  // Other platforms make it set the number of significant figures
546  ss.precision(1);
547  ss << std::fixed
548  << input;
549 #else
550  // Workaround to display 1023 KiB instead of 1.02e3 KiB
551  if (input >= 1000)
552  ss.precision(4);
553  else
554  ss.precision(3);
555  ss << input;
556 #endif
557  ss.precision(oldprec);
558 }
559 
561  const double multiplier = base2 ? 1024 : 1000;
562 
563  typedef boost::array<std::string, 9> strings9;
564 
565  strings9 prefixes;
566  strings9::const_iterator prefix;
567  if (input == 0.0) {
568  strings9 tmp = { { "","","","","","","","","" } };
569  prefixes = tmp;
570  prefix = prefixes.begin();
571  } else if (input < 1.0) {
572  strings9 tmp = { {
573  "",
574  _("prefix_milli^m"),
575  _("prefix_micro^µ"),
576  _("prefix_nano^n"),
577  _("prefix_pico^p"),
578  _("prefix_femto^f"),
579  _("prefix_atto^a"),
580  _("prefix_zepto^z"),
581  _("prefix_yocto^y")
582  } };
583  prefixes = tmp;
584  prefix = prefixes.begin();
585  while (input < 1.0 && *prefix != prefixes.back()) {
586  input *= multiplier;
587  ++prefix;
588  }
589  } else {
590  strings9 tmp = { {
591  "",
592  (base2 ?
593  _("prefix_kibi^K") :
594  _("prefix_kilo^k")
595  ),
596  _("prefix_mega^M"),
597  _("prefix_giga^G"),
598  _("prefix_tera^T"),
599  _("prefix_peta^P"),
600  _("prefix_exa^E"),
601  _("prefix_zetta^Z"),
602  _("prefix_yotta^Y")
603  } };
604  prefixes = tmp;
605  prefix = prefixes.begin();
606  while (input > multiplier && *prefix != prefixes.back()) {
607  input /= multiplier;
608  ++prefix;
609  }
610  }
611 
612  std::stringstream ss;
613  si_string_impl_stream_write(ss, input);
614  ss << ' '
615  << *prefix
616  << (base2 && (*prefix != "") ? _("infix_binary^i") : "")
617  << unit;
618  return ss.str();
619 }
620 
621 static bool is_username_char(char c) {
622  return ((c == '_') || (c == '-'));
623 }
624 
625 static bool is_wildcard_char(char c) {
626  return ((c == '?') || (c == '*'));
627 }
628 
629 bool isvalid_username(const std::string& username) {
630  const size_t alnum = std::count_if(username.begin(), username.end(), isalnum);
631  const size_t valid_char =
632  std::count_if(username.begin(), username.end(), is_username_char);
633  if ((alnum + valid_char != username.size())
634  || valid_char == username.size() || username.empty() )
635  {
636  return false;
637  }
638  return true;
639 }
640 
641 bool isvalid_wildcard(const std::string& username) {
642  const size_t alnum = std::count_if(username.begin(), username.end(), isalnum);
643  const size_t valid_char =
644  std::count_if(username.begin(), username.end(), is_username_char);
645  const size_t wild_char =
646  std::count_if(username.begin(), username.end(), is_wildcard_char);
647  if ((alnum + valid_char + wild_char != username.size())
648  || valid_char == username.size() || username.empty() )
649  {
650  return false;
651  }
652  return true;
653 }
654 
655 
656 bool word_completion(std::string& text, std::vector<std::string>& wordlist) {
657  std::vector<std::string> matches;
658  const size_t last_space = text.rfind(" ");
659  // If last character is a space return.
660  if (last_space == text.size() -1) {
661  wordlist = matches;
662  return false;
663  }
664 
665  bool text_start;
666  std::string semiword;
667  if (last_space == std::string::npos) {
668  text_start = true;
669  semiword = text;
670  } else {
671  text_start = false;
672  semiword.assign(text, last_space + 1, text.size());
673  }
674 
675  std::string best_match = semiword;
676  for (std::vector<std::string>::const_iterator word = wordlist.begin();
677  word != wordlist.end(); ++word)
678  {
679  if (word->size() < semiword.size()
680  || !std::equal(semiword.begin(), semiword.end(), word->begin(),
682  {
683  continue;
684  }
685  if (matches.empty()) {
686  best_match = *word;
687  } else {
688  int j = 0;
689  while (toupper(best_match[j]) == toupper((*word)[j])) j++;
690  if (best_match.begin() + j < best_match.end()) {
691  best_match.erase(best_match.begin() + j, best_match.end());
692  }
693  }
694  matches.push_back(*word);
695  }
696  if(!matches.empty()) {
697  text.replace(last_space + 1, best_match.size(), best_match);
698  }
699  wordlist = matches;
700  return text_start;
701 }
702 
703 static bool is_word_boundary(char c) {
704  return (c == ' ' || c == ',' || c == ':' || c == '\'' || c == '"' || c == '-');
705 }
706 
707 bool word_match(const std::string& message, const std::string& word) {
708  size_t first = message.find(word);
709  if (first == std::string::npos) return false;
710  if (first == 0 || is_word_boundary(message[first - 1])) {
711  size_t next = first + word.size();
712  if (next == message.size() || is_word_boundary(message[next])) {
713  return true;
714  }
715  }
716  return false;
717 }
718 
720  const bool wild_matching = (!match.empty() && match[0] == '*');
721  const std::string::size_type solid_begin = match.find_first_not_of('*');
722  const bool have_solids = (solid_begin != std::string::npos);
723  // Check the simple case first
724  if(str.empty() || !have_solids) {
725  return wild_matching || str == match;
726  }
727  const std::string::size_type solid_end = match.find_first_of('*', solid_begin);
728  const std::string::size_type solid_len = (solid_end == std::string::npos)
729  ? match.length() - solid_begin : solid_end - solid_begin;
730  std::string::size_type current = 0;
731  bool matches;
732  do {
733  matches = true;
734  // Now try to place the str into the solid space
735  const std::string::size_type test_len = str.length() - current;
736  for(std::string::size_type i=0; i < solid_len && matches; ++i) {
737  char solid_c = match[solid_begin + i];
738  if(i > test_len || !(solid_c == '?' || solid_c == str[current+i])) {
739  matches = false;
740  }
741  }
742  if(matches) {
743  // The solid space matched, now consume it and attempt to find more
744  const std::string consumed_match = (solid_begin+solid_len < match.length())
745  ? match.substr(solid_end) : "";
746  const std::string consumed_str = (solid_len < test_len)
747  ? str.substr(current+solid_len) : "";
748  matches = wildcard_string_match(consumed_str, consumed_match);
749  }
750  } while(wild_matching && !matches && ++current < str.length());
751  return matches;
752 }
753 
754 std::string indent(const std::string& string, size_t indent_size)
755 {
756  if(indent_size == 0) {
757  return string;
758  }
759 
760  const std::string indent(indent_size, ' ');
761 
762  if(string.empty()) {
763  return indent;
764  }
765 
766  const std::vector<std::string>& lines = split(string, '\x0A', 0);
768 
769  for(size_t lno = 0; lno < lines.size();) {
770  const std::string& line = lines[lno];
771 
772  // Lines containing only a carriage return count as empty.
773  if(!line.empty() && line != "\x0D") {
774  res += indent;
775  }
776 
777  res += line;
778 
779  if(++lno < lines.size()) {
780  res += '\x0A';
781  }
782  }
783 
784  return res;
785 }
786 
787 std::vector< std::string > quoted_split(std::string const &val, char c, int flags, char quote)
788 {
789  std::vector<std::string> res;
790 
791  std::string::const_iterator i1 = val.begin();
792  std::string::const_iterator i2 = val.begin();
793 
794  while (i2 != val.end()) {
795  if (*i2 == quote) {
796  // Ignore quoted character
797  ++i2;
798  if (i2 != val.end()) ++i2;
799  } else if (*i2 == c) {
800  std::string new_val(i1, i2);
801  if (flags & STRIP_SPACES)
802  strip(new_val);
803  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
804  res.push_back(new_val);
805  ++i2;
806  if (flags & STRIP_SPACES) {
807  while(i2 != val.end() && *i2 == ' ')
808  ++i2;
809  }
810 
811  i1 = i2;
812  } else {
813  ++i2;
814  }
815  }
816 
817  std::string new_val(i1, i2);
818  if (flags & STRIP_SPACES)
819  strip(new_val);
820  if (!(flags & REMOVE_EMPTY) || !new_val.empty())
821  res.push_back(new_val);
822 
823  return res;
824 }
825 
826 std::pair< int, int > parse_range(std::string const &str)
827 {
828  const std::string::const_iterator dash = std::find(str.begin(), str.end(), '-');
829  const std::string a(str.begin(), dash);
830  const std::string b = dash != str.end() ? std::string(dash + 1, str.end()) : a;
831  std::pair<int,int> res(std::stoi(a), std::stoi(b));
832  if (res.second < res.first)
833  res.second = res.first;
834 
835  return res;
836 }
837 
838 std::vector< std::pair< int, int > > parse_ranges(std::string const &str)
839 {
840  std::vector< std::pair< int, int > > to_return;
841  std::vector<std::string> strs = utils::split(str);
842  std::vector<std::string>::const_iterator i, i_end=strs.end();
843  for(i = strs.begin(); i != i_end; ++i) {
844  to_return.push_back(parse_range(*i));
845  }
846  return to_return;
847 }
848 
849 
850 void ellipsis_truncate(std::string& str, const size_t size)
851 {
852  const size_t prev_size = str.length();
853 
854  utf8::truncate(str, size);
855 
856  if(str.length() != prev_size) {
857  str += ellipsis;
858  }
859 }
860 
861 } // end namespace utils
std::string si_string(double input, bool base2, std::string unit)
Convert into a string with an SI-postfix.
bool isvalid_wildcard(const std::string &username)
Check if the username pattern contains only valid characters.
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.
Definition: unit.hpp:95
const GLfloat * c
Definition: glew.h:12741
int pos
Definition: formula.cpp:800
int div100rounded(int num)
Guarantees portable results for division by 100; round towards 0.
Definition: util.hpp:52
GLenum GLenum GLenum input
Definition: glew.h:10668
std::map< std::string, std::string > map_split(std::string const &val, char major, char minor, int flags, std::string const &default_value)
Splits a string based on two separators into a map.
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), and '?' as any one character.
GLuint const GLfloat * val
Definition: glew.h:2614
#define ERR_GENERAL
bool notspace(const char c)
static bool is_username_char(char c)
const std::string unicode_multiplication_sign
GLenum src
Definition: glew.h:2392
const std::string number
template to number regex
std::string quote(const std::string &str)
Surround the string 'str' with double quotes.
std::string & strip(std::string &str)
Remove whitespace from the front and back of the string 'str'.
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
STRIP_SPACES : strips leading and trailing blank spaces.
const std::string unicode_minus
void ellipsis_truncate(std::string &str, const size_t size)
Truncates a string to a given utf-8 character count and then appends an ellipsis. ...
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
bool chars_equal_insensitive(char a, char b)
Definition: util.hpp:206
GLuint GLuint end
Definition: glew.h:1221
const std::string unicode_en_dash
static bool is_wildcard_char(char c)
const GLdouble * v
Definition: glew.h:1359
GLsizei const GLfloat * value
Definition: glew.h:1817
GLenum GLenum dst
Definition: glew.h:2392
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
std::string & strip_end(std::string &str)
Remove whitespace from the back of the string 'str'.
GLenum GLuint GLsizei const char * buf
Definition: glew.h:2498
const std::string unicode_em_dash
GLfloat GLfloat p
Definition: glew.h:12766
utf8::string & truncate(utf8::string &str, const size_t size)
Truncates a UTF-8 string to the specified number of characters.
Definition: unicode.cpp:119
Templates and utility-routines for strings and numbers.
cl_event GLbitfield flags
Definition: glew.h:3070
const std::string &parameters float amount
Definition: filter.cpp:132
lu_byte right
Definition: lparser.cpp:1020
std::string indent(const std::string &string, size_t indent_size)
Indent a block of text.
std::string escape(const std::string &str, const char *special_chars)
Prepends a configurable set of characters with a backslash.
std::pair< int, int > parse_range(std::string const &str)
std::vector< std::string > quoted_split(std::string const &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...
GLuint res
Definition: glew.h:9258
const std::string unicode_figure_dash
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
GLint left
Definition: glew.h:5907
std::vector< std::pair< int, int > > parse_ranges(std::string const &str)
const std::string ellipsis
size_t i
Definition: function.cpp:1057
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)
std::string replace(std::string str, const std::string &src, const std::string &dst)
Replace all instances of src in str with dst.
#define next(ls)
Definition: llex.cpp:27
static lg::log_domain log_engine("engine")
GLsizeiptr size
Definition: glew.h:1649
std::vector< std::string > parenthetical_split(std::string const &val, const char separator, std::string const &left, std::string const &right, const int flags)
Splits a string based either on a separator where text within parenthesis is protected from splitting...
GLclampd n
Definition: glew.h:5903
bool find(E event, F functor)
Tests whether an event handler is available.
int apply_modifier(const int number, const std::string &amount, const int minimum)
static bool is_word_boundary(char c)
Standard logging facilities (interface).
static const char * match(MatchState *ms, const char *s, const char *p)
Definition: lstrlib.cpp:409
GLint * first
Definition: glew.h:1496
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
#define c
Definition: glew.h:12743
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
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
Definition: tokenizer.hpp:21
std::vector< std::string > square_parenthetical_split(std::string const &val, const char separator, std::string const &left, std::string const &right, const int flags)
Similar to parenthetical_split, but also expands embedded square brackets.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool word_completion(std::string &text, std::vector< std::string > &wordlist)
Try to complete the last word of 'text' with the 'wordlist'.
const std::string unicode_bullet
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.