2024-06-28 21:57:37 +02:00
|
|
|
|
2024-07-23 17:33:11 +02:00
|
|
|
ogb_instance void os_write_string_to_stdout(string s);
|
2024-06-28 21:57:37 +02:00
|
|
|
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);
|
|
|
|
|
2024-08-19 14:08:03 +02:00
|
|
|
u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list args);
|
|
|
|
u64 format_string_to_buffer_vararg(char* buffer, u64 count, const char* fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
u64 n = format_string_to_buffer(buffer, count, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
typedef struct _8_Bytes {u8 _[8];} _8_Bytes;
|
|
|
|
typedef struct _12_Bytes {u8 _[12];} _12_Bytes;
|
|
|
|
typedef struct _16_Bytes {u8 _[16];} _16_Bytes;
|
2024-06-28 21:57:37 +02:00
|
|
|
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') {
|
2024-08-18 12:31:42 +02:00
|
|
|
p += 1;
|
|
|
|
// We replace %s formatting with our fixed length string (if it is a valid such, otherwise treat as char*)
|
|
|
|
va_list args2; // C varargs are so good
|
|
|
|
va_copy(args2, args);
|
|
|
|
string s = va_arg(args2, string);
|
|
|
|
va_end(args2);
|
|
|
|
// Ooga booga moment
|
|
|
|
bool is_valid_fixed_length_string = s.count < 1024ULL*1024ULL*1024ULL*256ULL && is_pointer_valid(s.data);
|
|
|
|
if (is_valid_fixed_length_string) {
|
|
|
|
va_arg(args, string);
|
|
|
|
for (u64 i = 0; i < s.count && (bufp - buffer) < count - 1; i++) {
|
|
|
|
if (buffer) *bufp = s.data[i];
|
|
|
|
bufp += 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// #Copypaste
|
|
|
|
// We extend the standard formatting and add %cs so we can format c strings if we need to
|
|
|
|
char* s = va_arg(args, char*);
|
|
|
|
u64 len = 0;
|
|
|
|
while (*s != '\0' && (bufp - buffer) < count - 1) {
|
|
|
|
assert(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(len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*.");
|
|
|
|
}
|
2024-06-28 21:57:37 +02:00
|
|
|
}
|
|
|
|
} else if (*p == 'c' && *(p+1) == 's') {
|
2024-08-18 12:31:42 +02:00
|
|
|
// #Copypaste
|
2024-06-28 21:57:37 +02:00
|
|
|
// 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*);
|
|
|
|
u64 len = 0;
|
|
|
|
while (*s != '\0' && (bufp - buffer) < count - 1) {
|
2024-07-01 02:14:08 +02:00
|
|
|
assert(len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*.");
|
2024-06-28 21:57:37 +02:00
|
|
|
if (buffer) {
|
|
|
|
*bufp = *s;
|
|
|
|
}
|
|
|
|
s += 1;
|
|
|
|
bufp += 1;
|
|
|
|
len += 1;
|
2024-07-01 02:14:08 +02:00
|
|
|
assert(len < (1024ULL*1024ULL*1024ULL*1ULL), "The argument passed to %%cs is either way too big, missing null-termination or simply not a char*.");
|
2024-06-28 21:57:37 +02:00
|
|
|
}
|
2024-08-19 14:08:03 +02:00
|
|
|
} else if (*p == 'v' && *(p+1) == '2') {
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
_8_Bytes data = va_arg(args, _8_Bytes);
|
|
|
|
|
|
|
|
f32 x = *(((f32*)(&data))+0);
|
|
|
|
f32 y = *(((f32*)(&data))+1);
|
|
|
|
|
|
|
|
u64 n = format_string_to_buffer_vararg(buffer ? bufp : 0, 128, "{ X: %f, Y: %f }", x, y);
|
|
|
|
|
|
|
|
bufp += n;
|
|
|
|
} else if (*p == 'v' && *(p+1) == '3') {
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
_12_Bytes data = va_arg(args, _12_Bytes);
|
|
|
|
|
|
|
|
f32 x = *(((f32*)(&data))+0);
|
|
|
|
f32 y = *(((f32*)(&data))+1);
|
|
|
|
f32 z = *(((f32*)(&data))+2);
|
|
|
|
|
|
|
|
u64 n = format_string_to_buffer_vararg(buffer ? bufp : 0, 196, "{ X: %f, Y: %f, Z: %f }", x, y, z);
|
|
|
|
|
|
|
|
bufp += n;
|
|
|
|
} else if (*p == 'v' && *(p+1) == '4') {
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
_16_Bytes data = va_arg(args, _16_Bytes);
|
|
|
|
|
|
|
|
f32 x = *(((f32*)(&data))+0);
|
|
|
|
f32 y = *(((f32*)(&data))+1);
|
|
|
|
f32 z = *(((f32*)(&data))+2);
|
|
|
|
f32 w = *(((f32*)(&data))+3);
|
|
|
|
|
|
|
|
u64 n = format_string_to_buffer_vararg(buffer ? bufp : 0, 256, "{ X: %f, Y: %f, Z: %f, W: %f }", x, y, z, w);
|
|
|
|
|
|
|
|
bufp += n;
|
2024-06-28 21:57:37 +02:00
|
|
|
} 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;
|
|
|
|
}
|
2024-07-15 21:40:27 +02:00
|
|
|
u64 format_string_to_buffer_va(char* buffer, u64 count, const char* fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
u64 r = format_string_to_buffer(buffer, count, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
return r;
|
|
|
|
}
|
2024-07-02 15:27:33 +02:00
|
|
|
string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 buffer_size) {
|
|
|
|
u64 formatted_length = format_string_to_buffer((char*)buffer, buffer_size, fmt, args);
|
2024-06-28 21:57:37 +02:00
|
|
|
|
|
|
|
string result;
|
|
|
|
result.data = (u8*)buffer;
|
|
|
|
|
2024-07-02 15:27:33 +02:00
|
|
|
if (formatted_length >= 0 && formatted_length < buffer_size) {
|
2024-06-28 21:57:37 +02:00
|
|
|
result.count = formatted_length;
|
|
|
|
} else {
|
2024-07-02 15:27:33 +02:00
|
|
|
result.count = buffer_size - 1;
|
2024-06-28 21:57:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2024-07-02 15:27:33 +02:00
|
|
|
string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u64 buffer_size) {
|
2024-06-28 21:57:37 +02:00
|
|
|
|
|
|
|
char* fmt_cstring = temp_convert_to_null_terminated_string(fmt);
|
2024-07-02 15:27:33 +02:00
|
|
|
return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, buffer_size);
|
2024-06-28 21:57:37 +02:00
|
|
|
}
|
2024-07-01 13:10:06 +02:00
|
|
|
|
|
|
|
string sprint_va_list(Allocator allocator, const string fmt, va_list args) {
|
2024-06-28 21:57:37 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2024-07-01 13:10:06 +02:00
|
|
|
buffer = (char*)alloc(allocator, count);
|
2024-06-28 21:57:37 +02:00
|
|
|
|
|
|
|
return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count);
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:10:06 +02:00
|
|
|
|
|
|
|
string sprints(Allocator allocator, const string fmt, ...) {
|
2024-06-28 21:57:37 +02:00
|
|
|
va_list args = 0;
|
|
|
|
va_start(args, fmt);
|
2024-07-01 13:10:06 +02:00
|
|
|
string s = sprint_va_list(allocator, fmt, args);
|
2024-06-28 21:57:37 +02:00
|
|
|
va_end(args);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// temp allocator
|
|
|
|
string tprints(const string fmt, ...) {
|
|
|
|
va_list args = 0;
|
|
|
|
va_start(args, fmt);
|
2024-07-23 17:33:11 +02:00
|
|
|
string s = sprint_va_list(get_temporary_allocator(), fmt, args);
|
2024-06-28 21:57:37 +02:00
|
|
|
va_end(args);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:10:06 +02:00
|
|
|
|
|
|
|
string sprintf(Allocator allocator, const char *fmt, ...) {
|
2024-06-28 21:57:37 +02:00
|
|
|
string sfmt;
|
|
|
|
sfmt.data = cast(u8*)fmt;
|
|
|
|
sfmt.count = strlen(fmt);
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2024-07-01 13:10:06 +02:00
|
|
|
string s = sprint_va_list(allocator, sfmt, args);
|
2024-06-28 21:57:37 +02:00
|
|
|
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);
|
2024-07-23 17:33:11 +02:00
|
|
|
string s = sprint_va_list(get_temporary_allocator(), sfmt, args);
|
2024-06-28 21:57:37 +02:00
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2024-07-19 16:45:58 +02:00
|
|
|
// prints for 'string' and printf for 'char*'
|
2024-06-28 21:57:37 +02:00
|
|
|
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
- File IO
- os_file_open(string path, Os_Io_Open_Flags flags)
- os_file_close(File f)
- os_file_delete(string path)
- os_file_write_string(File f, string s)
- os_file_write_bytes(File f, void *buffer, u64 size_in_bytes)
- os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_bytes)
- os_write_entire_file_handle(File f, string data)
- os_write_entire_file(string path, string data)
- os_read_entire_file_handle(File f, string *result)
- os_read_entire_file(string path, string *result)
- fprint(File, string/char*, ...)
- Buncha tests
- os_high_precision_sleep
- talloc_string
- Program memory is touched on VirtualAlloc so it actually allocates physical memory (and we can tell when an address is untouched)
2024-06-29 20:55:43 +02:00
|
|
|
|
2024-07-01 13:10:06 +02:00
|
|
|
|
2024-06-28 21:57:37 +02:00
|
|
|
void prints(const string fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
print_va_list_buffered(fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
2024-07-01 13:10:06 +02:00
|
|
|
|
2024-06-28 21:57:37 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-07-01 02:14:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef void(*Logger_Proc)(Log_Level level, string s);
|
2024-07-23 17:33:11 +02:00
|
|
|
#define LOG_BASE(level, ...) if (get_context().logger) ((Logger_Proc)get_context().logger)(level, tprint(__VA_ARGS__))
|
2024-07-01 02:14:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
#define log_verbose(...) LOG_BASE(LOG_VERBOSE, __VA_ARGS__)
|
|
|
|
#define log_info(...) LOG_BASE(LOG_INFO, __VA_ARGS__)
|
|
|
|
#define log_warning(...) LOG_BASE(LOG_WARNING, __VA_ARGS__)
|
|
|
|
#define log_error(...) LOG_BASE(LOG_ERROR, __VA_ARGS__)
|
|
|
|
|
|
|
|
#define log(...) LOG_BASE(LOG_INFO, __VA_ARGS__)
|
|
|
|
|
2024-07-02 15:27:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void string_builder_prints(String_Builder *b, string fmt, ...) {
|
|
|
|
assert(b->allocator.proc, "String_Builder is missing allocator");
|
|
|
|
|
|
|
|
va_list args1 = 0;
|
|
|
|
va_start(args1, fmt);
|
|
|
|
va_list args2 = 0;
|
|
|
|
va_copy(args2, args1);
|
|
|
|
|
|
|
|
u64 formatted_count = format_string_to_buffer(0, 0, temp_convert_to_null_terminated_string(fmt), args1);
|
|
|
|
|
|
|
|
va_end(args1);
|
|
|
|
|
|
|
|
string_builder_reserve(b, b->count+formatted_count+1);
|
|
|
|
|
|
|
|
format_string_to_buffer((char*)b->buffer+b->count, b->count+formatted_count+1, temp_convert_to_null_terminated_string(fmt), args2);
|
|
|
|
b->count += formatted_count;
|
|
|
|
|
|
|
|
va_end(args2);
|
|
|
|
}
|
|
|
|
void string_builder_printf(String_Builder *b, const char *fmt, ...) {
|
|
|
|
assert(b->allocator.proc, "String_Builder is missing allocator");
|
|
|
|
|
|
|
|
va_list args1 = 0;
|
|
|
|
va_start(args1, fmt);
|
|
|
|
va_list args2 = 0;
|
|
|
|
va_copy(args2, args1);
|
|
|
|
|
|
|
|
u64 formatted_count = format_string_to_buffer(0, 0, fmt, args1);
|
|
|
|
|
|
|
|
va_end(args1);
|
|
|
|
|
|
|
|
string_builder_reserve(b, b->count+formatted_count+1);
|
|
|
|
|
|
|
|
format_string_to_buffer((char*)b->buffer+b->count, b->buffer_capacity-b->count+1, fmt, args2);
|
|
|
|
b->count += formatted_count;
|
|
|
|
|
|
|
|
va_end(args2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define string_builder_print(...) _Generic((SECOND_ARG(__VA_ARGS__)), \
|
|
|
|
string: string_builder_prints, \
|
|
|
|
default: string_builder_printf \
|
2024-07-19 16:45:58 +02:00
|
|
|
)(__VA_ARGS__)
|