From 09553f1e3b04851d99fa9835fbc0db7abf29c5d5 Mon Sep 17 00:00:00 2001 From: Charlie <66182434+asbott@users.noreply.github.com> Date: Fri, 28 Jun 2024 21:57:37 +0200 Subject: [PATCH] Same for sprint and tprint --- build.c | 2 +- oogabooga/base.c | 15 +++ oogabooga/oogabooga.c | 1 + oogabooga/os_interface.c | 59 ---------- oogabooga/string.c | 166 ---------------------------- oogabooga/string_format.c | 223 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 240 insertions(+), 226 deletions(-) create mode 100644 oogabooga/string_format.c diff --git a/build.c b/build.c index 5c1295b..f0fc461 100644 --- a/build.c +++ b/build.c @@ -3,7 +3,7 @@ /// // Build config stuff #define VERY_DEBUG 0 -#define RUN_TESTS 1 +#define RUN_TESTS 0 typedef struct Context_Extra { int monkee; diff --git a/oogabooga/base.c b/oogabooga/base.c index e1f41fb..b52c99e 100644 --- a/oogabooga/base.c +++ b/oogabooga/base.c @@ -82,6 +82,21 @@ void printf(const char* fmt, ...); #define inline inline #endif + +#define FIRST_ARG(arg1, ...) arg1 +#define print(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: prints, \ + default: printf \ + )(__VA_ARGS__) +#define sprint(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: sprints, \ + default: sprintf \ + )(__VA_ARGS__) +#define tprint(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: tprints, \ + default: tprintf \ + )(__VA_ARGS__) + typedef struct Nothing {int nothing;} Nothing; #ifndef CONTEXT_EXTRA diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index d40ef60..f660ed7 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -27,6 +27,7 @@ #include "base.c" #include "string.c" +#include "string_format.c" #include "os_interface.c" diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index dedee8b..3d33f09 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -182,66 +182,7 @@ void os_unload_dynamic_library(Dynamic_Library_Handle l); void os_write_string_to_stdout(string s); -// context.allocator (alloc & dealloc) -void print_va_list(const string fmt, va_list args) { - string s = sprint_va_list(fmt, args); - os_write_string_to_stdout(s); - dealloc(s.data); -} -// print for 'string' and printf for 'char*' - -#define PRINT_BUFFER_SIZE 4096 -// Avoids all and any allocations but overhead in speed and memory. -// Need this for standard printing so we don't get infinite recursions. -// (for example something in memory might fail assert and it needs to print that) -void print_va_list_buffered(const string fmt, va_list args) { - - string current = fmt; - - char buffer[PRINT_BUFFER_SIZE]; - - while (true) { - u64 size = min(current.count, PRINT_BUFFER_SIZE-1); - if (current.count <= 0) break; - - memcpy(buffer, current.data, size); - - char fmt_cstring[PRINT_BUFFER_SIZE+1]; - memcpy(fmt_cstring, current.data, size); - fmt_cstring[size] = 0; - - string s = sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, PRINT_BUFFER_SIZE); - os_write_string_to_stdout(s); - - current.count -= size; - current.data += size; - } -} - -// context.allocator (alloc & dealloc) -void prints(const string fmt, ...) { - va_list args; - va_start(args, fmt); - print_va_list_buffered(fmt, args); - va_end(args); -} -// context.allocator (alloc & dealloc) -void printf(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - string s; - s.data = cast(u8*)fmt; - s.count = strlen(fmt); - print_va_list_buffered(s, args); - va_end(args); -} - -#define FIRST_ARG(arg1, ...) arg1 -#define print(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ - string: prints, \ - default: printf \ - )(__VA_ARGS__) /// /// // Memory diff --git a/oogabooga/string.c b/oogabooga/string.c index 90a2bb6..b298228 100644 --- a/oogabooga/string.c +++ b/oogabooga/string.c @@ -95,170 +95,6 @@ char *temp_convert_to_null_terminated_string(const string s) { pop_allocator(); return c; } -inline int crt_sprintf(char *str, const char *format, ...); -int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args); - -bool is_pointer_valid(void *p); -u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list args) { - if (!buffer) count = UINT64_MAX; - const char* p = fmt; - char* bufp = buffer; - while (*p != '\0' && (bufp - buffer) < count - 1) { - if (*p == '%') { - p += 1; - if (*p == 's') { - // We replace %s formatting with our fixed length string - p += 1; - string s = va_arg(args, string); - assert(s.count < (1024ULL*1024ULL*1024ULL*256ULL), "Ypu passed something else than a fixed-length 'string' to %%s. Maybe you passed a char* and should do %%cs instead?"); - for (u64 i = 0; i < s.count && (bufp - buffer) < count - 1; i++) { - if (buffer) *bufp = s.data[i]; - bufp += 1; - } - } else if (*p == 'c' && *(p+1) == 's') { - // We extend the standard formatting and add %cs so we can format c strings if we need to - p += 2; - char* s = va_arg(args, char*); - assert(is_pointer_valid(s), "You passed an invalid pointer to %%cs"); - u64 len = 0; - while (*s != '\0' && (bufp - buffer) < count - 1) { - assert(is_pointer_valid(s) && len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*."); - if (buffer) { - *bufp = *s; - } - s += 1; - bufp += 1; - len += 1; - assert(is_pointer_valid(s) && len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*."); - } - } else { - // Fallback to standard vsnprintf - char temp_buffer[512]; - char format_specifier[64]; - int specifier_len = 0; - format_specifier[specifier_len++] = '%'; - - while (*p != '\0' && strchr("diuoxXfFeEgGaAcCpn%", *p) == NULL) { - format_specifier[specifier_len++] = *p++; - } - if (*p != '\0') { - format_specifier[specifier_len++] = *p++; - } - format_specifier[specifier_len] = '\0'; - - int temp_len = vsnprintf(temp_buffer, sizeof(temp_buffer), format_specifier, args); - switch (format_specifier[specifier_len - 1]) { - case 'd': case 'i': va_arg(args, int); break; - case 'u': case 'x': case 'X': case 'o': va_arg(args, unsigned int); break; - case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': va_arg(args, double); break; - case 'c': va_arg(args, int); break; - case 's': va_arg(args, char*); break; - case 'p': va_arg(args, void*); break; - case 'n': va_arg(args, int*); break; - default: break; - } - - if (temp_len < 0) { - return -1; // Error in formatting - } - - for (int i = 0; i < temp_len && (bufp - buffer) < count - 1; i++) { - if (buffer) *bufp = temp_buffer[i]; - bufp += 1; - } - } - } else { - if (buffer) { - *bufp = *p; - } - bufp += 1; - p += 1; - } - } - if (buffer) *bufp = '\0'; - - return bufp - buffer; -} -string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 count) { - u64 formatted_length = format_string_to_buffer((char*)buffer, count, fmt, args); - - string result; - result.data = (u8*)buffer; - - if (formatted_length >= 0 && formatted_length < count) { - result.count = formatted_length; - } else { - result.count = count - 1; - } - - return result; -} -string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u64 count) { - - char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); - return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); -} -// context.allocator -string sprint_va_list(const string fmt, va_list args) { - - char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); - u64 count = format_string_to_buffer(NULL, 0, fmt_cstring, args) + 1; - - char* buffer = NULL; - - buffer = (char*)alloc(count); - - return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); -} - -// context.allocator -string sprint(const string fmt, ...) { - va_list args = 0; - va_start(args, fmt); - string s = sprint_va_list(fmt, args); - va_end(args); - return s; -} - -// temp allocator -string tprint(const string fmt, ...) { - va_list args = 0; - va_start(args, fmt); - push_temp_allocator(); - string s = sprint_va_list(fmt, args); - pop_allocator(); - va_end(args); - return s; -} - -// context.allocator -string sprintf(const char *fmt, ...) { - string sfmt; - sfmt.data = cast(u8*)fmt; - sfmt.count = strlen(fmt); - - va_list args; - va_start(args, fmt); - string s = sprint_va_list(sfmt, args); - va_end(args); - - return s; -} -// temp allocator -string tprintf(const char *fmt, ...) { - string sfmt; - sfmt.data = cast(u8*)fmt; - sfmt.count = strlen(fmt); - - va_list args; - va_start(args, fmt); - push_temp_allocator(); - string s = sprint_va_list(sfmt, args); - pop_allocator(); - va_end(args); - - return s; -} bool strings_match(string a, string b) { if (a.count != b.count) return false; @@ -281,5 +117,3 @@ string string_view(string s, u64 start_index, u64 count) { return result; } -// Defined in os interface -void print(string s, ...); \ No newline at end of file diff --git a/oogabooga/string_format.c b/oogabooga/string_format.c new file mode 100644 index 0000000..d492fdd --- /dev/null +++ b/oogabooga/string_format.c @@ -0,0 +1,223 @@ + +void os_write_string_to_stdout(string s); +inline int crt_sprintf(char *str, const char *format, ...); +int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args); +bool is_pointer_valid(void *p); + +u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list args) { + if (!buffer) count = UINT64_MAX; + const char* p = fmt; + char* bufp = buffer; + while (*p != '\0' && (bufp - buffer) < count - 1) { + if (*p == '%') { + p += 1; + if (*p == 's') { + // We replace %s formatting with our fixed length string + p += 1; + string s = va_arg(args, string); + assert(s.count < (1024ULL*1024ULL*1024ULL*256ULL), "Ypu passed something else than a fixed-length 'string' to %%s. Maybe you passed a char* and should do %%cs instead?"); + for (u64 i = 0; i < s.count && (bufp - buffer) < count - 1; i++) { + if (buffer) *bufp = s.data[i]; + bufp += 1; + } + } else if (*p == 'c' && *(p+1) == 's') { + // We extend the standard formatting and add %cs so we can format c strings if we need to + p += 2; + char* s = va_arg(args, char*); + assert(is_pointer_valid(s), "You passed an invalid pointer to %%cs"); + u64 len = 0; + while (*s != '\0' && (bufp - buffer) < count - 1) { + assert(is_pointer_valid(s) && len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*."); + if (buffer) { + *bufp = *s; + } + s += 1; + bufp += 1; + len += 1; + assert(is_pointer_valid(s) && len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*."); + } + } else { + // Fallback to standard vsnprintf + char temp_buffer[512]; + char format_specifier[64]; + int specifier_len = 0; + format_specifier[specifier_len++] = '%'; + + while (*p != '\0' && strchr("diuoxXfFeEgGaAcCpn%", *p) == NULL) { + format_specifier[specifier_len++] = *p++; + } + if (*p != '\0') { + format_specifier[specifier_len++] = *p++; + } + format_specifier[specifier_len] = '\0'; + + int temp_len = vsnprintf(temp_buffer, sizeof(temp_buffer), format_specifier, args); + switch (format_specifier[specifier_len - 1]) { + case 'd': case 'i': va_arg(args, int); break; + case 'u': case 'x': case 'X': case 'o': va_arg(args, unsigned int); break; + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': va_arg(args, double); break; + case 'c': va_arg(args, int); break; + case 's': va_arg(args, char*); break; + case 'p': va_arg(args, void*); break; + case 'n': va_arg(args, int*); break; + default: break; + } + + if (temp_len < 0) { + return -1; // Error in formatting + } + + for (int i = 0; i < temp_len && (bufp - buffer) < count - 1; i++) { + if (buffer) *bufp = temp_buffer[i]; + bufp += 1; + } + } + } else { + if (buffer) { + *bufp = *p; + } + bufp += 1; + p += 1; + } + } + if (buffer) *bufp = '\0'; + + return bufp - buffer; +} +string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 count) { + u64 formatted_length = format_string_to_buffer((char*)buffer, count, fmt, args); + + string result; + result.data = (u8*)buffer; + + if (formatted_length >= 0 && formatted_length < count) { + result.count = formatted_length; + } else { + result.count = count - 1; + } + + return result; +} +string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u64 count) { + + char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); + return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); +} +// context.allocator +string sprint_va_list(const string fmt, va_list args) { + + char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); + u64 count = format_string_to_buffer(NULL, 0, fmt_cstring, args) + 1; + + char* buffer = NULL; + + buffer = (char*)alloc(count); + + return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); +} + +// context.allocator +string sprints(const string fmt, ...) { + va_list args = 0; + va_start(args, fmt); + string s = sprint_va_list(fmt, args); + va_end(args); + return s; +} + +// temp allocator +string tprints(const string fmt, ...) { + va_list args = 0; + va_start(args, fmt); + push_temp_allocator(); + string s = sprint_va_list(fmt, args); + pop_allocator(); + va_end(args); + return s; +} + +// context.allocator +string sprintf(const char *fmt, ...) { + string sfmt; + sfmt.data = cast(u8*)fmt; + sfmt.count = strlen(fmt); + + va_list args; + va_start(args, fmt); + string s = sprint_va_list(sfmt, args); + va_end(args); + + return s; +} +// temp allocator +string tprintf(const char *fmt, ...) { + string sfmt; + sfmt.data = cast(u8*)fmt; + sfmt.count = strlen(fmt); + + va_list args; + va_start(args, fmt); + push_temp_allocator(); + string s = sprint_va_list(sfmt, args); + pop_allocator(); + va_end(args); + + return s; +} + + +// context.allocator (alloc & dealloc) +void print_va_list(const string fmt, va_list args) { + string s = sprint_va_list(fmt, args); + os_write_string_to_stdout(s); + dealloc(s.data); +} + +// print for 'string' and printf for 'char*' + +#define PRINT_BUFFER_SIZE 4096 +// Avoids all and any allocations but overhead in speed and memory. +// Need this for standard printing so we don't get infinite recursions. +// (for example something in memory might fail assert and it needs to print that) +void print_va_list_buffered(const string fmt, va_list args) { + + string current = fmt; + + char buffer[PRINT_BUFFER_SIZE]; + + while (true) { + u64 size = min(current.count, PRINT_BUFFER_SIZE-1); + if (current.count <= 0) break; + + memcpy(buffer, current.data, size); + + char fmt_cstring[PRINT_BUFFER_SIZE+1]; + memcpy(fmt_cstring, current.data, size); + fmt_cstring[size] = 0; + + string s = sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, PRINT_BUFFER_SIZE); + os_write_string_to_stdout(s); + + current.count -= size; + current.data += size; + } +} + +// context.allocator (alloc & dealloc) +void prints(const string fmt, ...) { + va_list args; + va_start(args, fmt); + print_va_list_buffered(fmt, args); + va_end(args); +} +// context.allocator (alloc & dealloc) +void printf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + string s; + s.data = cast(u8*)fmt; + s.count = strlen(fmt); + print_va_list_buffered(s, args); + va_end(args); +} +