// Copyright 2013 Facebook, Inc. Licensed under Apache License 2.0 #pragma once #include #include #include #include #include #include #include #include #include #include #include #include // String formatting with variable arguments - creates formatted string from format specifier and arguments const std::string vStringFormat(const char* format, va_list args) { std::string output; va_list tmpargs; va_copy(tmpargs, args); int characters_used = vsnprintf(nullptr, 0, format, tmpargs); va_end(tmpargs); // Looks like we have a valid format string if (characters_used > 0) { output.resize(characters_used + 1); va_copy(tmpargs, args); characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs); va_end(tmpargs); output.resize(characters_used); // Format error handling - return empty string if error occurred if (characters_used < 0) output.clear(); } return output; } // Convert string to lowercase - returns new lowercase string const std::string str_tolower(std::string s) { std::transform( s.begin(), s.end(), s.begin(), [](unsigned char c) { return ::tolower(c); } ); return s; } // Split string by delimiter - returns vector of substrings std::vector split(std::string str_to_split, char delimiter) { std::stringstream ss(str_to_split); std::string item; std::vector exploded_values; while (std::getline(ss, item, delimiter)) { exploded_values.push_back(item); } return exploded_values; } // Convert string to uppercase - returns new uppercase string const std::string str_toupper(std::string s) { std::transform( s.begin(), s.end(), s.begin(), [](unsigned char c) { return ::toupper(c); } ); return s; } // Capitalize first character - returns string with first character uppercase const std::string ucfirst(std::string s) { std::string output = s; if (!s.empty()) output[0] = static_cast(::toupper(s[0])); return output; } // Format string with printf-style arguments - creates formatted string const std::string StringFormat(const char *format, ...) { va_list args; va_start(args, format); std::string output = vStringFormat(format, args); va_end(args); return output; } // Split string by delimiter - alternative implementation returning vector of substrings std::vector SplitString(const std::string &str, char delim) { std::vector ret; std::stringstream ss(str); std::string item; while(std::getline(ss, item, delim)) { ret.push_back(item); } return ret; } // Join vector of strings with glue string - concatenates strings with separator std::string implode(std::string glue, std::vector src) { if (src.empty()) { return {}; } std::ostringstream output; std::vector::iterator src_iter; for (src_iter = src.begin(); src_iter != src.end(); src_iter++) { output << *src_iter << glue; } std::string final_output = output.str(); final_output.resize(output.str().size() - glue.size()); return final_output; } // Escape special characters in string - adds backslash escapes for special characters std::string EscapeString(const std::string &s) { std::string ret; size_t sz = s.length(); for(size_t i = 0; i < sz; ++i) { char c = s[i]; switch(c) { case '\x00': ret += "\\x00"; break; case '\n': ret += "\\n"; break; case '\r': ret += "\\r"; break; case '\\': ret += "\\\\"; break; case '\'': ret += "\\'"; break; case '\"': ret += "\\\""; break; case '\x1a': ret += "\\x1a"; break; default: ret.push_back(c); break; } } return ret; } // Escape special characters in C string - adds backslash escapes for special characters std::string EscapeString(const char *src, size_t sz) { std::string ret; for(size_t i = 0; i < sz; ++i) { char c = src[i]; switch(c) { case '\x00': ret += "\\x00"; break; case '\n': ret += "\\n"; break; case '\r': ret += "\\r"; break; case '\\': ret += "\\\\"; break; case '\'': ret += "\\'"; break; case '\"': ret += "\\\""; break; case '\x1a': ret += "\\x1a"; break; default: ret.push_back(c); break; } } return ret; } // Check if string represents a number - returns true if string can be converted to double bool StringIsNumber(const std::string &s) { try { auto r = stod(s); return true; } catch (std::exception &) { return false; } } // Convert string to lowercase in-place - modifies original string void ToLowerString(std::string &s) { std::transform(s.begin(), s.end(), s.begin(), ::tolower); } // Convert string to uppercase in-place - modifies original string void ToUpperString(std::string &s) { std::transform(s.begin(), s.end(), s.begin(), ::toupper); } // Join vector of strings with delimiter - concatenates strings with separator std::string JoinString(const std::vector& ar, const std::string &delim) { std::string ret; for (size_t i = 0; i < ar.size(); ++i) { if (i != 0) { ret += delim; } ret += ar[i]; } return ret; } // Find and replace all occurrences in string - replaces search string with replacement string void find_replace(std::string &string_subject, const std::string &search_string, const std::string &replace_string) { if (string_subject.find(search_string) == std::string::npos) { return; } size_t start_pos = 0; while((start_pos = string_subject.find(search_string, start_pos)) != std::string::npos) { string_subject.replace(start_pos, search_string.length(), replace_string); start_pos += replace_string.length(); } } // Parse account string format - extracts account and login server from colon-separated string void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver) { auto split = SplitString(s, ':'); if (split.size() == 2) { loginserver = split[0]; account = split[1]; } else if(split.size() == 1) { account = split[0]; } } // String copy with null termination - copies string ensuring null termination char* strn0cpy(char* dest, const char* source, std::uint32_t size) { if (!dest) return 0; if (size == 0 || source == 0) { dest[0] = 0; return dest; } strncpy(dest, source, size); dest[size - 1] = 0; return dest; } // String copy with truncation check - copies string and returns whether it was truncated bool strn0cpyt(char* dest, const char* source, std::uint32_t size) { if (!dest) return 0; if (size == 0 || source == 0) { dest[0] = 0; return false; } strncpy(dest, source, size); dest[size - 1] = 0; return (bool)(source[strlen(dest)] == 0); } // Convert string to lowercase using static buffer - returns pointer to lowercase string const char *MakeLowerString(const char *source) { static char str[128]; if (!source) return nullptr; MakeLowerString(source, str); return str; } // Convert string to lowercase into target buffer - writes lowercase string to target void MakeLowerString(const char *source, char *target) { if (!source || !target) { *target = 0; return; } while (*source) { *target = tolower(*source); target++; source++; } *target = 0; } // Allocate and format string of any length - dynamically allocates buffer for formatted string int MakeAnyLenString(char** ret, const char* format, ...) { int buf_len = 128; int chars = -1; va_list argptr, tmpargptr; va_start(argptr, format); while (chars == -1 || chars >= buf_len) { delete[] *ret; if (chars == -1) buf_len *= 2; else buf_len = chars + 1; *ret = new char[buf_len]; va_copy(tmpargptr, argptr); chars = vsnprintf(*ret, buf_len, format, tmpargptr); } va_end(argptr); return chars; } // Append formatted string to existing buffer - extends buffer and appends formatted text std::uint32_t AppendAnyLenString(char** ret, std::uint32_t* bufsize, std::uint32_t* strlen, const char* format, ...) { if (*bufsize == 0) *bufsize = 256; if (*ret == 0) *strlen = 0; int chars = -1; char* oldret = 0; va_list argptr, tmpargptr; va_start(argptr, format); while (chars == -1 || chars >= (int32_t)(*bufsize - *strlen)) { if (chars == -1) *bufsize += 256; else *bufsize += chars + 25; oldret = *ret; *ret = new char[*bufsize]; if (oldret) { if (*strlen) memcpy(*ret, oldret, *strlen); delete[] oldret; } va_copy(tmpargptr, argptr); chars = vsnprintf(&(*ret)[*strlen], (*bufsize - *strlen), format, tmpargptr); } va_end(argptr); *strlen += chars; return *strlen; } // Convert hexadecimal string to integer - parses hex string to 32-bit unsigned integer std::uint32_t hextoi(const char* num) { if (num == nullptr) return 0; int len = strlen(num); if (len < 3) return 0; if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X')) return 0; std::uint32_t ret = 0; int mul = 1; for (int i = len - 1; i >= 2; i--) { if (num[i] >= 'A' && num[i] <= 'F') ret += ((num[i] - 'A') + 10) * mul; else if (num[i] >= 'a' && num[i] <= 'f') ret += ((num[i] - 'a') + 10) * mul; else if (num[i] >= '0' && num[i] <= '9') ret += (num[i] - '0') * mul; else return 0; mul *= 16; } return ret; } // Convert hexadecimal string to 64-bit integer - parses hex string to 64-bit unsigned integer std::uint64_t hextoi64(const char* num) { if (num == nullptr) return 0; int len = strlen(num); if (len < 3) return 0; if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X')) return 0; std::uint64_t ret = 0; int mul = 1; for (int i = len - 1; i >= 2; i--) { if (num[i] >= 'A' && num[i] <= 'F') ret += ((num[i] - 'A') + 10) * mul; else if (num[i] >= 'a' && num[i] <= 'f') ret += ((num[i] - 'a') + 10) * mul; else if (num[i] >= '0' && num[i] <= '9') ret += (num[i] - '0') * mul; else return 0; mul *= 16; } return ret; } // Convert string to boolean - parses various boolean representations to bool bool atobool(const char* iBool) { if (iBool == nullptr) return false; if (!strcasecmp(iBool, "true")) return true; if (!strcasecmp(iBool, "false")) return false; if (!strcasecmp(iBool, "yes")) return true; if (!strcasecmp(iBool, "no")) return false; if (!strcasecmp(iBool, "on")) return true; if (!strcasecmp(iBool, "off")) return false; if (!strcasecmp(iBool, "enable")) return true; if (!strcasecmp(iBool, "disable")) return false; if (!strcasecmp(iBool, "enabled")) return true; if (!strcasecmp(iBool, "disabled")) return false; if (!strcasecmp(iBool, "y")) return true; if (!strcasecmp(iBool, "n")) return false; if (atoi(iBool)) return true; return false; } // Clean mob name for display - removes non-alphabetic characters and converts underscores to spaces char *CleanMobName(const char *in, char *out) { unsigned i, j; for (i = j = 0; i < strlen(in); i++) { // Convert _ to space - other conversions may be added here if (in[i] == '_') { out[j++] = ' '; } else { // Only keep alphabetic characters and backticks - skip numbers and other characters if (isalpha(in[i]) || (in[i] == '`')) out[j++] = in[i]; } } out[j] = 0; // Terminate the string before returning return out; } // Remove apostrophes from string in-place - replaces apostrophes with underscores void RemoveApostrophes(std::string &s) { for (unsigned int i = 0; i < s.length(); ++i) if (s[i] == '\'') s[i] = '_'; } // Remove apostrophes from C string - creates new string with apostrophes replaced by underscores char *RemoveApostrophes(const char *s) { auto NewString = new char[strlen(s) + 1]; strcpy(NewString, s); for (unsigned int i = 0; i < strlen(NewString); ++i) if (NewString[i] == '\'') NewString[i] = '_'; return NewString; } // Convert integer to string - formats integer as string in provided buffer const char *ConvertArray(int input, char *returnchar) { sprintf(returnchar, "%i", input); return returnchar; } // Convert float to string - formats float as string with 2 decimal places in provided buffer const char *ConvertArrayF(float input, char *returnchar) { sprintf(returnchar, "%0.2f", input); return returnchar; } // Check if string contains only alphanumeric characters - returns true if all characters are letters or digits bool isAlphaNumeric(const char *text) { for (unsigned int charIndex = 0; charIndex < strlen(text); charIndex++) { if ((text[charIndex] < 'a' || text[charIndex] > 'z') && (text[charIndex] < 'A' || text[charIndex] > 'Z') && (text[charIndex] < '0' || text[charIndex] > '9')) return false; } return true; } // Inline utility functions for string trimming // Trim whitespace from left side of string - removes leading whitespace characters inline std::string <rim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { str.erase(0, str.find_first_not_of(chars)); return str; } // Trim whitespace from right side of string - removes trailing whitespace characters inline std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { str.erase(str.find_last_not_of(chars) + 1); return str; } // Trim whitespace from both sides of string - removes leading and trailing whitespace inline std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r ") { return ltrim(rtrim(str, chars), chars); } // Template function to join vector elements with encapsulation - joins elements with glue and wraps each in encapsulation characters template std::string implode(const std::string &glue, const std::pair &encapsulation, const std::vector &src) { if (src.empty()) { return {}; } std::ostringstream oss; for (const T &src_iter : src) { oss << encapsulation.first << src_iter << encapsulation.second << glue; } std::string output(oss.str()); output.resize(output.size() - glue.size()); return output; } // Template function to join vector of pairs - formats pairs with encapsulation and glue template std::vector join_pair(const std::string &glue, const std::pair &encapsulation, const std::vector> &src) { if (src.empty()) { return {}; } std::vector output; for (const std::pair &src_iter : src) { output.push_back( std::format( "{}{}{}{}{}{}{}", encapsulation.first, src_iter.first, encapsulation.second, glue, encapsulation.first, src_iter.second, encapsulation.second ) ); } return output; } // Template function to join vector of tuples - formats 4-tuples with encapsulation and glue template std::vector join_tuple(const std::string &glue, const std::pair &encapsulation, const std::vector> &src) { if (src.empty()) { return {}; } std::vector output; for (const std::tuple &src_iter : src) { output.push_back( std::format( "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", encapsulation.first, std::get<0>(src_iter), encapsulation.second, glue, encapsulation.first, std::get<1>(src_iter), encapsulation.second, glue, encapsulation.first, std::get<2>(src_iter), encapsulation.second, glue, encapsulation.first, std::get<3>(src_iter), encapsulation.second ) ); } return output; }