Minetest  5.4.0
string.h
Go to the documentation of this file.
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #pragma once
21 
22 #include "irrlichttypes_bloated.h"
23 #include "irrString.h"
24 #include <cstdlib>
25 #include <string>
26 #include <cstring>
27 #include <vector>
28 #include <map>
29 #include <sstream>
30 #include <iomanip>
31 #include <cctype>
32 #include <unordered_map>
33 
34 class Translations;
35 
36 #define STRINGIFY(x) #x
37 #define TOSTRING(x) STRINGIFY(x)
38 
39 // Checks whether a value is an ASCII printable character
40 #define IS_ASCII_PRINTABLE_CHAR(x) \
41  (((unsigned int)(x) >= 0x20) && \
42  ( (unsigned int)(x) <= 0x7e))
43 
44 // Checks whether a byte is an inner byte for an utf-8 multibyte sequence
45 #define IS_UTF8_MULTB_INNER(x) \
46  (((unsigned char)(x) >= 0x80) && \
47  ( (unsigned char)(x) <= 0xbf))
48 
49 // Checks whether a byte is a start byte for an utf-8 multibyte sequence
50 #define IS_UTF8_MULTB_START(x) \
51  (((unsigned char)(x) >= 0xc2) && \
52  ( (unsigned char)(x) <= 0xf4))
53 
54 // Given a start byte x for an utf-8 multibyte sequence
55 // it gives the length of the whole sequence in bytes.
56 #define UTF8_MULTB_START_LEN(x) \
57  (((unsigned char)(x) < 0xe0) ? 2 : \
58  (((unsigned char)(x) < 0xf0) ? 3 : 4))
59 
60 typedef std::unordered_map<std::string, std::string> StringMap;
61 
62 struct FlagDesc {
63  const char *name;
64  u32 flag;
65 };
66 
67 // Try to avoid converting between wide and UTF-8 unless you need to
68 // input/output stuff via Irrlicht
69 std::wstring utf8_to_wide(const std::string &input);
70 std::string wide_to_utf8(const std::wstring &input);
71 
72 // You must free the returned string!
73 // The returned string is allocated using new[]
74 wchar_t *utf8_to_wide_c(const char *str);
75 
76 std::string urlencode(const std::string &str);
77 std::string urldecode(const std::string &str);
78 u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask);
79 std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask);
80 size_t mystrlcpy(char *dst, const char *src, size_t size);
81 char *mystrtok_r(char *s, const char *sep, char **lasts);
82 u64 read_seed(const char *str);
83 bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
84  unsigned char default_alpha = 0xff);
85 
86 
92 inline std::string padStringRight(std::string str, size_t len)
93 {
94  if (len > str.size())
95  str.insert(str.end(), len - str.size(), ' ');
96 
97  return str;
98 }
99 
111 inline std::string removeStringEnd(const std::string &str,
112  const char *ends[])
113 {
114  const char **p = ends;
115 
116  for (; *p && (*p)[0] != '\0'; p++) {
117  std::string end = *p;
118  if (str.size() < end.size())
119  continue;
120  if (str.compare(str.size() - end.size(), end.size(), end) == 0)
121  return str.substr(0, str.size() - end.size());
122  }
123 
124  return "";
125 }
126 
127 
137 template <typename T>
138 inline bool str_equal(const std::basic_string<T> &s1,
139  const std::basic_string<T> &s2,
140  bool case_insensitive = false)
141 {
142  if (!case_insensitive)
143  return s1 == s2;
144 
145  if (s1.size() != s2.size())
146  return false;
147 
148  for (size_t i = 0; i < s1.size(); ++i)
149  if(tolower(s1[i]) != tolower(s2[i]))
150  return false;
151 
152  return true;
153 }
154 
155 
166 template <typename T>
167 inline bool str_starts_with(const std::basic_string<T> &str,
168  const std::basic_string<T> &prefix,
169  bool case_insensitive = false)
170 {
171  if (str.size() < prefix.size())
172  return false;
173 
174  if (!case_insensitive)
175  return str.compare(0, prefix.size(), prefix) == 0;
176 
177  for (size_t i = 0; i < prefix.size(); ++i)
178  if (tolower(str[i]) != tolower(prefix[i]))
179  return false;
180  return true;
181 }
182 
193 template <typename T>
194 inline bool str_starts_with(const std::basic_string<T> &str,
195  const T *prefix,
196  bool case_insensitive = false)
197 {
198  return str_starts_with(str, std::basic_string<T>(prefix),
199  case_insensitive);
200 }
201 
202 
213 template <typename T>
214 inline bool str_ends_with(const std::basic_string<T> &str,
215  const std::basic_string<T> &suffix,
216  bool case_insensitive = false)
217 {
218  if (str.size() < suffix.size())
219  return false;
220 
221  size_t start = str.size() - suffix.size();
222  if (!case_insensitive)
223  return str.compare(start, suffix.size(), suffix) == 0;
224 
225  for (size_t i = 0; i < suffix.size(); ++i)
226  if (tolower(str[start + i]) != tolower(suffix[i]))
227  return false;
228  return true;
229 }
230 
231 
242 template <typename T>
243 inline bool str_ends_with(const std::basic_string<T> &str,
244  const T *suffix,
245  bool case_insensitive = false)
246 {
247  return str_ends_with(str, std::basic_string<T>(suffix),
248  case_insensitive);
249 }
250 
251 
258 template <typename T>
259 inline std::vector<std::basic_string<T> > str_split(
260  const std::basic_string<T> &str,
261  T delimiter)
262 {
263  std::vector<std::basic_string<T> > parts;
264  std::basic_stringstream<T> sstr(str);
265  std::basic_string<T> part;
266 
267  while (std::getline(sstr, part, delimiter))
268  parts.push_back(part);
269 
270  return parts;
271 }
272 
273 
278 inline std::string lowercase(const std::string &str)
279 {
280  std::string s2;
281 
282  s2.reserve(str.size());
283 
284  for (char i : str)
285  s2 += tolower(i);
286 
287  return s2;
288 }
289 
290 
295 inline std::string trim(const std::string &str)
296 {
297  size_t front = 0;
298 
299  while (std::isspace(str[front]))
300  ++front;
301 
302  size_t back = str.size();
303  while (back > front && std::isspace(str[back - 1]))
304  --back;
305 
306  return str.substr(front, back - front);
307 }
308 
309 
316 inline bool is_yes(const std::string &str)
317 {
318  std::string s2 = lowercase(trim(str));
319 
320  return s2 == "y" || s2 == "yes" || s2 == "true" || atoi(s2.c_str()) != 0;
321 }
322 
323 
336 inline s32 mystoi(const std::string &str, s32 min, s32 max)
337 {
338  s32 i = atoi(str.c_str());
339 
340  if (i < min)
341  i = min;
342  if (i > max)
343  i = max;
344 
345  return i;
346 }
347 
352 inline s32 mystoi(const std::string &str)
353 {
354  return atoi(str.c_str());
355 }
356 
361 inline float mystof(const std::string &str)
362 {
363  return atof(str.c_str());
364 }
365 
366 #define stoi mystoi
367 #define stof mystof
368 
370 template <typename T>
371 inline T from_string(const std::string &str)
372 {
373  std::stringstream tmp(str);
374  T t;
375  tmp >> t;
376  return t;
377 }
378 
380 inline s64 stoi64(const std::string &str) { return from_string<s64>(str); }
381 
382 #if __cplusplus < 201103L
383 namespace std {
384 
386 template <typename T>
387 inline string to_string(T val)
388 {
389  ostringstream oss;
390  oss << val;
391  return oss.str();
392 }
393 #define DEFINE_STD_TOSTRING_FLOATINGPOINT(T) \
394  template <> \
395  inline string to_string<T>(T val) \
396  { \
397  ostringstream oss; \
398  oss << std::fixed \
399  << std::setprecision(6) \
400  << val; \
401  return oss.str(); \
402  }
406 
407 #undef DEFINE_STD_TOSTRING_FLOATINGPOINT
408 
410 template <typename T>
411 inline wstring to_wstring(T val)
412 {
413  return utf8_to_wide(to_string(val));
414 }
415 }
416 #endif
417 
419 inline std::string itos(s32 i) { return std::to_string(i); }
421 inline std::string i64tos(s64 i) { return std::to_string(i); }
422 
423 // std::to_string uses the '%.6f' conversion, which is inconsistent with
424 // std::ostream::operator<<() and impractical too. ftos() uses the
425 // more generic and std::ostream::operator<<()-compatible '%G' format.
427 inline std::string ftos(float f)
428 {
429  std::ostringstream oss;
430  oss << f;
431  return oss.str();
432 }
433 
434 
442 inline void str_replace(std::string &str, const std::string &pattern,
443  const std::string &replacement)
444 {
445  std::string::size_type start = str.find(pattern, 0);
446  while (start != str.npos) {
447  str.replace(start, pattern.size(), replacement);
448  start = str.find(pattern, start + replacement.size());
449  }
450 }
451 
455 inline void str_formspec_escape(std::string &str)
456 {
457  str_replace(str, "\\", "\\\\");
458  str_replace(str, "]", "\\]");
459  str_replace(str, "[", "\\[");
460  str_replace(str, ";", "\\;");
461  str_replace(str, ",", "\\,");
462 }
463 
471 void str_replace(std::string &str, char from, char to);
472 
473 
484 inline bool string_allowed(const std::string &str, const std::string &allowed_chars)
485 {
486  return str.find_first_not_of(allowed_chars) == str.npos;
487 }
488 
489 
500 inline bool string_allowed_blacklist(const std::string &str,
501  const std::string &blacklisted_chars)
502 {
503  return str.find_first_of(blacklisted_chars) == str.npos;
504 }
505 
506 
522 inline std::string wrap_rows(const std::string &from,
523  unsigned row_len)
524 {
525  std::string to;
526 
527  size_t character_idx = 0;
528  for (size_t i = 0; i < from.size(); i++) {
529  if (!IS_UTF8_MULTB_INNER(from[i])) {
530  // Wrap string after last inner byte of char
531  if (character_idx > 0 && character_idx % row_len == 0)
532  to += '\n';
533  character_idx++;
534  }
535  to += from[i];
536  }
537 
538  return to;
539 }
540 
541 
545 template <typename T>
546 inline std::basic_string<T> unescape_string(const std::basic_string<T> &s)
547 {
548  std::basic_string<T> res;
549 
550  for (size_t i = 0; i < s.length(); i++) {
551  if (s[i] == '\\') {
552  i++;
553  if (i >= s.length())
554  break;
555  }
556  res += s[i];
557  }
558 
559  return res;
560 }
561 
568 template <typename T>
569 std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
570 {
571  std::basic_string<T> output;
572  size_t i = 0;
573  while (i < s.length()) {
574  if (s[i] == '\x1b') {
575  ++i;
576  if (i == s.length()) continue;
577  if (s[i] == '(') {
578  ++i;
579  while (i < s.length() && s[i] != ')') {
580  if (s[i] == '\\') {
581  ++i;
582  }
583  ++i;
584  }
585  ++i;
586  } else {
587  ++i;
588  }
589  continue;
590  }
591  output += s[i];
592  ++i;
593  }
594  return output;
595 }
596 
597 template <typename T>
598 std::vector<std::basic_string<T> > split(const std::basic_string<T> &s, T delim)
599 {
600  std::vector<std::basic_string<T> > tokens;
601 
602  std::basic_string<T> current;
603  bool last_was_escape = false;
604  for (size_t i = 0; i < s.length(); i++) {
605  T si = s[i];
606  if (last_was_escape) {
607  current += '\\';
608  current += si;
609  last_was_escape = false;
610  } else {
611  if (si == delim) {
612  tokens.push_back(current);
613  current = std::basic_string<T>();
614  last_was_escape = false;
615  } else if (si == '\\') {
616  last_was_escape = true;
617  } else {
618  current += si;
619  last_was_escape = false;
620  }
621  }
622  }
623  //push last element
624  tokens.push_back(current);
625 
626  return tokens;
627 }
628 
629 std::wstring translate_string(const std::wstring &s, Translations *translations);
630 
631 std::wstring translate_string(const std::wstring &s);
632 
633 inline std::wstring unescape_translate(const std::wstring &s) {
635 }
636 
644 inline bool is_number(const std::string &to_check)
645 {
646  for (char i : to_check)
647  if (!std::isdigit(i))
648  return false;
649 
650  return !to_check.empty();
651 }
652 
653 
659 inline const char *bool_to_cstr(bool val)
660 {
661  return val ? "true" : "false";
662 }
663 
664 inline const std::string duration_to_string(int sec)
665 {
666  int min = sec / 60;
667  sec %= 60;
668  int hour = min / 60;
669  min %= 60;
670 
671  std::stringstream ss;
672  if (hour > 0) {
673  ss << hour << "h ";
674  }
675 
676  if (min > 0) {
677  ss << min << "m ";
678  }
679 
680  if (sec > 0) {
681  ss << sec << "s ";
682  }
683 
684  return ss.str();
685 }
686 
692 inline std::string str_join(const std::vector<std::string> &list,
693  const std::string &delimiter)
694 {
695  std::ostringstream oss;
696  bool first = true;
697  for (const auto &part : list) {
698  if (!first)
699  oss << delimiter;
700  oss << part;
701  first = false;
702  }
703  return oss.str();
704 }
705 
709 inline std::string stringw_to_utf8(const irr::core::stringw &input)
710 {
711  std::wstring str(input.c_str());
712  return wide_to_utf8(str);
713 }
714 
718 inline irr::core::stringw utf8_to_stringw(const std::string &input)
719 {
720  std::wstring str = utf8_to_wide(input);
721  return irr::core::stringw(str.c_str());
722 }
723 
730 std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix);
Definition: translation.h:31
s64 stoi64(const std::string &str)
Returns a 64-bit signed value represented by the string str (decimal).
Definition: string.h:380
std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask)
Definition: string.cpp:251
bool string_allowed(const std::string &str, const std::string &allowed_chars)
Check that a string only contains whitelisted characters.
Definition: string.h:484
bool str_starts_with(const std::basic_string< T > &str, const std::basic_string< T > &prefix, bool case_insensitive=false)
Check whether str begins with the string prefix.
Definition: string.h:167
std::string urldecode(const std::string &str)
Definition: string.cpp:197
std::string lowercase(const std::string &str)
Definition: string.h:278
bool is_yes(const std::string &str)
Returns whether str should be regarded as (bool) true.
Definition: string.h:316
#define DEFINE_STD_TOSTRING_FLOATINGPOINT(T)
Definition: string.h:393
u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask)
Definition: string.cpp:215
std::basic_string< T > unescape_string(const std::basic_string< T > &s)
Removes backslashes from an escaped string (FormSpec strings)
Definition: string.h:546
#define IS_UTF8_MULTB_INNER(x)
Definition: string.h:45
const std::string duration_to_string(int sec)
Definition: string.h:664
std::string removeStringEnd(const std::string &str, const char *ends[])
Returns a version of str with the first occurrence of a string contained within ends[] removed from t...
Definition: string.h:111
void str_replace(std::string &str, const std::string &pattern, const std::string &replacement)
Replace all occurrences of pattern in str with replacement.
Definition: string.h:442
irr::core::stringw utf8_to_stringw(const std::string &input)
Create a irr::core:stringw from a UTF8 std::string.
Definition: string.h:718
std::wstring utf8_to_wide(const std::string &input)
Definition: string.cpp:90
std::string trim(const std::string &str)
Definition: string.h:295
bool parseColorString(const std::string &value, video::SColor &color, bool quiet, unsigned char default_alpha=0xff)
Definition: string.cpp:327
T from_string(const std::string &str)
Returns a value represented by the string val.
Definition: string.h:371
char * mystrtok_r(char *s, const char *sep, char **lasts)
Definition: string.cpp:285
std::wstring translate_string(const std::wstring &s, Translations *translations)
Definition: string.cpp:812
std::unordered_map< std::string, std::string > StringMap
Definition: string.h:60
std::string stringw_to_utf8(const irr::core::stringw &input)
Create a UTF8 std::string from a irr::core::stringw.
Definition: string.h:709
std::string urlencode(const std::string &str)
Definition: string.cpp:179
std::string str_join(const std::vector< std::string > &list, const std::string &delimiter)
Joins a vector of strings by the string delimiter.
Definition: string.h:692
wstring to_wstring(T val)
Returns a wide string representing the value val.
Definition: string.h:411
std::string padStringRight(std::string str, size_t len)
Returns a copy of str with spaces inserted at the right hand side to ensure that the string is len ch...
Definition: string.h:92
std::vector< std::basic_string< T > > str_split(const std::basic_string< T > &str, T delimiter)
Splits a string into its component parts separated by the character delimiter.
Definition: string.h:259
std::wstring unescape_translate(const std::wstring &s)
Definition: string.h:633
wchar_t * utf8_to_wide_c(const char *str)
Definition: string.cpp:169
float mystof(const std::string &str)
Returns a float reprensented by the string str (decimal).
Definition: string.h:361
std::string wide_to_utf8(const std::wstring &input)
Definition: string.cpp:118
std::string itos(s32 i)
Returns a string representing the decimal value of the 32-bit value i.
Definition: string.h:419
std::basic_string< T > unescape_enriched(const std::basic_string< T > &s)
Remove all escape sequences in s.
Definition: string.h:569
void str_formspec_escape(std::string &str)
Escapes characters [ ] \ , ; that can not be used in formspecs.
Definition: string.h:455
std::string i64tos(s64 i)
Returns a string representing the decimal value of the 64-bit value i.
Definition: string.h:421
bool str_equal(const std::basic_string< T > &s1, const std::basic_string< T > &s2, bool case_insensitive=false)
Check two strings for equivalence.
Definition: string.h:138
bool is_number(const std::string &to_check)
Checks that all characters in to_check are a decimal digits.
Definition: string.h:644
std::string ftos(float f)
Returns a string representing the decimal value of the float value f.
Definition: string.h:427
bool string_allowed_blacklist(const std::string &str, const std::string &blacklisted_chars)
Check that a string contains no blacklisted characters.
Definition: string.h:500
string to_string(T val)
Returns a string representing the value val.
Definition: string.h:387
std::string wrap_rows(const std::string &from, unsigned row_len)
Create a string based on from where a newline is forcefully inserted every row_len characters.
Definition: string.h:522
std::string sanitizeDirName(const std::string &str, const std::string &optional_prefix)
Sanitize the name of a new directory.
Definition: string.cpp:868
std::vector< std::basic_string< T > > split(const std::basic_string< T > &s, T delim)
Definition: string.h:598
const char * bool_to_cstr(bool val)
Returns a C-string, either "true" or "false", corresponding to val.
Definition: string.h:659
bool str_ends_with(const std::basic_string< T > &str, const std::basic_string< T > &suffix, bool case_insensitive=false)
Check whether str ends with the string suffix.
Definition: string.h:214
u64 read_seed(const char *str)
Definition: string.cpp:311
size_t mystrlcpy(char *dst, const char *src, size_t size)
Definition: string.cpp:272
s32 mystoi(const std::string &str, s32 min, s32 max)
Converts the string str to a signed 32-bit integer.
Definition: string.h:336
Definition: string.h:62
u32 flag
Definition: string.h:64
const char * name
Definition: string.h:63
std::string p(std::string path)
Definition: test_filepath.cpp:59