mirror of
https://github.com/Ed94/metadesk.git
synced 2026-06-12 23:51:37 -07:00
progress on strings (currently on basic text and escapes)
This commit is contained in:
+455
-282
@@ -1,5 +1,7 @@
|
||||
#ifdef INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "macros.h"
|
||||
# include "debug.h"
|
||||
# include "strings.h"
|
||||
# include "thread_context.h"
|
||||
#endif
|
||||
@@ -1217,337 +1219,508 @@ utf16_encode(U16 *str, U32 codepoint) {
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8
|
||||
str8_from_16(Arena *arena, String16 in){
|
||||
U64 cap = in.size*3;
|
||||
U8 *str = push_array_no_zero(arena, U8, cap + 1);
|
||||
U16 *ptr = in.str;
|
||||
U16 *opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc){
|
||||
consume = utf16_decode(ptr, opl - ptr);
|
||||
size += utf8_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size));
|
||||
return(str8(str, size));
|
||||
String8
|
||||
str8_from_16(Arena* arena, String16 in) {
|
||||
U64 cap = in.size * 3;
|
||||
U8* str = push_array_no_zero(arena, U8, cap + 1);
|
||||
U16* ptr = in.str;
|
||||
U16* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc) {
|
||||
consume = utf16_decode(ptr, opl - ptr);
|
||||
size += utf8_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size));
|
||||
return(str8(str, size));
|
||||
}
|
||||
|
||||
internal String16
|
||||
str16_from_8(Arena *arena, String8 in){
|
||||
U64 cap = in.size*2;
|
||||
U16 *str = push_array_no_zero(arena, U16, cap + 1);
|
||||
U8 *ptr = in.str;
|
||||
U8 *opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc){
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
size += utf16_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size)*2);
|
||||
return(str16(str, size));
|
||||
String16
|
||||
str16_from_8(Arena* arena, String8 in) {
|
||||
U64 cap = in.size * 2;
|
||||
U16* str = push_array_no_zero(arena, U16, cap + 1);
|
||||
U8* ptr = in.str;
|
||||
U8* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc) {
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
size += utf16_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size)*2);
|
||||
return(str16(str, size));
|
||||
}
|
||||
|
||||
internal String8
|
||||
String8
|
||||
str8_from_32(Arena *arena, String32 in){
|
||||
U64 cap = in.size*4;
|
||||
U8 *str = push_array_no_zero(arena, U8, cap + 1);
|
||||
U32 *ptr = in.str;
|
||||
U32 *opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
for (;ptr < opl; ptr += 1){
|
||||
size += utf8_encode(str + size, *ptr);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size));
|
||||
return(str8(str, size));
|
||||
U64 cap = in.size * 4;
|
||||
U8* str = push_array_no_zero(arena, U8, cap + 1);
|
||||
U32* ptr = in.str;
|
||||
U32* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
for (;ptr < opl; ptr += 1){
|
||||
size += utf8_encode(str + size, *ptr);
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size));
|
||||
return(str8(str, size));
|
||||
}
|
||||
|
||||
internal String32
|
||||
String32
|
||||
str32_from_8(Arena *arena, String8 in){
|
||||
U64 cap = in.size;
|
||||
U32 *str = push_array_no_zero(arena, U32, cap + 1);
|
||||
U8 *ptr = in.str;
|
||||
U8 *opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc){
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
str[size] = consume.codepoint;
|
||||
size += 1;
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size)*4);
|
||||
return(str32(str, size));
|
||||
U64 cap = in.size;
|
||||
U32* str = push_array_no_zero(arena, U32, cap + 1);
|
||||
U8* ptr = in.str;
|
||||
U8* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc){
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
str[size] = consume.codepoint;
|
||||
size += 1;
|
||||
}
|
||||
str[size] = 0;
|
||||
arena_pop(arena, (cap - size)*4);
|
||||
return(str32(str, size));
|
||||
}
|
||||
|
||||
String8
|
||||
str8_from_16(AllocatorInfo ainfo, String16 in) {
|
||||
U64 cap = in.size * 3;
|
||||
U8* str = alloc_array_no_zero(ainfo, U8, cap + 1);
|
||||
U16* ptr = in.str;
|
||||
U16* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc) {
|
||||
consume = utf16_decode(ptr, opl - ptr);
|
||||
size += utf8_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
resize(ainfo, str, (cap - size));
|
||||
return(str8(str, size));
|
||||
}
|
||||
|
||||
String16
|
||||
str16_from_8(AllocatorInfo ainfo, String8 in) {
|
||||
U64 cap = in.size * 2;
|
||||
U16* str = alloc_array_no_zero(ainfo, U16, cap + 1);
|
||||
U8* ptr = in.str;
|
||||
U8* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc) {
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
size += utf16_encode(str + size, consume.codepoint);
|
||||
}
|
||||
str[size] = 0;
|
||||
resize(ainfo, str, (cap - size));
|
||||
return(str16(str, size));
|
||||
}
|
||||
|
||||
String8
|
||||
str8_from_32(AllocatorInfo ainfo, String32 in){
|
||||
U64 cap = in.size * 4;
|
||||
U8* str = alloc_array_no_zero(ainfo, U8, cap + 1);
|
||||
U32* ptr = in.str;
|
||||
U32* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
for (;ptr < opl; ptr += 1){
|
||||
size += utf8_encode(str + size, *ptr);
|
||||
}
|
||||
str[size] = 0;
|
||||
resize(ainfo, str, (cap - size));
|
||||
return(str8(str, size));
|
||||
}
|
||||
|
||||
String32
|
||||
str32_from_8(AllocatorInfo ainfo, String8 in){
|
||||
U64 cap = in.size;
|
||||
U32* str = alloc_array_no_zero(ainfo, U32, cap + 1);
|
||||
U8* ptr = in.str;
|
||||
U8* opl = ptr + in.size;
|
||||
U64 size = 0;
|
||||
UnicodeDecode consume;
|
||||
for (;ptr < opl; ptr += consume.inc){
|
||||
consume = utf8_decode(ptr, opl - ptr);
|
||||
str[size] = consume.codepoint;
|
||||
size += 1;
|
||||
}
|
||||
str[size] = 0;
|
||||
resize(ainfo, str, (cap - size));
|
||||
return(str32(str, size));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
internal String8
|
||||
string_from_dimension(Dimension dimension){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("X"),
|
||||
str8_lit_comp("Y"),
|
||||
str8_lit_comp("Z"),
|
||||
str8_lit_comp("W"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if ((U32)dimension < 4){
|
||||
result = strings[dimension];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
typedef struct OS_EnumMap OS_EnumMap;
|
||||
struct OS_EnumMap
|
||||
{
|
||||
String8 string;
|
||||
OperatingSystem os;
|
||||
};
|
||||
|
||||
internal String8
|
||||
string_from_side(Side side){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Min"),
|
||||
str8_lit_comp("Max"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if ((U32)side < 2){
|
||||
result = strings[side];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
read_only global OS_EnumMap g_os_enum_map[] =
|
||||
{
|
||||
{ str8_lit_comp(""), OperatingSystem_Null },
|
||||
{ str8_lit_comp("Windows"), OperatingSystem_Windows, },
|
||||
{ str8_lit_comp("Linux"), OperatingSystem_Linux, },
|
||||
{ str8_lit_comp("Mac"), OperatingSystem_Mac, },
|
||||
};
|
||||
md_static_assert(array_count(g_os_enum_map) == OperatingSystem_COUNT, g_os_enum_map_count_check);
|
||||
|
||||
internal String8
|
||||
string_from_operating_system(OperatingSystem os){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Windows"),
|
||||
str8_lit_comp("Linux"),
|
||||
str8_lit_comp("Mac"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (os < OperatingSystem_COUNT){
|
||||
result = strings[os];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal String8
|
||||
string_from_architecture(Architecture arch){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("x64"),
|
||||
str8_lit_comp("x86"),
|
||||
str8_lit_comp("arm64"),
|
||||
str8_lit_comp("arm32"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (arch < Architecture_COUNT){
|
||||
result = strings[arch];
|
||||
}
|
||||
return(result);
|
||||
OperatingSystem
|
||||
operating_system_from_string(String8 string)
|
||||
{
|
||||
for (U64 i = 0; i < array_count(g_os_enum_map); ++i) {
|
||||
if(str8_match(g_os_enum_map[i].string, string, StringMatchFlag_CaseInsensitive)) {
|
||||
return g_os_enum_map[i].os;
|
||||
}
|
||||
}
|
||||
return OperatingSystem_Null;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8
|
||||
string_from_week_day(WeekDay week_day){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Sun"),
|
||||
str8_lit_comp("Mon"),
|
||||
str8_lit_comp("Tue"),
|
||||
str8_lit_comp("Wed"),
|
||||
str8_lit_comp("Thu"),
|
||||
str8_lit_comp("Fri"),
|
||||
str8_lit_comp("Sat"),
|
||||
};
|
||||
String8 result = str8_lit("Err");
|
||||
if ((U32)week_day < WeekDay_COUNT){
|
||||
result = strings[week_day];
|
||||
}
|
||||
return(result);
|
||||
String8
|
||||
push_date_time_string(Arena* arena, DateTime* date_time) {
|
||||
char* mon_str = (char*)string_from_month(date_time->month).str;
|
||||
|
||||
U32 adjusted_hour = date_time->hour % 12;
|
||||
if (adjusted_hour == 0){
|
||||
adjusted_hour = 12;
|
||||
}
|
||||
|
||||
char* ampm = "am";
|
||||
if (date_time->hour >= 12){
|
||||
ampm = "pm";
|
||||
}
|
||||
|
||||
String8 result = push_str8f(arena,
|
||||
"%d %s %d, %02d:%02d:%02d %s",
|
||||
date_time->day, mon_str, date_time->year,
|
||||
adjusted_hour, date_time->min, date_time->sec, ampm
|
||||
);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal String8
|
||||
string_from_month(Month month){
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Jan"),
|
||||
str8_lit_comp("Feb"),
|
||||
str8_lit_comp("Mar"),
|
||||
str8_lit_comp("Apr"),
|
||||
str8_lit_comp("May"),
|
||||
str8_lit_comp("Jun"),
|
||||
str8_lit_comp("Jul"),
|
||||
str8_lit_comp("Aug"),
|
||||
str8_lit_comp("Sep"),
|
||||
str8_lit_comp("Oct"),
|
||||
str8_lit_comp("Nov"),
|
||||
str8_lit_comp("Dec"),
|
||||
};
|
||||
String8 result = str8_lit("Err");
|
||||
if ((U32)month < Month_COUNT){
|
||||
result = strings[month];
|
||||
}
|
||||
return(result);
|
||||
String8
|
||||
push_file_name_date_time_string(Arena* arena, DateTime* date_time) {
|
||||
char* mon_str = (char*)string_from_month(date_time->month).str;
|
||||
|
||||
String8 result = push_str8f(arena,
|
||||
"%d-%s-%0d--%02d-%02d-%02d",
|
||||
date_time->year, mon_str, date_time->day,
|
||||
date_time->hour, date_time->min, date_time->sec
|
||||
);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_date_time_string(Arena *arena, DateTime *date_time){
|
||||
char *mon_str = (char*)string_from_month(date_time->month).str;
|
||||
U32 adjusted_hour = date_time->hour%12;
|
||||
if (adjusted_hour == 0){
|
||||
adjusted_hour = 12;
|
||||
}
|
||||
char *ampm = "am";
|
||||
if (date_time->hour >= 12){
|
||||
ampm = "pm";
|
||||
}
|
||||
String8 result = push_str8f(arena, "%d %s %d, %02d:%02d:%02d %s",
|
||||
date_time->day, mon_str, date_time->year,
|
||||
adjusted_hour, date_time->min, date_time->sec, ampm);
|
||||
return(result);
|
||||
String8
|
||||
string_from_elapsed_time(Arena* arena, DateTime dt) {
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
String8List list = {0};
|
||||
if (dt.year) {
|
||||
str8_list_pushf(scratch.arena, &list, "%dy", dt.year);
|
||||
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
|
||||
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
|
||||
} else if (dt.mon) {
|
||||
str8_list_pushf(scratch.arena, &list, "%um", dt.mon);
|
||||
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
|
||||
} else if (dt.day) {
|
||||
str8_list_pushf(scratch.arena, &list, "%ud", dt.day);
|
||||
}
|
||||
str8_list_pushf(scratch.arena, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec);
|
||||
StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") };
|
||||
String8 result = str8_list_join(arena, &list, &join);
|
||||
scratch_end(scratch);
|
||||
return(result);
|
||||
}
|
||||
|
||||
internal String8
|
||||
push_file_name_date_time_string(Arena *arena, DateTime *date_time){
|
||||
char *mon_str = (char*)string_from_month(date_time->month).str;
|
||||
String8 result = push_str8f(arena, "%d-%s-%0d--%02d-%02d-%02d",
|
||||
date_time->year, mon_str, date_time->day,
|
||||
date_time->hour, date_time->min, date_time->sec);
|
||||
return(result);
|
||||
String8
|
||||
push_date_time_string(AllocatorInfo ainfo, DateTime* date_time) {
|
||||
char* mon_str = (char*)string_from_month(date_time->month).str;
|
||||
|
||||
U32 adjusted_hour = date_time->hour % 12;
|
||||
if (adjusted_hour == 0){
|
||||
adjusted_hour = 12;
|
||||
}
|
||||
|
||||
char* ampm = "am";
|
||||
if (date_time->hour >= 12){
|
||||
ampm = "pm";
|
||||
}
|
||||
|
||||
String8 result = str8f(ainfo,
|
||||
"%d %s %d, %02d:%02d:%02d %s",
|
||||
date_time->day, mon_str, date_time->year,
|
||||
adjusted_hour, date_time->min, date_time->sec, ampm
|
||||
);
|
||||
return(result);
|
||||
}
|
||||
|
||||
String8
|
||||
push_file_name_date_time_string(AllocatorInfo ainfo, DateTime* date_time) {
|
||||
char* mon_str = (char*)string_from_month(date_time->month).str;
|
||||
|
||||
String8 result = str8f(ainfo,
|
||||
"%d-%s-%0d--%02d-%02d-%02d",
|
||||
date_time->year, mon_str, date_time->day,
|
||||
date_time->hour, date_time->min, date_time->sec
|
||||
);
|
||||
return(result);
|
||||
}
|
||||
|
||||
String8
|
||||
string_from_elapsed_time(AllocatorInfo ainfo, DateTime dt) {
|
||||
U8 bytes[KB(8)];
|
||||
FArena arena = farena_from_memory(bytes, size_of(bytes));
|
||||
AllocatorInfo scratch = farena_allocator(arena);
|
||||
|
||||
String8List list = {0};
|
||||
if (dt.year) {
|
||||
str8_list_allocf(scratch, &list, "%dy", dt.year);
|
||||
str8_list_allocf(scratch, &list, "%um", dt.mon);
|
||||
str8_list_allocf(scratch, &list, "%ud", dt.day);
|
||||
} else if (dt.mon) {
|
||||
str8_list_allocf(scratch, &list, "%um", dt.mon);
|
||||
str8_list_allocf(scratch, &list, "%ud", dt.day);
|
||||
} else if (dt.day) {
|
||||
str8_list_allocf(scratch, &list, "%ud", dt.day);
|
||||
}
|
||||
str8_list_allocf(scratch, &list, "%u:%u:%u:%u ms", dt.hour, dt.min, dt.sec, dt.msec);
|
||||
|
||||
StringJoin join = { str8_lit_comp(""), str8_lit_comp(" "), str8_lit_comp("") };
|
||||
String8 result = str8_list_join_alloc(ainfo, &list, &join);
|
||||
return(result);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Escaping
|
||||
//~ Globally UNique Ids
|
||||
|
||||
internal String8
|
||||
escaped_from_raw_str8(Arena *arena, String8 string)
|
||||
B32
|
||||
try_guid_from_string(String8 string, Guid *guid_out)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
String8List parts = {0};
|
||||
U64 start_split_idx = 0;
|
||||
for(U64 idx = 0; idx <= string.size; idx += 1)
|
||||
{
|
||||
U8 byte = (idx < string.size) ? string.str[idx] : 0;
|
||||
B32 split = 1;
|
||||
String8 separator_replace = {0};
|
||||
switch(byte)
|
||||
{
|
||||
default:{split = 0;}break;
|
||||
case 0: {}break;
|
||||
case '\a': {separator_replace = str8_lit("\\a");}break;
|
||||
case '\b': {separator_replace = str8_lit("\\b");}break;
|
||||
case '\f': {separator_replace = str8_lit("\\f");}break;
|
||||
case '\n': {separator_replace = str8_lit("\\n");}break;
|
||||
case '\r': {separator_replace = str8_lit("\\r");}break;
|
||||
case '\t': {separator_replace = str8_lit("\\t");}break;
|
||||
case '\v': {separator_replace = str8_lit("\\v");}break;
|
||||
case '\\': {separator_replace = str8_lit("\\\\");}break;
|
||||
case '"': {separator_replace = str8_lit("\\\"");}break;
|
||||
case '?': {separator_replace = str8_lit("\\?");}break;
|
||||
}
|
||||
if(split)
|
||||
{
|
||||
String8 substr = str8_substr(string, r1u64(start_split_idx, idx));
|
||||
start_split_idx = idx+1;
|
||||
str8_list_push(scratch.arena, &parts, substr);
|
||||
if(separator_replace.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &parts, separator_replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
StringJoin join = {0};
|
||||
String8 result = str8_list_join(arena, &parts, &join);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
TempArena scratch = scratch_begin(0,0);
|
||||
B32 is_parsed = 0;
|
||||
|
||||
internal String8
|
||||
raw_from_escaped_str8(Arena *arena, String8 string)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
String8List strs = {0};
|
||||
U64 start = 0;
|
||||
for(U64 idx = 0; idx <= string.size; idx += 1)
|
||||
{
|
||||
if(idx == string.size || string.str[idx] == '\\' || string.str[idx] == '\r')
|
||||
{
|
||||
String8 str = str8_substr(string, r1u64(start, idx));
|
||||
if(str.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strs, str);
|
||||
}
|
||||
start = idx+1;
|
||||
}
|
||||
if(idx < string.size && string.str[idx] == '\\')
|
||||
{
|
||||
U8 next_char = string.str[idx+1];
|
||||
U8 replace_byte = 0;
|
||||
switch(next_char)
|
||||
{
|
||||
default:{}break;
|
||||
case 'a': replace_byte = 0x07; break;
|
||||
case 'b': replace_byte = 0x08; break;
|
||||
case 'e': replace_byte = 0x1b; break;
|
||||
case 'f': replace_byte = 0x0c; break;
|
||||
case 'n': replace_byte = 0x0a; break;
|
||||
case 'r': replace_byte = 0x0d; break;
|
||||
case 't': replace_byte = 0x09; break;
|
||||
case 'v': replace_byte = 0x0b; break;
|
||||
case '\\':replace_byte = '\\'; break;
|
||||
case '\'':replace_byte = '\''; break;
|
||||
case '"': replace_byte = '"'; break;
|
||||
case '?': replace_byte = '?'; break;
|
||||
}
|
||||
String8 replace_string = push_str8_copy(scratch.arena, str8(&replace_byte, 1));
|
||||
str8_list_push(scratch.arena, &strs, replace_string);
|
||||
idx += 1;
|
||||
start += 1;
|
||||
}
|
||||
}
|
||||
String8 result = str8_list_join(arena, &strs, 0);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
String8List list = str8_split_by_string_chars(scratch.arena, string, str8_lit("-"), StringSplitFlag_KeepEmpties);
|
||||
if(list.node_count == 5)
|
||||
{
|
||||
String8 data1_str = list.first->string;
|
||||
String8 data2_str = list.first->next->string;
|
||||
String8 data3_str = list.first->next->next->string;
|
||||
String8 data4_hi_str = list.first->next->next->next->string;
|
||||
String8 data4_lo_str = list.first->next->next->next->next->string;
|
||||
if( str8_is_integer(data1_str, 16) &&
|
||||
str8_is_integer(data2_str, 16) &&
|
||||
str8_is_integer(data3_str, 16) &&
|
||||
str8_is_integer(data4_hi_str, 16) &&
|
||||
str8_is_integer(data4_lo_str, 16) )
|
||||
{
|
||||
U64 data1 = u64_from_str8(data1_str, 16);
|
||||
U64 data2 = u64_from_str8(data2_str, 16);
|
||||
U64 data3 = u64_from_str8(data3_str, 16);
|
||||
U64 data4_hi = u64_from_str8(data4_hi_str, 16);
|
||||
U64 data4_lo = u64_from_str8(data4_lo_str, 16);
|
||||
if( data1 <= MAX_U32 &&
|
||||
data2 <= MAX_U16 &&
|
||||
data3 <= MAX_U16 &&
|
||||
data4_hi <= MAX_U16 &&
|
||||
data4_lo <= 0xffffffffffff )
|
||||
{
|
||||
guid_out->data1 = (U32)data1;
|
||||
guid_out->data2 = (U16)data2;
|
||||
guid_out->data3 = (U16)data3;
|
||||
|
||||
U64 data4 = (data4_hi << 48) | data4_lo;
|
||||
memory_copy(&guid_out->data4[0], &data4, sizeof(data4));
|
||||
is_parsed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
internal String8
|
||||
indented_from_string(Arena *arena, String8 string)
|
||||
String8
|
||||
indented_from_string(Arena* arena, String8 string)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
|
||||
read_only local_persist U8 indentation_bytes[] = " ";
|
||||
String8List indented_strings = {0};
|
||||
S64 depth = 0;
|
||||
S64 next_depth = 0;
|
||||
|
||||
S64 depth = 0;
|
||||
S64 next_depth = 0;
|
||||
U64 line_begin_off = 0;
|
||||
for(U64 off = 0; off <= string.size; off += 1)
|
||||
{
|
||||
U8 byte = off<string.size ? string.str[off] : 0;
|
||||
switch(byte)
|
||||
{
|
||||
default:{}break;
|
||||
case '{':case '[':case '(':{next_depth += 1; next_depth = max(0, next_depth);}break;
|
||||
case '}':case ']':case ')':{next_depth -= 1; next_depth = max(0, next_depth); depth = next_depth;}break;
|
||||
case '\n':
|
||||
case 0:
|
||||
{
|
||||
String8 line = str8_skip_chop_whitespace(str8_substr(string, r1u64(line_begin_off, off)));
|
||||
if(line.size != 0)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth*2, indentation_bytes, line);
|
||||
}
|
||||
line_begin_off = off+1;
|
||||
depth = next_depth;
|
||||
}break;
|
||||
}
|
||||
U8 byte = off<string.size ? string.str[off] : 0;
|
||||
switch(byte)
|
||||
{
|
||||
default:{}break;
|
||||
case '{':case '[':case '(':{next_depth += 1; next_depth = max(0, next_depth);}break;
|
||||
case '}':case ']':case ')':{next_depth -= 1; next_depth = max(0, next_depth); depth = next_depth;}break;
|
||||
case '\n':
|
||||
case 0:
|
||||
{
|
||||
String8 line = str8_skip_chop_whitespace(str8_substr(string, r1u64(line_begin_off, off)));
|
||||
if(line.size != 0) {
|
||||
str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth * 2, indentation_bytes, line);
|
||||
}
|
||||
line_begin_off = off + 1;
|
||||
depth = next_depth;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
String8 result = str8_list_join(arena, &indented_strings, 0);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
String8
|
||||
indented_from_string_alloc(AllocatorInfo ainfo, String8 string)
|
||||
{
|
||||
Arena* arena = arena_alloc(.backing = ainfo, .block_size = MB(1));
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
|
||||
read_only local_persist U8 indentation_bytes[] = " ";
|
||||
String8List indented_strings = {0};
|
||||
|
||||
S64 depth = 0;
|
||||
S64 next_depth = 0;
|
||||
U64 line_begin_off = 0;
|
||||
for(U64 off = 0; off <= string.size; off += 1)
|
||||
{
|
||||
U8 byte = off<string.size ? string.str[off] : 0;
|
||||
switch(byte)
|
||||
{
|
||||
default:{}break;
|
||||
case '{':case '[':case '(':{next_depth += 1; next_depth = max(0, next_depth);}break;
|
||||
case '}':case ']':case ')':{next_depth -= 1; next_depth = max(0, next_depth); depth = next_depth;}break;
|
||||
case '\n':
|
||||
case 0:
|
||||
{
|
||||
String8 line = str8_skip_chop_whitespace(str8_substr(string, r1u64(line_begin_off, off)));
|
||||
if(line.size != 0) {
|
||||
str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth * 2, indentation_bytes, line);
|
||||
}
|
||||
line_begin_off = off + 1;
|
||||
depth = next_depth;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
String8 result = str8_list_join_alloc(ainfo, &indented_strings, 0);
|
||||
scratch_end(scratch);
|
||||
arena_release(arena);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Escaping
|
||||
|
||||
String8
|
||||
escaped_from_raw_str8(Arena* arena, String8 string)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
|
||||
String8List parts = {0};
|
||||
U64 start_split_idx = 0;
|
||||
for(U64 idx = 0; idx <= string.size; idx += 1)
|
||||
{
|
||||
U8 byte = (idx < string.size) ? string.str[idx] : 0;
|
||||
B32 split = 1;
|
||||
String8 separator_replace = {0};
|
||||
switch (byte)
|
||||
{
|
||||
default: { split = 0; } break;
|
||||
|
||||
case 0: {} break;
|
||||
case '\a': { separator_replace = str8_lit("\\a" ); } break;
|
||||
case '\b': { separator_replace = str8_lit("\\b" ); } break;
|
||||
case '\f': { separator_replace = str8_lit("\\f" ); } break;
|
||||
case '\n': { separator_replace = str8_lit("\\n" ); } break;
|
||||
case '\r': { separator_replace = str8_lit("\\r" ); } break;
|
||||
case '\t': { separator_replace = str8_lit("\\t" ); } break;
|
||||
case '\v': { separator_replace = str8_lit("\\v" ); } break;
|
||||
case '\\': { separator_replace = str8_lit("\\\\"); } break;
|
||||
case '"': { separator_replace = str8_lit("\\\""); } break;
|
||||
case '?': { separator_replace = str8_lit("\\?" ); } break;
|
||||
}
|
||||
if (split)
|
||||
{
|
||||
String8 substr = str8_substr(string, r1u64(start_split_idx, idx));
|
||||
start_split_idx = idx + 1;
|
||||
str8_list_push(scratch.arena, &parts, substr);
|
||||
if(separator_replace.size != 0) {
|
||||
str8_list_push(scratch.arena, &parts, separator_replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringJoin join = {0};
|
||||
String8 result = str8_list_join(arena, &parts, &join);
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
String8
|
||||
raw_from_escaped_str8(Arena* arena, String8 string)
|
||||
{
|
||||
TempArena scratch = scratch_begin(&arena, 1);
|
||||
String8List strs = {0};
|
||||
U64 start = 0;
|
||||
for (U64 idx = 0; idx <= string.size; idx += 1)
|
||||
{
|
||||
if (idx == string.size || string.str[idx] == '\\' || string.str[idx] == '\r') {
|
||||
String8 str = str8_substr(string, r1u64(start, idx));
|
||||
if (str.size != 0) {
|
||||
str8_list_push(scratch.arena, &strs, str);
|
||||
}
|
||||
start = idx + 1;
|
||||
}
|
||||
if (idx < string.size && string.str[idx] == '\\') {
|
||||
U8 next_char = string.str[idx+1];
|
||||
U8 replace_byte = 0;
|
||||
switch(next_char)
|
||||
{
|
||||
default: {} break;
|
||||
case 'a': replace_byte = 0x07; break;
|
||||
case 'b': replace_byte = 0x08; break;
|
||||
case 'e': replace_byte = 0x1b; break;
|
||||
case 'f': replace_byte = 0x0c; break;
|
||||
case 'n': replace_byte = 0x0a; break;
|
||||
case 'r': replace_byte = 0x0d; break;
|
||||
case 't': replace_byte = 0x09; break;
|
||||
case 'v': replace_byte = 0x0b; break;
|
||||
case '\\': replace_byte = '\\'; break;
|
||||
case '\'': replace_byte = '\''; break;
|
||||
case '"': replace_byte = '"'; break;
|
||||
case '?': replace_byte = '?'; break;
|
||||
}
|
||||
|
||||
String8 replace_string = push_str8_copy(scratch.arena, str8(&replace_byte, 1));
|
||||
str8_list_push(scratch.arena, &strs, replace_string);
|
||||
idx += 1;
|
||||
start += 1;
|
||||
}
|
||||
}
|
||||
|
||||
String8 result = str8_list_join(arena, &strs, 0);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
|
||||
+156
-31
@@ -531,10 +531,10 @@ String8List str8_split_by_string_chars_alloc (AllocatorInfo ainfo, String8
|
||||
String8List str8_list_split_by_string_chars (Arena* arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||
String8List str8_list_split_by_string_chars_alloc(AllocatorInfo ainfo, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||
|
||||
MD_API String8 str8_list_join (Arena* arena, String8List* list, StringJoin* optional_params);
|
||||
MD_API String8 str8_list_join_alloc (AllocatorInfo ainfo, String8List* list, StringJoin* optional_params);
|
||||
void str8_list_from_flags (Arena* arena, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count);
|
||||
void str8_list_from_flags_alloc(AllocatorInfo ainfo, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count);
|
||||
MD_API String8 str8_list_join (Arena* arena, String8List* list, StringJoin* optional_params);
|
||||
MD_API String8 str8_list_join_alloc (AllocatorInfo ainfo, String8List* list, StringJoin* optional_params);
|
||||
void str8_list_from_flags (Arena* arena, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count);
|
||||
void str8_list_from_flags_alloc(AllocatorInfo ainfo, String8List* list, U32 flags, String8* flag_string_table, U32 flag_string_count);
|
||||
|
||||
inline String8List
|
||||
str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags) {
|
||||
@@ -694,74 +694,199 @@ inline U32 utf8_from_utf32_single(U8* buffer, U32 character){ return(utf8_encode
|
||||
////////////////////////////////
|
||||
//~ rjf: Unicode String Conversions
|
||||
|
||||
internal String8 str8_from_16(Arena* arena, String16 in);
|
||||
internal String16 str16_from_8(Arena* arena, String8 in);
|
||||
internal String8 str8_from_32(Arena* arena, String32 in);
|
||||
internal String32 str32_from_8(Arena* arena, String8 in);
|
||||
MD_API String8 str8_from_16(Arena* arena, String16 in);
|
||||
MD_API String16 str16_from_8(Arena* arena, String8 in);
|
||||
MD_API String8 str8_from_32(Arena* arena, String32 in);
|
||||
MD_API String32 str32_from_8(Arena* arena, String8 in);
|
||||
|
||||
MD_API String8 str8_from_16_alloc(AllocatorInfo ainfo, String16 in);
|
||||
MD_API String16 str16_from_8_alloc(AllocatorInfo ainfo, String8 in);
|
||||
MD_API String8 str8_from_32_alloc(AllocatorInfo ainfo, String32 in);
|
||||
MD_API String32 str32_from_8_alloc(AllocatorInfo ainfo, String8 in);
|
||||
|
||||
////////////////////////////////
|
||||
//~ String -> Enum Conversions
|
||||
|
||||
internal OperatingSystem operating_system_from_string(String8 string);
|
||||
MD_API OperatingSystem operating_system_from_string(String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||
|
||||
internal String8 string_from_dimension(Dimension dimension);
|
||||
internal String8 string_from_side(Side side);
|
||||
internal String8 string_from_operating_system(OperatingSystem os);
|
||||
internal String8 string_from_arch(Arch arch);
|
||||
inline String8
|
||||
string_from_dimension(Dimension dimension) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("X"),
|
||||
str8_lit_comp("Y"),
|
||||
str8_lit_comp("Z"),
|
||||
str8_lit_comp("W"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if ((U32)dimension < 4) {
|
||||
result = strings[dimension];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline String8
|
||||
string_from_side(Side side) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Min"),
|
||||
str8_lit_comp("Max"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if ((U32)side < 2) {
|
||||
result = strings[side];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline String8
|
||||
string_from_operating_system(OperatingSystem os) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Windows"),
|
||||
str8_lit_comp("Linux"),
|
||||
str8_lit_comp("Mac"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (os < OperatingSystem_COUNT) {
|
||||
result = strings[os];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline String8
|
||||
string_from_architecture(Arch arch) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("x64"),
|
||||
str8_lit_comp("x86"),
|
||||
str8_lit_comp("arm64"),
|
||||
str8_lit_comp("arm32"),
|
||||
};
|
||||
String8 result = str8_lit("error");
|
||||
if (arch < Arch_COUNT) {
|
||||
result = strings[arch];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Time Types -> String
|
||||
|
||||
internal String8 string_from_week_day (WeekDay week_day);
|
||||
internal String8 string_from_month (Month month);
|
||||
internal String8 push_date_time_string (Arena* arena, DateTime* date_time);
|
||||
internal String8 push_file_name_date_time_string(Arena* arena, DateTime* date_time);
|
||||
internal String8 string_from_elapsed_time (Arena* arena, DateTime dt);
|
||||
inline String8
|
||||
string_from_week_day(WeekDay week_day) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Sun"),
|
||||
str8_lit_comp("Mon"),
|
||||
str8_lit_comp("Tue"),
|
||||
str8_lit_comp("Wed"),
|
||||
str8_lit_comp("Thu"),
|
||||
str8_lit_comp("Fri"),
|
||||
str8_lit_comp("Sat"),
|
||||
};
|
||||
String8 result = str8_lit("Err");
|
||||
if ((U32)week_day < WeekDay_COUNT) {
|
||||
result = strings[week_day];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline String8
|
||||
string_from_month(Month month) {
|
||||
local_persist String8 strings[] = {
|
||||
str8_lit_comp("Jan"),
|
||||
str8_lit_comp("Feb"),
|
||||
str8_lit_comp("Mar"),
|
||||
str8_lit_comp("Apr"),
|
||||
str8_lit_comp("May"),
|
||||
str8_lit_comp("Jun"),
|
||||
str8_lit_comp("Jul"),
|
||||
str8_lit_comp("Aug"),
|
||||
str8_lit_comp("Sep"),
|
||||
str8_lit_comp("Oct"),
|
||||
str8_lit_comp("Nov"),
|
||||
str8_lit_comp("Dec"),
|
||||
};
|
||||
String8 result = str8_lit("Err");
|
||||
if ((U32)month < Month_COUNT) {
|
||||
result = strings[month];
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_API String8 push_date_time_string (Arena* arena, DateTime* date_time);
|
||||
MD_API String8 push_file_name_date_time_string(Arena* arena, DateTime* date_time);
|
||||
MD_API String8 string_from_elapsed_time (Arena* arena, DateTime date_time);
|
||||
|
||||
MD_API String8 alloc_date_time_string (AllocatorInfo ainfo, DateTime* date_time);
|
||||
MD_API String8 alloc_file_name_date_time_string(AllocatorInfo ainfo, DateTime* date_time);
|
||||
MD_API String8 string_from_elapsed_time_alloc (AllocatorInfo ainfo, DateTime date_time);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Globally Unique Ids
|
||||
|
||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
||||
internal Guid guid_from_string(String8 string);
|
||||
inline String8
|
||||
string_from_guid(Arena* arena, Guid guid) {
|
||||
String8 result = push_str8f(arena,
|
||||
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
guid.data1,
|
||||
guid.data2,
|
||||
guid.data3,
|
||||
guid.data4[0],
|
||||
guid.data4[1],
|
||||
guid.data4[2],
|
||||
guid.data4[3],
|
||||
guid.data4[4],
|
||||
guid.data4[5],
|
||||
guid.data4[6],
|
||||
guid.data4[7]
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Guid guid_from_string(String8 string) { Guid guid = {0}; try_guid_from_string(string, &guid); return guid; }
|
||||
|
||||
MD_API B32 try_guid_from_string(String8 string, Guid* guid_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Text Indentation
|
||||
|
||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
||||
MD_API String8 indented_from_string(Arena* arena, String8 string);
|
||||
MD_API String8 indented_from_string(AllocatorInfo arena, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Escaping
|
||||
|
||||
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
|
||||
internal String8 raw_from_escaped_str8(Arena *arena, String8 string);
|
||||
MD_API String8 escaped_from_raw_str8(Arena* arena, String8 string);
|
||||
MD_API String8 escaped_from_raw_str8(AllocatorInfo ainfo, String8 string);
|
||||
MD_API String8 raw_from_escaped_str8(Arena* arena, String8 string);
|
||||
MD_API String8 raw_from_escaped_str8(AllocatorInfo ainfo, String8 string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Text Wrapping
|
||||
|
||||
String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
String8List wrapped_lines_from_string(Arena* arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <-> Color
|
||||
|
||||
internal String8 hex_string_from_rgba_4f32(Arena *arena, Vec4F32 rgba);
|
||||
internal String8 hex_string_from_rgba_4f32(Arena* arena, Vec4F32 rgba);
|
||||
internal Vec4F32 rgba_from_hex_string_4f32(String8 hex_string);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Fuzzy Matching
|
||||
|
||||
internal FuzzyMatchRangeList fuzzy_match_find (Arena *arena, String8 needle, String8 haystack);
|
||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena *arena, FuzzyMatchRangeList *src);
|
||||
internal FuzzyMatchRangeList fuzzy_match_find (Arena* arena, String8 needle, String8 haystack);
|
||||
internal FuzzyMatchRangeList fuzzy_match_range_list_copy(Arena* arena, FuzzyMatchRangeList* src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ NOTE(allen): Serialization Helpers
|
||||
|
||||
internal void str8_serial_write_to_dst (String8List *srl, void *out);
|
||||
|
||||
internal void str8_serial_begin (Arena *arena, String8List *srl);
|
||||
internal String8 str8_serial_end (Arena *arena, String8List *srl);
|
||||
internal void str8_serial_write_to_dst (String8List *srl, void *out);
|
||||
internal U64 str8_serial_push_align (Arena *arena, String8List *srl, U64 align);
|
||||
internal void* str8_serial_push_size (Arena *arena, String8List *srl, U64 size);
|
||||
internal void* str8_serial_push_data (Arena *arena, String8List *srl, void *data, U64 size);
|
||||
@@ -785,8 +910,8 @@ internal void* str8_deserial_get_raw_ptr (String8 string, U64 off
|
||||
internal U64 str8_deserial_read_cstr (String8 string, U64 off, String8* cstr_out);
|
||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16* str_out);
|
||||
internal U64 str8_deserial_read_block (String8 string, U64 off, U64 size, String8* block_out);
|
||||
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
|
||||
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
|
||||
internal U64 str8_deserial_read_uleb128 (String8 string, U64 off, U64* value_out);
|
||||
internal U64 str8_deserial_read_sleb128 (String8 string, U64 off, S64* value_out);
|
||||
|
||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)) * (count), sizeof( *(ptr)))
|
||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof( *(ptr)))
|
||||
|
||||
Reference in New Issue
Block a user