Line data Source code
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 : #ifndef UTIL_STRING_HEADER
21 : #define UTIL_STRING_HEADER
22 :
23 : #include "irrlichttypes_bloated.h"
24 : #include <stdlib.h>
25 : #include <string>
26 : #include <cstring>
27 : #include <vector>
28 : #include <map>
29 : #include <sstream>
30 : #include <cctype>
31 :
32 : #define STRINGIFY(x) #x
33 : #define TOSTRING(x) STRINGIFY(x)
34 :
35 : // Checks whether a byte is an inner byte for an utf-8 multibyte sequence
36 : #define IS_UTF8_MULTB_INNER(x) (((unsigned char)x >= 0x80) && ((unsigned char)x < 0xc0))
37 :
38 : typedef std::map<std::string, std::string> StringMap;
39 :
40 : struct FlagDesc {
41 : const char *name;
42 : u32 flag;
43 : };
44 :
45 : // try not to convert between wide/utf8 encodings; this can result in data loss
46 : // try to only convert between them when you need to input/output stuff via Irrlicht
47 : std::wstring utf8_to_wide(const std::string &input);
48 : std::string wide_to_utf8(const std::wstring &input);
49 :
50 : // NEVER use those two functions unless you have a VERY GOOD reason to
51 : // they just convert between wide and multibyte encoding
52 : // multibyte encoding depends on current locale, this is no good, especially on Windows
53 :
54 : // You must free the returned string!
55 : // The returned string is allocated using new
56 : wchar_t *narrow_to_wide_c(const char *str);
57 : std::wstring narrow_to_wide(const std::string &mbs);
58 : std::string wide_to_narrow(const std::wstring &wcs);
59 :
60 : std::string urlencode(std::string str);
61 : std::string urldecode(std::string str);
62 : u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask);
63 : std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask);
64 : size_t mystrlcpy(char *dst, const char *src, size_t size);
65 : char *mystrtok_r(char *s, const char *sep, char **lasts);
66 : u64 read_seed(const char *str);
67 : bool parseColorString(const std::string &value, video::SColor &color, bool quiet);
68 :
69 :
70 : /**
71 : * Returns a copy of \p str with spaces inserted at the right hand side to ensure
72 : * that the string is \p len characters in length. If \p str is <= \p len then the
73 : * returned string will be identical to str.
74 : */
75 0 : inline std::string padStringRight(std::string str, size_t len)
76 : {
77 0 : if (len > str.size())
78 0 : str.insert(str.end(), len - str.size(), ' ');
79 :
80 0 : return str;
81 : }
82 :
83 : /**
84 : * Returns a version of \p str with the first occurrence of a string
85 : * contained within ends[] removed from the end of the string.
86 : *
87 : * @param str
88 : * @param ends A NULL- or ""- terminated array of strings to remove from s in
89 : * the copy produced. Note that once one of these strings is removed
90 : * that no further postfixes contained within this array are removed.
91 : *
92 : * @return If no end could be removed then "" is returned.
93 : */
94 9890 : inline std::string removeStringEnd(const std::string &str,
95 : const char *ends[])
96 : {
97 9890 : const char **p = ends;
98 :
99 24282 : for (; *p && (*p)[0] != '\0'; p++) {
100 23724 : std::string end = *p;
101 16528 : if (str.size() < end.size())
102 0 : continue;
103 16528 : if (str.compare(str.size() - end.size(), end.size(), end) == 0)
104 9332 : return str.substr(0, str.size() - end.size());
105 : }
106 :
107 558 : return "";
108 : }
109 :
110 :
111 : /**
112 : * Check two strings for equivalence. If \p case_insensitive is true
113 : * then the case of the strings is ignored (default is false).
114 : *
115 : * @param s1
116 : * @param s2
117 : * @param case_insensitive
118 : * @return true if the strings match
119 : */
120 : template <typename T>
121 0 : inline bool str_equal(const std::basic_string<T> &s1,
122 : const std::basic_string<T> &s2,
123 : bool case_insensitive = false)
124 : {
125 0 : if (!case_insensitive)
126 0 : return s1 == s2;
127 :
128 0 : if (s1.size() != s2.size())
129 0 : return false;
130 :
131 0 : for (size_t i = 0; i < s1.size(); ++i)
132 0 : if(tolower(s1[i]) != tolower(s2[i]))
133 0 : return false;
134 :
135 0 : return true;
136 : }
137 :
138 :
139 : /**
140 : * Check whether \p str begins with the string prefix. If \p case_insensitive
141 : * is true then the check is case insensitve (default is false; i.e. case is
142 : * significant).
143 : *
144 : * @param str
145 : * @param prefix
146 : * @param case_insensitive
147 : * @return true if the str begins with prefix
148 : */
149 : template <typename T>
150 27280 : inline bool str_starts_with(const std::basic_string<T> &str,
151 : const std::basic_string<T> &prefix,
152 : bool case_insensitive = false)
153 : {
154 27280 : if (str.size() < prefix.size())
155 0 : return false;
156 :
157 27280 : if (!case_insensitive)
158 27280 : return str.compare(0, prefix.size(), prefix) == 0;
159 :
160 0 : for (size_t i = 0; i < prefix.size(); ++i)
161 0 : if (tolower(str[i]) != tolower(prefix[i]))
162 0 : return false;
163 0 : return true;
164 : }
165 :
166 : /**
167 : * Check whether \p str begins with the string prefix. If \p case_insensitive
168 : * is true then the check is case insensitve (default is false; i.e. case is
169 : * significant).
170 : *
171 : * @param str
172 : * @param prefix
173 : * @param case_insensitive
174 : * @return true if the str begins with prefix
175 : */
176 : template <typename T>
177 27280 : inline bool str_starts_with(const std::basic_string<T> &str,
178 : const T *prefix,
179 : bool case_insensitive = false)
180 : {
181 54560 : return str_starts_with(str, std::basic_string<T>(prefix),
182 54560 : case_insensitive);
183 : }
184 :
185 : /**
186 : * Splits a string into its component parts separated by the character
187 : * \p delimiter.
188 : *
189 : * @return An std::vector<std::basic_string<T> > of the component parts
190 : */
191 : template <typename T>
192 0 : inline std::vector<std::basic_string<T> > str_split(
193 : const std::basic_string<T> &str,
194 : T delimiter)
195 : {
196 0 : std::vector<std::basic_string<T> > parts;
197 0 : std::basic_stringstream<T> sstr(str);
198 0 : std::basic_string<T> part;
199 :
200 0 : while (std::getline(sstr, part, delimiter))
201 0 : parts.push_back(part);
202 :
203 0 : return parts;
204 : }
205 :
206 :
207 : /**
208 : * @param str
209 : * @return A copy of \p str converted to all lowercase characters.
210 : */
211 77537 : inline std::string lowercase(const std::string &str)
212 : {
213 77537 : std::string s2;
214 :
215 77537 : s2.reserve(str.size());
216 :
217 453780 : for (size_t i = 0; i < str.size(); i++)
218 376243 : s2 += tolower(str[i]);
219 :
220 77537 : return s2;
221 : }
222 :
223 :
224 : /**
225 : * @param str
226 : * @return A copy of \p str with leading and trailing whitespace removed.
227 : */
228 78336 : inline std::string trim(const std::string &str)
229 : {
230 78336 : size_t front = 0;
231 :
232 78994 : while (std::isspace(str[front]))
233 329 : ++front;
234 :
235 78336 : size_t back = str.size();
236 79002 : while (back > front && std::isspace(str[back - 1]))
237 333 : --back;
238 :
239 78336 : return str.substr(front, back - front);
240 : }
241 :
242 :
243 : /**
244 : * Returns whether \p str should be regarded as (bool) true. Case and leading
245 : * and trailing whitespace are ignored. Values that will return
246 : * true are "y", "yes", "true" and any number that is not 0.
247 : * @param str
248 : */
249 76997 : inline bool is_yes(const std::string &str)
250 : {
251 153994 : std::string s2 = lowercase(trim(str));
252 :
253 153994 : return s2 == "y" || s2 == "yes" || s2 == "true" || atoi(s2.c_str()) != 0;
254 : }
255 :
256 :
257 : /**
258 : * Converts the string \p str to a signed 32-bit integer. The converted value
259 : * is constrained so that min <= value <= max.
260 : *
261 : * @see atoi(3) for limitations
262 : *
263 : * @param str
264 : * @param min Range minimum
265 : * @param max Range maximum
266 : * @return The value converted to a signed 32-bit integer and constrained
267 : * within the range defined by min and max (inclusive)
268 : */
269 10372 : inline s32 mystoi(const std::string &str, s32 min, s32 max)
270 : {
271 10372 : s32 i = atoi(str.c_str());
272 :
273 10372 : if (i < min)
274 0 : i = min;
275 10372 : if (i > max)
276 0 : i = max;
277 :
278 10372 : return i;
279 : }
280 :
281 :
282 : /// Returns a 64-bit value represented by the string \p str (decimal).
283 : inline s64 stoi64(const std::string &str)
284 : {
285 : std::stringstream tmp(str);
286 : s64 t;
287 : tmp >> t;
288 : return t;
289 : }
290 :
291 : // MSVC2010 includes it's own versions of these
292 : //#if !defined(_MSC_VER) || _MSC_VER < 1600
293 :
294 :
295 : /**
296 : * Returns a 32-bit value reprensented by the string \p str (decimal).
297 : * @see atoi(3) for further limitations
298 : */
299 4420 : inline s32 mystoi(const std::string &str)
300 : {
301 4420 : return atoi(str.c_str());
302 : }
303 :
304 :
305 : /**
306 : * Returns s 32-bit value represented by the wide string \p str (decimal).
307 : * @see atoi(3) for further limitations
308 : */
309 : inline s32 mystoi(const std::wstring &str)
310 : {
311 : return mystoi(wide_to_narrow(str));
312 : }
313 :
314 :
315 : /**
316 : * Returns a float reprensented by the string \p str (decimal).
317 : * @see atof(3)
318 : */
319 7872 : inline float mystof(const std::string &str)
320 : {
321 7872 : return atof(str.c_str());
322 : }
323 :
324 : //#endif
325 :
326 : #define stoi mystoi
327 : #define stof mystof
328 :
329 : // TODO: Replace with C++11 std::to_string.
330 :
331 : /// Returns A string representing the value \p val.
332 : template <typename T>
333 85275 : inline std::string to_string(T val)
334 : {
335 170559 : std::ostringstream oss;
336 85283 : oss << val;
337 170552 : return oss.str();
338 : }
339 :
340 : /// Returns a string representing the decimal value of the 32-bit value \p i.
341 85098 : inline std::string itos(s32 i) { return to_string(i); }
342 : /// Returns a string representing the decimal value of the 64-bit value \p i.
343 : inline std::string i64tos(s64 i) { return to_string(i); }
344 : /// Returns a string representing the decimal value of the float value \p f.
345 175 : inline std::string ftos(float f) { return to_string(f); }
346 :
347 :
348 : /**
349 : * Replace all occurrences of \p pattern in \p str with \p replacement.
350 : *
351 : * @param str String to replace pattern with replacement within.
352 : * @param pattern The pattern to replace.
353 : * @param replacement What to replace the pattern with.
354 : */
355 0 : inline void str_replace(std::string &str, const std::string &pattern,
356 : const std::string &replacement)
357 : {
358 0 : std::string::size_type start = str.find(pattern, 0);
359 0 : while (start != str.npos) {
360 0 : str.replace(start, pattern.size(), replacement);
361 0 : start = str.find(pattern, start + replacement.size());
362 : }
363 0 : }
364 :
365 :
366 : /**
367 : * Replace all occurrences of the character \p from in \p str with \p to.
368 : *
369 : * @param str The string to (potentially) modify.
370 : * @param from The character in str to replace.
371 : * @param to The replacement character.
372 : */
373 : void str_replace(std::string &str, char from, char to);
374 :
375 :
376 : /**
377 : * Check that a string only contains whitelisted characters. This is the
378 : * opposite of string_allowed_blacklist().
379 : *
380 : * @param str The string to be checked.
381 : * @param allowed_chars A string containing permitted characters.
382 : * @return true if the string is allowed, otherwise false.
383 : *
384 : * @see string_allowed_blacklist()
385 : */
386 2635 : inline bool string_allowed(const std::string &str, const std::string &allowed_chars)
387 : {
388 2635 : return str.find_first_not_of(allowed_chars) == str.npos;
389 : }
390 :
391 :
392 : /**
393 : * Check that a string contains no blacklisted characters. This is the
394 : * opposite of string_allowed().
395 : *
396 : * @param str The string to be checked.
397 : * @param blacklisted_chars A string containing prohibited characters.
398 : * @return true if the string is allowed, otherwise false.
399 :
400 : * @see string_allowed()
401 : */
402 0 : inline bool string_allowed_blacklist(const std::string &str,
403 : const std::string &blacklisted_chars)
404 : {
405 0 : return str.find_first_of(blacklisted_chars) == str.npos;
406 : }
407 :
408 :
409 : /**
410 : * Create a string based on \p from where a newline is forcefully inserted
411 : * every \p row_len characters.
412 : *
413 : * @note This function does not honour word wraps and blindy inserts a newline
414 : * every \p row_len characters whether it breaks a word or not. It is
415 : * intended to be used for, for example, showing paths in the GUI.
416 : *
417 : * @note This function doesn't wrap inside utf-8 multibyte sequences and also
418 : * counts multibyte sequences correcly as single characters.
419 : *
420 : * @param from The (utf-8) string to be wrapped into rows.
421 : * @param row_len The row length (in characters).
422 : * @return A new string with the wrapping applied.
423 : */
424 1 : inline std::string wrap_rows(const std::string &from,
425 : unsigned row_len)
426 : {
427 1 : std::string to;
428 :
429 1 : size_t character_idx = 0;
430 22 : for (size_t i = 0; i < from.size(); i++) {
431 21 : if (!IS_UTF8_MULTB_INNER(from[i])) {
432 : // Wrap string after last inner byte of char
433 21 : if (character_idx > 0 && character_idx % row_len == 0)
434 1 : to += '\n';
435 21 : character_idx++;
436 : }
437 21 : to += from[i];
438 : }
439 :
440 1 : return to;
441 : }
442 :
443 :
444 : /**
445 : * Removes backslashes from an escaped string (FormSpec strings)
446 : */
447 : template <typename T>
448 40 : inline std::basic_string<T> unescape_string(std::basic_string<T> &s)
449 : {
450 40 : std::basic_string<T> res;
451 :
452 751 : for (size_t i = 0; i < s.length(); i++) {
453 711 : if (s[i] == '\\') {
454 0 : i++;
455 0 : if (i >= s.length())
456 0 : break;
457 : }
458 711 : res += s[i];
459 : }
460 :
461 40 : return res;
462 : }
463 :
464 :
465 : /**
466 : * Checks that all characters in \p to_check are a decimal digits.
467 : *
468 : * @param to_check
469 : * @return true if to_check is not empty and all characters in to_check are
470 : * decimal digits, otherwise false
471 : */
472 203 : inline bool is_number(const std::string &to_check)
473 : {
474 721 : for (size_t i = 0; i < to_check.size(); i++)
475 518 : if (!std::isdigit(to_check[i]))
476 0 : return false;
477 :
478 203 : return !to_check.empty();
479 : }
480 :
481 :
482 : /**
483 : * Returns a C-string, either "true" or "false", corresponding to \p val.
484 : *
485 : * @return If \p val is true, then "true" is returned, otherwise "false".
486 : */
487 0 : inline const char *bool_to_cstr(bool val)
488 : {
489 0 : return val ? "true" : "false";
490 : }
491 :
492 : #endif
|