From b78d4408f13ba80db958dcda18d8b73f1d230e07 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 26 Dec 2024 00:46:45 -0600 Subject: [PATCH] remove all uses of stdlib printf/putc/puts --- Makefile | 7 +- c/class_resolver.c | 16 +-- c/debug_class_file.c | 80 ++++++------ c/file.h | 1 + c/hash_table.c | 5 +- c/minmax.h | 4 + c/parse.c | 70 +++++++++++ c/parse.h | 21 ++++ c/print_class.c | 8 +- c/{printf_dreamcast.c => printf.c} | 39 +++++- c/printf.h | 37 ++++-- c/printf_dreamcast.h | 17 --- c/printf_hosted.h | 6 - c/unparse.c | 194 +++++++++++++++++++++++++++++ c/unparse.h | 17 +++ 15 files changed, 433 insertions(+), 89 deletions(-) create mode 100644 c/minmax.h create mode 100644 c/parse.c create mode 100644 c/parse.h rename c/{printf_dreamcast.c => printf.c} (78%) delete mode 100644 c/printf_dreamcast.h delete mode 100644 c/printf_hosted.h create mode 100644 c/unparse.c create mode 100644 c/unparse.h diff --git a/Makefile b/Makefile index 0c1c651..f320727 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,10 @@ OBJ = \ c/memory_allocator.o \ c/class_resolver.o \ c/hash_table.o \ - c/frame.o + c/frame.o \ + c/printf.o \ + c/parse.o \ + c/unparse.o MAIN_OBJ = \ $(OBJ) \ @@ -29,7 +32,7 @@ PRINT_CLASS_OBJ = \ CC ?= gcc ARCH = -m32 -CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -std=c2x -DDEBUG -g +CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -DDEBUG -g OPT ?= -O0 DEPFLAGS = -MMD -MP diff --git a/c/class_resolver.c b/c/class_resolver.c index fd4acbb..0885e10 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -200,8 +200,8 @@ struct class_entry * class_resolver_lookup_class(int class_hash_table_length, int class_name_length) { debugf("class_resolver_lookup_class: "); - for (int i = 0; i < class_name_length; i++) { fputc(class_name[i], stdout); } - fputc('\n', stdout); + for (int i = 0; i < class_name_length; i++) { debugc(class_name[i]); } + debugc('\n'); struct hash_table_entry * e = hash_table_find(class_hash_table_length, class_hash_table, @@ -248,8 +248,8 @@ struct field_entry * class_resolver_lookup_field(int fields_hash_table_length, int field_name_length) { debugf("class_resolver_lookup_field: "); - for (int i = 0; i < field_name_length; i++) { fputc(field_name[i], stdout); } - fputc('\n', stdout); + for (int i = 0; i < field_name_length; i++) { debugc(field_name[i]); } + debugc('\n'); struct hash_table_entry * e = hash_table_find(fields_hash_table_length, fields_hash_table, @@ -302,10 +302,10 @@ struct method_info * class_resolver_lookup_method(int methods_hash_table_length, int method_descriptor_length) { debugf("class_resolver_lookup_method: "); - for (int i = 0; i < method_name_length; i++) { fputc(method_name[i], stdout); } - fputc(' ', stdout); - for (int i = 0; i < method_descriptor_length; i++) { fputc(method_descriptor[i], stdout); } - fputc('\n', stdout); + for (int i = 0; i < method_name_length; i++) { debugc(method_name[i]); } + debugc(' '); + for (int i = 0; i < method_descriptor_length; i++) { debugc(method_descriptor[i]); } + debugc('\n'); struct hash_table_entry * e = hash_table_find2(methods_hash_table_length, methods_hash_table, diff --git a/c/debug_class_file.c b/c/debug_class_file.c index 7ceb7de..aab185c 100644 --- a/c/debug_class_file.c +++ b/c/debug_class_file.c @@ -12,7 +12,7 @@ void print_utf8_string(struct constant * constant) { for (int i = 0; i < constant->utf8.length; i++) { - fputc(constant->utf8.bytes[i], stdout); + debugc(constant->utf8.bytes[i]); } } @@ -101,111 +101,111 @@ void print_constant(struct constant * constant) void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) { - fputs(indent, stdout); + debugs(indent); debugf("attribute_name_index: %d\n", attribute->attribute_name_index); struct constant * attribute_name = &constant_pool[attribute->attribute_name_index - 1]; - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); print_constant(attribute_name); if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "ConstantValue")) { - fputs(indent, stdout); + debugs(indent); debugf("constantvalue_index %d\n", attribute->constantvalue->constantvalue_index); struct constant * value = &constant_pool[attribute->constantvalue->constantvalue_index - 1]; - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); print_constant(value); if (value->tag == CONSTANT_String) { - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); print_constant(&constant_pool[value->string.string_index - 1]); } } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "Code")) { // print code - fputs(indent, stdout); + debugs(indent); debugf("max_stack %d\n", attribute->code->max_stack); - fputs(indent, stdout); + debugs(indent); debugf("max_locals %d\n", attribute->code->max_locals); - fputs(indent, stdout); + debugs(indent); debugf("code_length %d\n", attribute->code->code_length); // dump code - fputs(indent, stdout); + debugs(indent); debugf("code:\n"); uint32_t pc = 0; while (pc < attribute->code->code_length) { - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); pc = decode_print_instruction(attribute->code->code, pc); } - fputs(indent, stdout); + debugs(indent); debugf("exception_table_length: %d\n", attribute->code->exception_table_length); - fputs(indent, stdout); + debugs(indent); debugf("exceptions:\n"); for (int i = 0; i < attribute->code->exception_table_length; i++) { - fputs(indent, stdout); + debugs(indent); debugf(" exception %d:\n", i); - fputs(indent, stdout); + debugs(indent); debugf(" start_pc: %d\n", attribute->code->exception_table[i].start_pc); - fputs(indent, stdout); + debugs(indent); debugf(" end_pc: %d\n", attribute->code->exception_table[i].end_pc); - fputs(indent, stdout); + debugs(indent); debugf(" handler_pc: %d\n", attribute->code->exception_table[i].handler_pc); - fputs(indent, stdout); + debugs(indent); debugf(" catch_type: %d\n", attribute->code->exception_table[i].catch_type); } - fputs(indent, stdout); + debugs(indent); debugf("attributes_count: %d\n", attribute->code->attributes_count); - fputs(indent, stdout); + debugs(indent); debugf("attributes:\n"); for (int i = 0; i < attribute->code->attributes_count; i++) { char indent2[string_length(indent) + 2 + 1]; string_copy(indent2, indent); string_copy(indent2 + string_length(indent), " "); - fputs(indent, stdout); + debugs(indent); debugf(" attribute %d:\n", i); print_attribute(indent2, &attribute->code->attributes[i], constant_pool); } } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { - fputs(indent, stdout); + debugs(indent); debugf("num_bootstrap_methods: %d\n", attribute->bootstrapmethods->num_bootstrap_methods); - fputs(indent, stdout); + debugs(indent); debugf("bootstrap methods:\n"); for (int i = 0; i < attribute->bootstrapmethods->num_bootstrap_methods; i++) { - fputs(indent, stdout); + debugs(indent); debugf(" bootstrap_method %d:\n", i); - fputs(indent, stdout); + debugs(indent); debugf(" bootstrap_method_ref: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_method_ref); - fputs(indent, stdout); + debugs(indent); debugf(" num_bootstrap_arguments: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments); - fputs(indent, stdout); + debugs(indent); debugf(" bootstrap_arguments:\n"); for (int j = 0; j < attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; j++) { - fputs(indent, stdout); + debugs(indent); debugf(" bootstrap_argument %d: %d\n", j, attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_arguments[j]); } } } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestHost")) { - fputs(indent, stdout); + debugs(indent); debugf("host_class_index: %d\n", attribute->nesthost->host_class_index); } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestMembers")) { - fputs(indent, stdout); + debugs(indent); debugf("number_of_classes: %d\n", attribute->nestmembers->number_of_classes); - fputs(indent, stdout); + debugs(indent); debugf("classes:\n"); for (int i = 0; i < attribute->nestmembers->number_of_classes; i++) { - fputs(indent, stdout); + debugs(indent); debugf(" class %d:\n", i); - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); print_constant(&constant_pool[attribute->nestmembers->classes[i] - 1]); int ix = constant_pool[attribute->nestmembers->classes[i] - 1].class.name_index; - fputs(indent, stdout); - fputs(" ", stdout); + debugs(indent); + debugs(" "); print_constant(&constant_pool[ix - 1]); } } diff --git a/c/file.h b/c/file.h index 9ada825..9cbc9c4 100644 --- a/c/file.h +++ b/c/file.h @@ -1,5 +1,6 @@ #pragma once #include +#include uint8_t * file_read(const char * path, size_t * file_size); diff --git a/c/hash_table.c b/c/hash_table.c index d01f7e3..b5c00b4 100644 --- a/c/hash_table.c +++ b/c/hash_table.c @@ -42,8 +42,8 @@ void print_key(const uint8_t * key, int key_length) { debugf("key: "); for (int i = 0; i < key_length; i++) - fputc(key[i], stdout); - fputc('\n', stdout); + debugc(key[i]); + debugc('\n'); } void hash_table_add(int hash_table_length, @@ -104,7 +104,6 @@ struct hash_table_entry * hash_table_find(int hash_table_length, } e = e->next; } - fflush(stdout); return nullptr; } diff --git a/c/minmax.h b/c/minmax.h new file mode 100644 index 0000000..df4c506 --- /dev/null +++ b/c/minmax.h @@ -0,0 +1,4 @@ +#pragma once + +#define min(a, b) ( (a < b) ? a : b ) +#define max(a, b) ( (a > b) ? a : b ) diff --git a/c/parse.c b/c/parse.c new file mode 100644 index 0000000..46b9b9c --- /dev/null +++ b/c/parse.c @@ -0,0 +1,70 @@ +#include + +#include "parse.h" + +int parse_base10_digit(char c) +{ + switch (c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + default: return -1; + } +} + +const char * parse_base10(const char * s, int * n) +{ + *n = 0; + int sign = 1; + + if (*s == '-') { + sign = -1; + s++; + } + + while (true) { + int digit = parse_base10_digit(*s); + if (digit == -1) + break; + + *n *= 10; + *n += digit; + s++; + } + + *n *= sign; + + return s; +} + +const char * parse_base10_64(const char * s, int64_t * n) +{ + *n = 0; + int sign = 1; + + if (*s == '-') { + sign = -1; + s++; + } + + while (true) { + int digit = parse_base10_digit(*s); + if (digit == -1) + break; + + *n *= 10; + *n += digit; + s++; + } + + *n *= sign; + + return s; +} diff --git a/c/parse.h b/c/parse.h new file mode 100644 index 0000000..3e7f4e4 --- /dev/null +++ b/c/parse.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +const char * parse_skip(const char * s, char c); +const char * parse_find(const char * s, char c); +const char * parse_find_first_right(const char * s, int length, char c); +int parse_base10_digit(char c); +const char * parse_base10(const char * s, int * n); +const char * parse_base10_64(const char * s, int64_t * n); +const char * parse_match(const char * s, const char * m); +int parse_stride(const char * s, int length); +int parse_height(const char * s, int length); + +#ifdef __cplusplus +} +#endif diff --git a/c/print_class.c b/c/print_class.c index 6afb9a7..de2e771 100644 --- a/c/print_class.c +++ b/c/print_class.c @@ -1,3 +1,5 @@ +#include + #include "assert.h" #include "debug_class_file.h" #include "file.h" @@ -6,10 +8,14 @@ int main(int argc, char * argv[]) { assert(argc >= 2); - uint8_t * buf = file_read(argv[1]); + size_t file_size; + uint8_t * buf = file_read(argv[1], &file_size); struct class_file * class_file = class_file_parse(buf); print_class_file(class_file); + (void)file_size; + free(buf); + return 0; } diff --git a/c/printf_dreamcast.c b/c/printf.c similarity index 78% rename from c/printf_dreamcast.c rename to c/printf.c index 7d4ae66..97db667 100644 --- a/c/printf_dreamcast.c +++ b/c/printf.c @@ -1,5 +1,4 @@ #include -#include #include #include "parse.h" @@ -8,8 +7,10 @@ #include "sh7091_scif.h" enum format_type { + FORMAT_BASE10_UNSIGNED, FORMAT_BASE10, FORMAT_BASE10_64, + FORMAT_POINTER, FORMAT_BASE16, FORMAT_STRING, FORMAT_CHAR, @@ -28,7 +29,10 @@ static const char * parse_fill_pad(const char * format, struct format * ft) { if (*format == 0) return format; - ft->fill_char = *format++; + if (*format >= '1' || *format <= '9') + ft->fill_char = ' '; + else + ft->fill_char = *format++; format = parse_base10(format, &ft->pad_length); return parse_escape(format, ft); } @@ -38,12 +42,18 @@ static const char * parse_escape(const char * format, struct format * ft) switch (*format) { case 0: return format; + case 'u': + ft->type = FORMAT_BASE10_UNSIGNED; + return format + 1; case 'd': ft->type = FORMAT_BASE10; return format + 1; case 'l': ft->type = FORMAT_BASE10_64; return format + 1; + case 'p': + ft->type = FORMAT_POINTER; + return format + 1; case 'x': ft->type = FORMAT_BASE16; return format + 1; @@ -61,8 +71,6 @@ static const char * parse_escape(const char * format, struct format * ft) } } -struct output_buffer global_output_buffer = {0}; - void print_string(const char * s, int length) { for (int i = 0; i < length; i++) { @@ -70,6 +78,13 @@ void print_string(const char * s, int length) } } +void print_cstring(const char * s) +{ + while (*s != 0) { + print_char(*s++); + } +} + void _printf(const char * format, ...) { va_list args; @@ -85,12 +100,20 @@ void _printf(const char * format, ...) struct format ft = {0}; format = parse_escape(format + 1, &ft); switch (ft.type) { + case FORMAT_BASE10_UNSIGNED: + { + uint32_t num = va_arg(args, uint32_t); + char s[10]; + int offset = unparse_base10_unsigned(s, num, ft.pad_length, ft.fill_char); + print_string(s, offset); + } + break; case FORMAT_BASE10: { int32_t num = va_arg(args, int32_t); char s[10]; int offset = unparse_base10(s, num, ft.pad_length, ft.fill_char); - print_trings(s, offset); + print_string(s, offset); } break; case FORMAT_BASE10_64: @@ -101,6 +124,12 @@ void _printf(const char * format, ...) print_string(s, offset); } break; + case FORMAT_POINTER: + { + print_char('0'); + print_char('x'); + } + [[fallthrough]]; case FORMAT_BASE16: { uint32_t num = va_arg(args, uint32_t); diff --git a/c/printf.h b/c/printf.h index 6a53840..fcbeaa2 100644 --- a/c/printf.h +++ b/c/printf.h @@ -1,11 +1,34 @@ #pragma once -#if defined(__linux__) -#include "printf_hosted.h" -#elif defined(_WIN32) -#include "printf_hosted.h" -#elif defined(__APPLE__) -#include "printf_hosted.h" +#if defined(__dreamcast__) +#include "sh7091_scif.h" #else -#include "printf_dreamcast.h" +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void print_char(char c) +{ +#if defined(__dreamcast__) + scif_character(c); +#else + fputc(c, stderr); +#endif +} + +void print_string(const char * s, int length); +void print_cstring(const char * s); + +void _printf(const char * format, ...); + +#define printf(...) _printf(__VA_ARGS__) +#define debugf(...) _printf(__VA_ARGS__) +#define debugc(c) print_char(c) +#define debugs(s) print_cstring(s) + +#ifdef __cplusplus +} #endif diff --git a/c/printf_dreamcast.h b/c/printf_dreamcast.h deleted file mode 100644 index 607552b..0000000 --- a/c/printf_dreamcast.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -static inline void print_char(char c) -{ - scif_character(c); -} - -void print_string(const char * s, int length) -{ - for (int i = 0; i < length; i++) { - print_char(s[i]); - } -} - -#define printf(...) _printf(__VA_ARGS__) -#define debugf(...) _printf(__VA_ARGS__) -#define debugc(c) print_char(c) diff --git a/c/printf_hosted.h b/c/printf_hosted.h deleted file mode 100644 index a0ed230..0000000 --- a/c/printf_hosted.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include - -#define debugf(...) printf(__VA_ARGS__) -#define debugc(c) putc(stdout, c) diff --git a/c/unparse.c b/c/unparse.c new file mode 100644 index 0000000..820e18e --- /dev/null +++ b/c/unparse.c @@ -0,0 +1,194 @@ +#include + +#include "minmax.h" +#include "unparse.h" + +int digits_base10(uint32_t n) +{ + if (n >= 1000000000ul) return 10; + if (n >= 100000000ul) return 9; + if (n >= 10000000ul) return 8; + if (n >= 1000000ul) return 7; + if (n >= 100000ul) return 6; + if (n >= 10000ul) return 5; + if (n >= 1000ul) return 4; + if (n >= 100ul) return 3; + if (n >= 10ul) return 2; + return 1; +} + +int unparse_base10_unsigned(char * s, uint32_t n, int len, char fill) +{ + int digits = 0; + digits += digits_base10(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +int unparse_base10(char * s, int32_t n, int len, char fill) +{ + bool negative = false; + int digits = 0; + if (n < 0) { + digits += 1; + n = -n; + negative = true; + } + + digits += digits_base10(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + if (negative) { + *s++ = '-'; + len--; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +int digits_base10_64(uint64_t n) +{ + if (n >= 10000000000000000000ull) return 20; + if (n >= 1000000000000000000ull) return 19; + if (n >= 100000000000000000ull) return 18; + if (n >= 10000000000000000ull) return 17; + if (n >= 1000000000000000ull) return 16; + if (n >= 100000000000000ull) return 15; + if (n >= 10000000000000ull) return 14; + if (n >= 1000000000000ull) return 13; + if (n >= 100000000000ull) return 12; + if (n >= 10000000000ull) return 11; + if (n >= 1000000000ull) return 10; + if (n >= 100000000ull) return 9; + if (n >= 10000000ull) return 8; + if (n >= 1000000ull) return 7; + if (n >= 100000ull) return 6; + if (n >= 10000ull) return 5; + if (n >= 1000ull) return 4; + if (n >= 100ull) return 3; + if (n >= 10ull) return 2; + return 1; +} + +int unparse_base10_64(char * s, int64_t n, int len, char fill) +{ + bool negative = false; + int digits = 0; + if (n < 0) { + digits += 1; + n = -n; + negative = true; + } + + digits += digits_base10_64(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + if (negative) { + *s++ = '-'; + len--; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +static int digits_base16(uint32_t n) +{ + if (n <= 0xf) return 1; + if (n <= 0xff) return 2; + if (n <= 0xfff) return 3; + if (n <= 0xffff) return 4; + if (n <= 0xfffff) return 5; + if (n <= 0xffffff) return 6; + if (n <= 0xfffffff) return 7; + return 8; +} + +int unparse_base16(char * s, uint32_t n, int len, char fill) +{ + int digits = digits_base16(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + while (len > 0) { + uint32_t nib = n & 0xf; + n = n >> 4; + if (nib > 9) { + nib += (97 - 10); + } else { + nib += (48 - 0); + } + + s[--len] = nib; + } + + return ret; +} + +#ifdef UNPARSE_TEST +#include + +int main() +{ + char s[1024]; + + { + int n = 124; + + int offset = unparse_base10(s, n, 6, ' '); + s[offset] = 0; + + printf("`%s`\n", s); + } + + { + int n = 0x5678; + + int offset = unparse_base16(s, n, 7, '0'); + s[offset] = 0; + + printf("`%s`\n", s); + } +} +#endif diff --git a/c/unparse.h b/c/unparse.h new file mode 100644 index 0000000..3f80008 --- /dev/null +++ b/c/unparse.h @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int unparse_base10_unsigned(char * s, uint32_t n, int len, char fill); +int unparse_base10(char * s, int32_t n, int len, char fill); +int unparse_base10_64(char * s, int64_t n, int len, char fill); +int unparse_base16(char * s, uint32_t n, int len, char fill); + +int digits_base_64(uint64_t n); +int digits_base10_64(uint64_t n); + +#ifdef __cplusplus +} +#endif