squall/storm/String.cpp

719 lines
14 KiB
C++
Raw Normal View History

2020-11-01 17:45:45 -06:00
#include "storm/String.hpp"
#include "storm/Error.hpp"
#include <bc/Memory.hpp>
2020-11-14 17:18:49 -06:00
#include "storm/string/bjhash.hpp"
2020-11-16 18:41:53 -06:00
#include <cctype>
2020-11-21 14:05:13 -06:00
#include <cmath>
2020-11-21 21:02:01 -06:00
#include <cstdarg>
#include <cstdio>
2020-11-14 17:58:34 -06:00
#include <cstring>
#include <algorithm>
2020-12-02 20:04:02 -06:00
#if defined(WHOA_SYSTEM_WIN)
#include <string.h>
#endif
2020-12-02 20:04:02 -06:00
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
2020-11-15 12:47:41 -06:00
#include <strings.h>
#endif
2020-11-14 17:18:49 -06:00
uint8_t bytesFromUTF8[256] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6
};
uint32_t offsetsFromUTF8[8] = {
0,
0,
0x3080,
0x0E2080,
0x3C82080,
0x0FA082080,
0x82082080,
0
};
2020-11-21 14:05:13 -06:00
int32_t s_initialized;
double s_realDigit[20][10];
2020-11-14 17:18:49 -06:00
void GetNextTextUpper(uint32_t* orig, const char** string, uint32_t* upper) {
uint8_t byte = **string;
int32_t v3 = bytesFromUTF8[byte];
*orig = 0;
*upper = 0;
switch (v3) {
case 6:
case 5:
case 4:
case 3:
case 2:
*orig += **string;
(*string)++;
if (!**string) {
return;
}
*orig <<= 6;
case 1:
*orig += **string;
(*string)++;
default:
*orig -= offsetsFromUTF8[v3];
if (*orig > 0xFFFF) {
*orig = 0xFFFF;
}
uint32_t v4 = *orig;
bool v5, v6;
if (v3 == 1) {
if (v4 < 0x61) {
*upper = v4;
return;
}
v5 = v4 < 0x7A;
v6 = v4 == 122;
if (!v5 && !v6) {
*upper = v4;
return;
}
v4 -= 32;
*upper = v4;
return;
}
if (v3 != 2) {
*upper = v4;
return;
}
if (v4 >= 0xE0 && v4 <= 0xFE) {
v4 -= 32;
*upper = v4;
return;
}
if (v4 == 339) {
*upper = 338;
return;
}
if (v4 == 1105) {
*upper = 1025;
return;
}
if (v4 >= 0x430) {
v5 = v4 < 0x44F;
v6 = v4 == 1103;
if (!v5 && !v6) {
*upper = v4;
return;
}
v4 -= 32;
*upper = v4;
return;
}
*upper = v4;
return;
}
}
2020-09-08 21:37:30 -05:00
2020-11-21 14:05:13 -06:00
void InitializeFloatDigits() {
for (int32_t i = -1; i > -21; i--) {
for (int32_t j = 0; j < 10; j++) {
double v3 = 10.0;
int32_t v4 = i < 0 ? -i : i;
double v5 = 1.0;
while (true) {
if (v4 & 1) {
v5 *= v3;
}
v4 >>= 1;
if (!v4) {
break;
}
v3 *= v3;
}
double v6 = i < 0 ? 1.0 / v5 : v5;
double v7 = v6 * static_cast<double>(j);
s_realDigit[-i - 1][j] = v7;
}
}
}
2020-11-21 21:02:01 -06:00
size_t ISStrVPrintf(const char* format, va_list va, char* dest, size_t maxchars) {
if (!maxchars) {
return 0;
}
size_t result;
if (maxchars == STORM_MAX_STR) {
// TODO conditional vsoprintf;
result = vsprintf(dest, format, va);
} else {
// TODO conditional vsnoprintf;
result = vsnprintf(dest, maxchars, format, va);
if (result >= maxchars) {
result = maxchars - 1;
dest[result] = '\0';
}
}
return result;
}
2020-11-21 14:05:13 -06:00
void SStrInitialize() {
if (!s_initialized) {
InitializeFloatDigits();
s_initialized = 1;
}
}
char* SStrChr(char* string, char search) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
if (!*string) {
return nullptr;
}
while (*string != search) {
string++;
if (!*string) {
return nullptr;
}
}
return string;
}
2020-11-21 12:11:01 -06:00
const char* SStrChr(const char* string, char search) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2020-11-21 12:11:01 -06:00
if (!*string) {
return nullptr;
}
while (*string != search) {
string++;
if (!*string) {
return nullptr;
}
}
return string;
}
char* SStrChrR(char* string, char search) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
char* result;
for (result = nullptr; *string; string++) {
if (*string == search) {
result = string;
}
}
return result;
}
2020-11-21 12:49:47 -06:00
const char* SStrChrR(const char* string, char search) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2020-11-21 12:49:47 -06:00
const char* result;
for (result = nullptr; *string; string++) {
if (*string == search) {
result = string;
}
}
return result;
}
2020-11-14 17:58:34 -06:00
int32_t SStrCmp(const char* string1, const char* string2, size_t maxchars) {
return strncmp(string1, string2, maxchars);
}
2020-11-15 12:47:41 -06:00
int32_t SStrCmpI(const char* string1, const char* string2, size_t maxchars) {
2020-12-02 20:04:02 -06:00
#if defined(WHOA_SYSTEM_WIN)
return _strnicmp(string1, string2, maxchars);
#endif
2020-12-02 20:04:02 -06:00
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
2020-11-15 12:47:41 -06:00
return strncasecmp(string1, string2, maxchars);
#endif
2020-11-15 12:47:41 -06:00
}
2020-09-08 21:37:30 -05:00
size_t SStrCopy(char* dest, const char* source, size_t destsize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(dest);
STORM_VALIDATE(source);
STORM_VALIDATE_END;
2020-09-08 21:37:30 -05:00
char* destbuf = dest;
if (destsize == STORM_MAX_STR) {
2020-09-08 21:37:30 -05:00
while (*source) {
*destbuf = *source;
++destbuf;
++source;
}
} else {
if (*source) {
while (destbuf < &dest[destsize - 1]) {
*destbuf = *source;
++destbuf;
++source;
if (!*source) {
*destbuf = '\0';
return static_cast<size_t>(destbuf - dest);
}
}
}
}
*destbuf = '\0';
return static_cast<size_t>(destbuf - dest);
}
2020-11-14 17:18:49 -06:00
size_t SStrNCopy(char* dest, const char* source, size_t maxchars, size_t destsize) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(dest);
STORM_VALIDATE(source);
STORM_VALIDATE_END;
auto length = strnlen(source, maxchars);
if (destsize) {
auto count = std::min(length, destsize - 1);
memcpy(dest, source, count);
dest[count] = '\0';
}
return length;
}
2020-11-15 13:09:14 -06:00
char* SStrDupA(const char* string, const char* filename, uint32_t linenumber) {
size_t len = SStrLen(string) + 1;
char* dup = static_cast<char*>(SMemAlloc(len, filename, linenumber, 0x0));
memcpy(dup, string, len);
return dup;
}
2020-11-14 17:18:49 -06:00
uint32_t SStrHashHT(const char* string) {
char normalized[0x400];
char* buf = normalized;
uint32_t length = 0;
if (*string) {
uint32_t value, orig, upper;
while (*string && length <= 0x3FB) {
// Convert each character to uppercase
GetNextTextUpper(&orig, &string, &upper);
// Replace forward slash with back slash
value = upper == '/' ? '\\' : upper;
while (value) {
*buf = value;
value >>= 8;
length++;
buf++;
}
}
}
// Ensure string is terminated
*buf = 0;
return bjhash((uint8_t*)&normalized, length, 0);
}
2020-11-15 12:57:32 -06:00
size_t SStrLen(const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2020-11-15 12:57:32 -06:00
2020-11-16 23:34:36 -06:00
auto stringEnd = string;
while (*stringEnd) {
stringEnd++;
}
return stringEnd - string;
2020-11-15 12:57:32 -06:00
}
2020-11-16 17:44:08 -06:00
2020-11-16 18:41:53 -06:00
void SStrLower(char* string) {
2020-11-16 23:32:34 -06:00
while (*string) {
*string = static_cast<char>(tolower(*string));
string++;
2020-11-16 18:41:53 -06:00
}
}
2020-11-21 15:03:44 -06:00
uint32_t SStrPack(char* dest, const char* source, uint32_t destsize) {
STORM_ASSERT(dest);
STORM_ASSERT(source);
if (!destsize) {
return 0;
}
char* i;
const char* v5;
char v6;
const char* j;
for (i = dest; *i; i++)
;
if (destsize == STORM_MAX_STR) {
v6 = *source;
for (j = source; *j; i++) {
j++;
*i = v6;
v6 = *j;
}
} else {
v5 = source;
if (*source) {
while (i < &dest[destsize - 1]) {
*i++ = *v5++;
if (!*v5) {
*i = '\0';
return static_cast<uint32_t>(i - dest);
2020-11-21 15:03:44 -06:00
}
}
}
}
*i = '\0';
return static_cast<uint32_t>(i - dest);
2020-11-21 15:03:44 -06:00
}
2020-11-21 21:02:01 -06:00
size_t SStrPrintf(char* dest, size_t maxchars, const char* format, ...) {
va_list va;
va_start(va, format);
STORM_ASSERT(dest);
STORM_ASSERT(format);
return ISStrVPrintf(format, va, dest, maxchars);
}
2020-11-16 17:44:08 -06:00
const char* SStrStr(const char* string, const char* search) {
STORM_ASSERT(string);
STORM_ASSERT(search);
2020-11-16 23:04:32 -06:00
if (!*string) {
2020-11-16 17:44:08 -06:00
return nullptr;
}
2020-11-16 23:04:32 -06:00
auto searchEnd = search;
while (*searchEnd) {
searchEnd++;
}
size_t searchLength = searchEnd - search;
auto substring = string;
while (SStrCmp(substring, search, searchLength)) {
2020-11-16 17:44:08 -06:00
substring++;
if (!*substring) {
return nullptr;
}
2020-11-16 17:44:08 -06:00
}
return substring;
}
2020-11-21 13:14:15 -06:00
2020-11-21 20:44:37 -06:00
void SStrTokenize(const char** string, char* buffer, size_t bufferchars, const char* whitespace, int32_t* quoted) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE(*string);
STORM_VALIDATE(buffer || !bufferchars);
STORM_VALIDATE(whitespace);
STORM_VALIDATE_END_VOID;
2020-11-21 20:44:37 -06:00
int32_t inquotes = 0;
int32_t usedquotes = 0;
auto curstring = *string;
auto v17 = false;
for (const char* w = whitespace; w && *w; w++) {
if (*w == '"') {
v17 = true;
break;
}
}
while (*curstring && SStrChr(whitespace, *curstring)) {
if (v17 && *curstring == '"') {
inquotes = 1;
usedquotes = 1;
curstring++;
break;
}
curstring++;
}
uint32_t bufferlen = 0;
if (*curstring) {
auto curbuffer = buffer;
while (v17 && *curstring == '"') {
if (bufferlen && !inquotes) {
goto LABEL_35;
}
curstring++;
usedquotes = 1;
inquotes = inquotes == 0;
if (!inquotes) {
goto LABEL_35;
}
LABEL_32:
if (!*curstring) {
goto LABEL_35;
}
}
if (inquotes) {
LABEL_29:
if (curbuffer - buffer < bufferchars) {
bufferlen++;
*curbuffer = *curstring;
curbuffer++;
}
curstring++;
goto LABEL_32;
}
auto v14 = SStrChr(whitespace, *curstring);
if (!v14) {
goto LABEL_29;
}
curstring++;
}
LABEL_35:
if (bufferlen < bufferchars) {
buffer[bufferlen] = 0;
}
*string = curstring;
if (quoted) {
*quoted = usedquotes;
}
}
2020-11-21 14:05:13 -06:00
float SStrToFloat(const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2020-11-21 14:05:13 -06:00
SStrInitialize();
double result;
bool negative = false;
2020-11-21 14:05:13 -06:00
if (*string == '-') {
negative = true;
string++;
}
double v16 = 10.0;
double v4 = 0.0;
uint32_t v5 = *string - '0';
const char* v6 = string;
if (v5 >= 10) {
v5 = 0;
result = static_cast<double>(v5);
} else {
string++;
uint32_t v8 = *string - '0';
if (v8 >= 10) {
result = static_cast<double>(v5);
} else {
do {
v5 = v8 + 10 * v5;
string++;
if (v5 >= 0x19999999) {
v4 = v4 * pow(10.0, string - v6) + static_cast<double>(v5);
v5 = 0;
v6 = string;
}
v8 = *string - '0';
} while (v8 < 10);
if (v4 == 0.0) {
result = static_cast<double>(v5);
} else {
result = pow(10.0, string - v6) * v4 + static_cast<double>(v5);
}
}
}
if (*string == '.') {
string++;
uint32_t v23 = *string - '0';
int32_t v24 = 0;
if (v23 < 10) {
int32_t v26 = -1;
double v31;
do {
string++;
if (v24 < 20) {
v31 = s_realDigit[v24][v23];
2020-11-21 14:05:13 -06:00
} else {
v31 = pow(v16, v26) * v23;
}
result += v31;
v23 = *string - '0';
v24++;
v26--;
} while (v23 < 10);
}
}
if (*string == 'e' || *string == 'E') {
const char* v32 = string + 1;
if (*v32 == '+') {
v32++;
}
result *= pow(10.0, SStrToInt(v32));
}
if (negative) {
result = -result;
}
return static_cast<float>(result);
}
2020-11-21 13:14:15 -06:00
int32_t SStrToInt(const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2020-11-21 13:14:15 -06:00
int32_t result = 0;
bool negative = false;
if (*string == '-') {
negative = true;
string++;
}
uint32_t digit;
while ((digit = *string - '0') < 10) {
result = digit + (10 * result);
string++;
}
if (negative) {
result = -result;
}
return result;
}
2021-02-13 18:51:47 -06:00
2024-12-24 14:08:06 -05:00
uint32_t SStrToUnsigned(const char* string) {
STORM_VALIDATE_BEGIN;
STORM_VALIDATE(string);
STORM_VALIDATE_END;
2024-12-24 14:08:06 -05:00
uint32_t result = 0;
uint32_t digit;
while ((digit = *string - '0') < 10) {
result = digit + (10 * result);
string++;
}
return result;
}
2021-02-13 18:51:47 -06:00
void SStrUpper(char* string) {
while (*string) {
*string = static_cast<char>(toupper(*string));
string++;
}
}