| 1 | #include "Library/Base/StringUtil.h" |
| 2 | |
| 3 | #include <prim/seadStringUtil.h> |
| 4 | |
| 5 | namespace al { |
| 6 | const char* createStringIfInStack(const char* str) { |
| 7 | if (!isInStack(str)) |
| 8 | return str; |
| 9 | |
| 10 | s32 len = strlen(str) + 1; |
| 11 | char* buffer = new char[len]; |
| 12 | snprintf(buffer, len, "%s" , str); |
| 13 | |
| 14 | return buffer; |
| 15 | } |
| 16 | |
| 17 | const char* createConcatString(const char* start, const char* end) { |
| 18 | s32 len = strlen(start) + strlen(end) + 1; |
| 19 | char* buffer = new char[len]; |
| 20 | snprintf(buffer, len, "%s%s" , start, end); |
| 21 | |
| 22 | return buffer; |
| 23 | } |
| 24 | |
| 25 | void createFileNameBySuffix(sead::BufferedSafeString* out, const char* name, const char* suffix) { |
| 26 | out->clear(); |
| 27 | if (!suffix) { |
| 28 | out->append(str: name); |
| 29 | return; |
| 30 | } |
| 31 | out->append(str: name); |
| 32 | out->append(str: suffix); |
| 33 | } |
| 34 | |
| 35 | u32 outputValueWithComma(char* out, u32 size, u64 value, bool usePadding, bool padToThousands) { |
| 36 | if (value > 999999999) { |
| 37 | return sead::StringUtil::snprintf(s: out, n: size, format: "%3d,%03d,%03d,%03d" , |
| 38 | (u32)(value / 1000000000), (u32)(value / 1000000 % 1000), |
| 39 | (u32)(value / 1000 % 1000), (u32)(value % 1000)); |
| 40 | } |
| 41 | if (value > 999999) { |
| 42 | if (usePadding) { |
| 43 | return sead::StringUtil::snprintf(s: out, n: size, format: "%3d,%03d,%03d" , (u32)(value / 1000000), |
| 44 | (u32)(value / 1000 % 1000), (u32)(value % 1000)); |
| 45 | } |
| 46 | return sead::StringUtil::snprintf(s: out, n: size, format: "%d,%03d,%03d" , (u32)(value / 1000000), |
| 47 | (u32)(value / 1000 % 1000), (u32)(value % 1000)); |
| 48 | } |
| 49 | if (value > 999) { |
| 50 | if (usePadding) { |
| 51 | if (padToThousands) { |
| 52 | return sead::StringUtil::snprintf(s: out, n: size, format: "%3d,%03d" , (u32)(value / 1000), |
| 53 | (u32)(value % 1000)); |
| 54 | } |
| 55 | return sead::StringUtil::snprintf(s: out, n: size, format: " %3d,%03d" , (u32)(value / 1000), |
| 56 | (u32)(value % 1000)); |
| 57 | } |
| 58 | return sead::StringUtil::snprintf(s: out, n: size, format: "%d,%03d" , (u32)(value / 1000), |
| 59 | (u32)(value % 1000)); |
| 60 | } |
| 61 | if (usePadding) { |
| 62 | if (padToThousands) |
| 63 | return sead::StringUtil::snprintf(s: out, n: size, format: " %3d" , (u32)value); |
| 64 | return sead::StringUtil::snprintf(s: out, n: size, format: " %3d" , (u32)value); |
| 65 | } |
| 66 | return sead::StringUtil::snprintf(s: out, n: size, format: "%d" , (u32)value); |
| 67 | } |
| 68 | |
| 69 | void (char* out, const char* str, u32 len, u32 unused) { |
| 70 | strncpy(out, str, len); |
| 71 | out[len] = '\0'; |
| 72 | } |
| 73 | |
| 74 | const char* searchSubString(const char* str, const char* substr) { |
| 75 | return searchSubString(str, substr, substrLen: strlen(substr)); |
| 76 | } |
| 77 | |
| 78 | const char* searchSubString(const char* str, const char* substr, s32 substrLen) { |
| 79 | while (str[0] != '\0') { |
| 80 | s32 size = 0; |
| 81 | for (s32 index = 0; index < substrLen; index++) { |
| 82 | if (str[index] == '\0' || str[index] != substr[index]) |
| 83 | break; |
| 84 | size++; |
| 85 | } |
| 86 | |
| 87 | if (size == substrLen) |
| 88 | return str; |
| 89 | |
| 90 | str++; |
| 91 | } |
| 92 | |
| 93 | return nullptr; |
| 94 | } |
| 95 | |
| 96 | // const char* getSubStringUnmatched(const char**, const char*, const MatchStr&, |
| 97 | // void (*)(const char*, const char*, void*), void*); |
| 98 | // const char* getSubStringUnmatched(const char*, const MatchStr&); |
| 99 | // void extractBaseNameW(sead::WBufferedSafeString*, const sead::WSafeString&); |
| 100 | |
| 101 | void removeExtensionString(char* out, u32 len, const char* str) { |
| 102 | snprintf(out, len, "%s" , str); |
| 103 | char* dot = strchr(s: out, c: '.'); |
| 104 | char* dirSeparator = strchr(s: out, c: '/'); |
| 105 | |
| 106 | if (dot == nullptr || dot < dirSeparator || ++dirSeparator == dot) |
| 107 | return; |
| 108 | |
| 109 | *dot = '\0'; |
| 110 | } |
| 111 | |
| 112 | void removeStringFromEnd(char* out, u32 len, const char* end, const char* str) { |
| 113 | snprintf(out, len, "%s" , str); |
| 114 | |
| 115 | s32 lenStr = strlen(out); |
| 116 | s32 lenEnd = strlen(end); |
| 117 | |
| 118 | if (lenEnd > lenStr) |
| 119 | return; |
| 120 | |
| 121 | out[lenStr - lenEnd] = '\0'; |
| 122 | } |
| 123 | |
| 124 | void translateCharacters(char* string, const char* charmap, const char* newCharmap) { |
| 125 | while (charmap[0] != '\0') { |
| 126 | for (s32 index = 0; string[index] != '\0'; index++) |
| 127 | if (string[index] == *charmap) |
| 128 | string[index] = *newCharmap; |
| 129 | |
| 130 | newCharmap++; |
| 131 | charmap++; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // void tryReplaceString(sead::BufferedSafeString*, const char*, const char*); |
| 136 | // void tryReplaceString(sead::BufferedSafeString*, const char*, const char*, const char*); |
| 137 | // void tryReplaceStringNoRecursive(sead::BufferedSafeString*, const char*, const char*, |
| 138 | // const char*); |
| 139 | |
| 140 | bool isEqualString(const char16* str1, const char16* str2) { |
| 141 | while (*str1 == *str2) { |
| 142 | char16 val = *str1; |
| 143 | |
| 144 | if (!val) |
| 145 | return true; |
| 146 | |
| 147 | str2++; |
| 148 | str1++; |
| 149 | } |
| 150 | |
| 151 | return false; |
| 152 | } |
| 153 | |
| 154 | bool isEqualSubString(const char* str, const char* subStr) { |
| 155 | return strstr(s1: str, s2: subStr) != nullptr; |
| 156 | } |
| 157 | |
| 158 | bool isEqualSubString(const sead::SafeString& str, const sead::SafeString& subStr) { |
| 159 | return isEqualSubString(str: str.cstr(), subStr: subStr.cstr()); |
| 160 | } |
| 161 | |
| 162 | bool isStartWithString(const char* str, const char* start) { |
| 163 | if (*start == '\0') |
| 164 | return true; |
| 165 | |
| 166 | while (*str != '\0' && *str == *start) { |
| 167 | str++; |
| 168 | start++; |
| 169 | |
| 170 | if (*start == '\0') |
| 171 | return true; |
| 172 | } |
| 173 | |
| 174 | return false; |
| 175 | } |
| 176 | |
| 177 | bool isEndWithString(const char* str, const char* end) { |
| 178 | s32 lenStr = strlen(str); |
| 179 | s32 lenEnd = strlen(end); |
| 180 | |
| 181 | if (lenStr < lenEnd) |
| 182 | return false; |
| 183 | |
| 184 | return isEqualString(str1: &str[lenStr - lenEnd], str2: end); |
| 185 | } |
| 186 | |
| 187 | // bool isMatchString(const char*, const MatchStr&); |
| 188 | |
| 189 | s32 compareStringIgnoreCase(const char* str1, const char* str2) { |
| 190 | return strcasecmp(str1, str2); |
| 191 | } |
| 192 | |
| 193 | // void makeUrlEncodeString(char*, u32, const char*); |
| 194 | // void makeUrlDecodeString(char*, u32, const char*); |
| 195 | |
| 196 | void copyString(char* out, const char* str, u32 len) { |
| 197 | strncpy(out, str, len); |
| 198 | } |
| 199 | |
| 200 | void copyStringW(char16* out, const char16* str, u32 len) { |
| 201 | sead::StringUtil::wcs16cpy(out, n: len, str); |
| 202 | } |
| 203 | |
| 204 | // bool isInStack(const void*); |
| 205 | |
| 206 | // Attr required for isEndWithString |
| 207 | __attribute__((noinline)) bool isEqualString(const char* str1, const char* str2) { |
| 208 | while (*str1 == *str2) { |
| 209 | char val = *str1; |
| 210 | |
| 211 | if (!val) |
| 212 | return true; |
| 213 | |
| 214 | str2++; |
| 215 | str1++; |
| 216 | } |
| 217 | |
| 218 | return false; |
| 219 | } |
| 220 | |
| 221 | bool isEqualString(const sead::SafeString& safestr1, const sead::SafeString& safestr2) { |
| 222 | const char* str1 = safestr1.cstr(); |
| 223 | const char* str2 = safestr2.cstr(); |
| 224 | while (*str1 == *str2) { |
| 225 | char val = *str1; |
| 226 | |
| 227 | if (!val) |
| 228 | return true; |
| 229 | |
| 230 | str2++; |
| 231 | str1++; |
| 232 | } |
| 233 | |
| 234 | return false; |
| 235 | } |
| 236 | |
| 237 | bool isEqualStringCase(const char* str1, const char* str2) { |
| 238 | return compareStringIgnoreCase(str1, str2) == 0; |
| 239 | } |
| 240 | |
| 241 | bool isEqualStringCase(const sead::SafeString& str1, const sead::SafeString& str2) { |
| 242 | return isEqualStringCase(str1: str1.cstr(), str2: str2.cstr()); |
| 243 | } |
| 244 | } // namespace al |
| 245 | |