X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Futil%2Fstring.h;h=3cb0f7bec15af0e51940cdcf7faf33e082b5fa51;hb=63867b1a372a4d1a4a4ffdec9d0862b094211a89;hp=58274c6773cd7a3807c52c7df7674e29734a81fc;hpb=3578e1d4a711a32e2e768dcc6ff207ffc1bccbad;p=minetest.git diff --git a/src/util/string.h b/src/util/string.h index 58274c677..3cb0f7bec 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,6 +1,6 @@ /* -Minetest-c55 -Copyright (C) 2010-2012 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -20,165 +20,269 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef UTIL_STRING_HEADER #define UTIL_STRING_HEADER -#include "../irrlichttypes.h" -#include "../strfnd.h" // For trim() -#include "pointer.h" +#include "irrlichttypes_bloated.h" +#include #include #include #include #include +#include -static inline std::string padStringRight(std::string s, size_t len) +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +struct FlagDesc { + const char *name; + u32 flag; +}; + +std::wstring narrow_to_wide(const std::string& mbs); +std::string wide_to_narrow(const std::wstring& wcs); +std::string translatePassword(std::string playername, std::wstring password); +std::string urlencode(std::string str); +std::string urldecode(std::string str); +u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask); +std::string writeFlagString(u32 flags, const FlagDesc *flagdesc, u32 flagmask); +size_t mystrlcpy(char *dst, const char *src, size_t size); +char *mystrtok_r(char *s, const char *sep, char **lasts); +u64 read_seed(const char *str); +bool parseColorString(const std::string &value, video::SColor &color, bool quiet); + + +/** + * Returns a copy of \p str with spaces inserted at the right hand side to ensure + * that the string is \p len characters in length. If \p str is <= \p len then the + * returned string will be identical to str. + */ +inline std::string padStringRight(std::string str, size_t len) { - if(len > s.size()) - s.insert(s.end(), len - s.size(), ' '); - return s; + if (len > str.size()) + str.insert(str.end(), len - str.size(), ' '); + + return str; } -// ends: NULL- or ""-terminated array of strings -// Returns "" if no end could be removed. -static inline std::string removeStringEnd(const std::string &s, const char *ends[]) +/** + * Returns a version of \p str with the first occurrence of a string + * contained within ends[] removed from the end of the string. + * + * @param str + * @param ends A NULL- or ""- terminated array of strings to remove from s in + * the copy produced. Note that once one of these strings is removed + * that no further postfixes contained within this array are removed. + * + * @return If no end could be removed then "" is returned. + */ +inline std::string removeStringEnd(const std::string &str, + const char *ends[]) { const char **p = ends; - for(; (*p) && (*p)[0] != '\0'; p++){ + + for (; *p && (*p)[0] != '\0'; p++) { std::string end = *p; - if(s.size() < end.size()) + if (str.size() < end.size()) continue; - if(s.substr(s.size()-end.size(), end.size()) == end) - return s.substr(0, s.size() - end.size()); + if (str.compare(str.size() - end.size(), end.size(), end) == 0) + return str.substr(0, str.size() - end.size()); } + return ""; } -// Tests if two strings are equal, optionally case insensitive -inline bool str_equal(const std::wstring& s1, const std::wstring& s2, + +/** + * Check two strings for equivalence. If \p case_insensitive is true + * then the case of the strings is ignored (default is false). + * + * @param s1 + * @param s2 + * @param case_insensitive + * @return true if the strings match + */ +template +inline bool str_equal(const std::basic_string &s1, + const std::basic_string &s2, bool case_insensitive = false) { - if(case_insensitive) - { - if(s1.size() != s2.size()) - return false; - for(size_t i = 0; i < s1.size(); ++i) - if(tolower(s1[i]) != tolower(s2[i])) - return false; - return true; - } - else - { + if (!case_insensitive) return s1 == s2; - } + + if (s1.size() != s2.size()) + return false; + + for (size_t i = 0; i < s1.size(); ++i) + if(tolower(s1[i]) != tolower(s2[i])) + return false; + + return true; } -// Tests if the second string is a prefix of the first, optionally case insensitive -inline bool str_starts_with(const std::wstring& str, const std::wstring& prefix, + +/** + * Check whether \p str begins with the string prefix. If \p case_insensitive + * is true then the check is case insensitve (default is false; i.e. case is + * significant). + * + * @param str + * @param prefix + * @param case_insensitive + * @return true if the str begins with prefix + */ +template +inline bool str_starts_with(const std::basic_string &str, + const std::basic_string &prefix, bool case_insensitive = false) { - if(str.size() < prefix.size()) + if (str.size() < prefix.size()) return false; - if(case_insensitive) - { - for(size_t i = 0; i < prefix.size(); ++i) - if(tolower(str[i]) != tolower(prefix[i])) - return false; - } - else - { - for(size_t i = 0; i < prefix.size(); ++i) - if(str[i] != prefix[i]) - return false; - } + + if (!case_insensitive) + return str.compare(0, prefix.size(), prefix) == 0; + + for (size_t i = 0; i < prefix.size(); ++i) + if (tolower(str[i]) != tolower(prefix[i])) + return false; return true; } -inline std::wstring narrow_to_wide(const std::string& mbs) -{ - size_t wcl = mbs.size(); - Buffer wcs(wcl+1); - size_t l = mbstowcs(*wcs, mbs.c_str(), wcl); - if(l == (size_t)(-1)) - return L""; - wcs[l] = 0; - return *wcs; -} -inline std::string wide_to_narrow(const std::wstring& wcs) +/** + * Splits a string into its component parts separated by the character + * \p delimiter. + * + * @return An std::vector > of the component parts + */ +template +inline std::vector > str_split( + const std::basic_string &str, + T delimiter) { - size_t mbl = wcs.size()*4; - SharedBuffer mbs(mbl+1); - size_t l = wcstombs(*mbs, wcs.c_str(), mbl); - if(l == (size_t)(-1)) - mbs[0] = 0; - else - mbs[l] = 0; - return *mbs; -} + std::vector > parts; + std::basic_stringstream sstr(str); + std::basic_string part; -// Split a string using the given delimiter. Returns a vector containing -// the component parts. -inline std::vector str_split(const std::wstring &str, wchar_t delimiter) -{ - std::vector parts; - std::wstringstream sstr(str); - std::wstring part; - while(std::getline(sstr, part, delimiter)) + while (std::getline(sstr, part, delimiter)) parts.push_back(part); + return parts; } -inline std::string lowercase(const std::string &s) + +/** + * @param str + * @return A copy of \p str converted to all lowercase characters. + */ +inline std::string lowercase(const std::string &str) { std::string s2; - for(size_t i=0; i= 'A' && c <= 'Z') - c -= 'A' - 'a'; - s2 += c; - } + + s2.reserve(str.size()); + + for (size_t i = 0; i < str.size(); i++) + s2 += tolower(str[i]); + return s2; } -inline bool is_yes(const std::string &s) + +/** + * @param str + * @return A copy of \p str with leading and trailing whitespace removed. + */ +inline std::string trim(const std::string &str) +{ + size_t front = 0; + + while (std::isspace(str[front])) + ++front; + + size_t back = str.size(); + while (back > front && std::isspace(str[back - 1])) + --back; + + return str.substr(front, back - front); +} + + +/** + * Returns whether \p str should be regarded as (bool) true. Case and leading + * and trailing whitespace are ignored. Values that will return + * true are "y", "yes", "true" and any number that is not 0. + * @param str + */ +inline bool is_yes(const std::string &str) { - std::string s2 = lowercase(trim(s)); - if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1") - return true; - return false; + std::string s2 = lowercase(trim(str)); + + return s2 == "y" || s2 == "yes" || s2 == "true" || atoi(s2.c_str()) != 0; } -inline s32 mystoi(const std::string &s, s32 min, s32 max) + +/** + * Converts the string \p str to a signed 32-bit integer. The converted value + * is constrained so that min <= value <= max. + * + * @see atoi(3) for limitations + * + * @param str + * @param min Range minimum + * @param max Range maximum + * @return The value converted to a signed 32-bit integer and constrained + * within the range defined by min and max (inclusive) + */ +inline s32 mystoi(const std::string &str, s32 min, s32 max) { - s32 i = atoi(s.c_str()); - if(i < min) + s32 i = atoi(str.c_str()); + + if (i < min) i = min; - if(i > max) + if (i > max) i = max; + return i; } +/// Returns a 64-bit value represented by the string \p str (decimal). +inline s64 stoi64(const std::string &str) +{ + std::stringstream tmp(str); + s64 t; + tmp >> t; + return t; +} + // MSVC2010 includes it's own versions of these //#if !defined(_MSC_VER) || _MSC_VER < 1600 -inline s32 mystoi(const std::string &s) + +/** + * Returns a 32-bit value reprensented by the string \p str (decimal). + * @see atoi(3) for further limitations + */ +inline s32 mystoi(const std::string &str) { - return atoi(s.c_str()); + return atoi(str.c_str()); } -inline s32 mystoi(const std::wstring &s) + +/** + * Returns s 32-bit value represented by the wide string \p str (decimal). + * @see atoi(3) for further limitations + */ +inline s32 mystoi(const std::wstring &str) { - return atoi(wide_to_narrow(s).c_str()); + return mystoi(wide_to_narrow(str)); } -inline float mystof(const std::string &s) + +/** + * Returns a float reprensented by the string \p str (decimal). + * @see atof(3) + */ +inline float mystof(const std::string &str) { - // This crap causes a segfault in certain cases on MinGW - /*float f; - std::istringstream ss(s); - ss>>f; - return f;*/ - // This works in that case - return atof(s.c_str()); + return atof(str.c_str()); } //#endif @@ -186,103 +290,156 @@ inline float mystof(const std::string &s) #define stoi mystoi #define stof mystof -inline std::string itos(s32 i) -{ - std::ostringstream o; - o< +inline std::string to_string(T val) { - std::ostringstream o; - o< +inline std::basic_string unescape_string(std::basic_string &s) +{ + std::basic_string res; + + for (size_t i = 0; i < s.length(); i++) { + if (s[i] != '\\') + res += s[i]; + } + + return res; +} + +/** + * Checks that all characters in \p to_check are a decimal digits. + * + * @param to_check + * @return true if to_check is not empty and all characters in to_check are + * decimal digits, otherwise false + */ +inline bool is_number(const std::string &to_check) +{ + for (size_t i = 0; i < to_check.size(); i++) + if (!std::isdigit(to_check[i])) + return false; + + return !to_check.empty(); +} + + +/** + * Returns a C-string, either "true" or "false", corresponding to \p val. + * + * @return If \p val is true, then "true" is returned, otherwise "false". + */ +inline const char *bool_to_cstr(bool val) +{ + return val ? "true" : "false"; +} + +#endif