249 lines
6.7 KiB
C++
249 lines
6.7 KiB
C++
wchar_t ToLowerCase(wchar_t a) {
|
|
if (a >= 'A' && a <= 'Z') a += 32;
|
|
return a;
|
|
}
|
|
|
|
wchar_t ToUpperCase(wchar_t a) {
|
|
if (a >= 'a' && a <= 'z') a -= 32;
|
|
return a;
|
|
}
|
|
|
|
bool IsWhitespace(wchar_t w) {
|
|
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
|
return result;
|
|
}
|
|
|
|
bool IsSymbol(wchar_t w) {
|
|
bool result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
|
return result;
|
|
}
|
|
|
|
bool IsNonWord(wchar_t w) {
|
|
if (w == '_') return false;
|
|
bool result = IsSymbol(w) || IsWhitespace(w);
|
|
return result;
|
|
}
|
|
|
|
bool IsWord(wchar_t w) {
|
|
bool result = !IsNonWord(w);
|
|
return result;
|
|
}
|
|
|
|
bool IsLoadWord(wchar_t w) {
|
|
bool result = w == '/' || w == '\\' || w == ':' || w == '*' || w == '_' || w == '.' || w == '-';
|
|
if (!result) {
|
|
result = !(IsSymbol(w) || IsWhitespace(w));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool IsAlphabetic(wchar_t a) {
|
|
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
|
return result;
|
|
}
|
|
|
|
bool IsIdent(wchar_t a) {
|
|
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
|
return result;
|
|
}
|
|
|
|
bool IsDigit(wchar_t a) {
|
|
bool result = a >= '0' && a <= '9';
|
|
return result;
|
|
}
|
|
|
|
bool IsAlphanumeric(wchar_t a) {
|
|
bool result = IsDigit(a) || IsAlphabetic(a);
|
|
return result;
|
|
}
|
|
|
|
bool AreEqual(String16 a, String16 b, unsigned ignore_case = false) {
|
|
if (a.len != b.len) return false;
|
|
for (int64_t i = 0; i < a.len; i++) {
|
|
wchar_t A = a.data[i];
|
|
wchar_t B = b.data[i];
|
|
if (ignore_case) {
|
|
A = ToLowerCase(A);
|
|
B = ToLowerCase(B);
|
|
}
|
|
if (A != B)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
inline bool operator==(String16 a, String16 b) { return AreEqual(a, b); }
|
|
inline bool operator!=(String16 a, String16 b) { return !AreEqual(a, b); }
|
|
|
|
String16 Merge(Allocator allocator, Array<String16> list, String16 separator = " ") {
|
|
int64_t char_count = 0;
|
|
For(list) char_count += it.len;
|
|
if (char_count == 0) return {};
|
|
int64_t node_count = list.len;
|
|
|
|
int64_t base_size = (char_count + 1);
|
|
int64_t sep_size = (node_count - 1) * separator.len;
|
|
int64_t size = base_size + sep_size;
|
|
wchar_t *buff = (wchar_t *)AllocSize(allocator, sizeof(wchar_t) * (size + 1));
|
|
String16 string = {buff, 0};
|
|
For(list) {
|
|
Assert(string.len + it.len <= size);
|
|
memcpy(string.data + string.len, it.data, it.len * sizeof(wchar_t));
|
|
string.len += it.len;
|
|
if (!IsLast(list, it)) {
|
|
memcpy(string.data + string.len, separator.data, separator.len * sizeof(wchar_t));
|
|
string.len += separator.len;
|
|
}
|
|
}
|
|
Assert(string.len == size - 1);
|
|
string.data[size] = 0;
|
|
return string;
|
|
}
|
|
|
|
bool Seek(String16 string, String16 find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None) {
|
|
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
|
|
bool result = false;
|
|
if (flags & SeekFlag_MatchFindLast) {
|
|
for (int64_t i = string.len; i != 0; i--) {
|
|
int64_t index = i - 1;
|
|
String16 substring = GetSlice(string, index, index + find.len);
|
|
if (AreEqual(substring, find, ignore_case)) {
|
|
if (index_out)
|
|
*index_out = index;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
for (int64_t i = 0; i < string.len; i++) {
|
|
String16 substring = GetSlice(string, i, i + find.len);
|
|
if (AreEqual(substring, find, ignore_case)) {
|
|
if (index_out)
|
|
*index_out = i;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
String16 ChopLastSlash(String16 s) {
|
|
String16 result = s;
|
|
Seek(s, L"/", &result.len, SeekFlag_MatchFindLast);
|
|
return result;
|
|
}
|
|
|
|
String16 ChopLastPeriod(String16 s) {
|
|
String16 result = s;
|
|
Seek(s, L".", &result.len, SeekFlag_MatchFindLast);
|
|
return result;
|
|
}
|
|
|
|
String16 SkipToLastSlash(String16 s) {
|
|
int64_t pos;
|
|
String16 result = s;
|
|
if (Seek(s, L"/", &pos, SeekFlag_MatchFindLast)) {
|
|
result = Skip(result, pos + 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String16 SkipToLastPeriod(String16 s) {
|
|
int64_t pos;
|
|
String16 result = s;
|
|
if (Seek(s, L".", &pos, SeekFlag_MatchFindLast)) {
|
|
result = Skip(result, pos + 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String16 CutPrefix(String16 *string, int64_t len) {
|
|
String16 result = GetPrefix(*string, len);
|
|
*string = Skip(*string, len);
|
|
return result;
|
|
}
|
|
|
|
String16 CutPostfix(String16 *string, int64_t len) {
|
|
String16 result = GetPostfix(*string, len);
|
|
*string = Chop(*string, len);
|
|
return result;
|
|
}
|
|
|
|
String16 Trim(String16 string) {
|
|
if (string.len == 0)
|
|
return string;
|
|
|
|
int64_t whitespace_begin = 0;
|
|
for (; whitespace_begin < string.len; whitespace_begin++) {
|
|
if (!IsWhitespace(string.data[whitespace_begin])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
int64_t whitespace_end = string.len;
|
|
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
|
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (whitespace_begin == whitespace_end) {
|
|
string.len = 0;
|
|
} else {
|
|
string = GetSlice(string, whitespace_begin, whitespace_end);
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
String16 TrimEnd(String16 string) {
|
|
int64_t whitespace_end = string.len;
|
|
for (; whitespace_end != 0; whitespace_end--) {
|
|
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
String16 result = GetPrefix(string, whitespace_end);
|
|
return result;
|
|
}
|
|
|
|
bool EndsWith(String16 a, String16 end, unsigned ignore_case = false) {
|
|
String16 a_end = GetPostfix(a, end.len);
|
|
bool result = AreEqual(end, a_end, ignore_case);
|
|
return result;
|
|
}
|
|
|
|
bool StartsWith(String16 a, String16 start, unsigned ignore_case = false) {
|
|
String16 a_start = GetPrefix(a, start.len);
|
|
bool result = AreEqual(start, a_start, ignore_case);
|
|
return result;
|
|
}
|
|
|
|
// chop this - :324
|
|
String16 ChopNumberEx(String16 *string) {
|
|
String16 col = {};
|
|
for (int64_t i = string->len - 1; i >= 0; i -= 1) {
|
|
if (IsDigit(string->data[i])) {
|
|
col.data = string->data + i;
|
|
col.len += 1;
|
|
} else if (string->data[i] == L':') {
|
|
break;
|
|
} else {
|
|
return {};
|
|
}
|
|
}
|
|
*string = Chop(*string, col.len + 1);
|
|
return col;
|
|
}
|
|
|
|
Int ChopNumber(String16 *string) {
|
|
Scratch scratch;
|
|
String16 col = ChopNumberEx(string);
|
|
if (col.len == 0) return -1;
|
|
String num_string = ToString(scratch, col);
|
|
Int result = strtoll(num_string.data, NULL, 10) - 1;
|
|
return result;
|
|
}
|