From 53dc8a7a447b982e7300f92979c48513a05448ca Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Mon, 7 Oct 2019 16:54:46 -0700 Subject: [PATCH] strings: store size together with text in memory --- ain.c | 23 ++++++++++++++++-- ain.h | 6 +++-- string.c | 45 +++++++++++++++++------------------- vm.c | 26 ++++++++++----------- sys4_string.h => vm_string.h | 12 +++++----- 5 files changed, 64 insertions(+), 48 deletions(-) rename sys4_string.h => vm_string.h (80%) diff --git a/ain.c b/ain.c index 760b325..5eeec69 100644 --- a/ain.c +++ b/ain.c @@ -28,6 +28,7 @@ #include "ain.h" #include "little_endian.h" #include "instructions.h" +#include "vm_string.h" static const char *errtab[AIN_MAX_ERROR] = { [AIN_SUCCESS] = "Success", @@ -86,6 +87,24 @@ static char **read_strings(struct ain_reader *r, int count) return strings; } +static struct string *read_vm_string(struct ain_reader *r) +{ + size_t len = strlen((char*)r->buf + r->index); + struct string *s = make_string((char*)r->buf + r->index, len); + s->literal = true; + r->index += len + 1; + return s; +} + +static struct string **read_vm_strings(struct ain_reader *r, int count) +{ + struct string **strings = calloc(count, sizeof(struct string*)); + for (int i = 0; i < count; i++) { + strings[i] = read_vm_string(r); + } + return strings; +} + static struct ain_variable *read_variables(struct ain_reader *r, int count) { struct ain_variable *variables = calloc(count, sizeof(struct ain_variable)); @@ -260,7 +279,7 @@ static bool read_tag(struct ain_reader *r, struct ain *ain) int32_t count = read_int32(r); ain->structures = read_structures(r, count); } else if (TAG_EQ("MSG0")) { - ain->messages = read_strings(r, read_int32(r)); + ain->messages = read_vm_strings(r, read_int32(r)); } else if (TAG_EQ("MAIN")) { ain->main = read_int32(r); } else if (TAG_EQ("MSGF")) { @@ -274,7 +293,7 @@ static bool read_tag(struct ain_reader *r, struct ain *ain) } else if (TAG_EQ("GVER")) { ain->game_version = read_int32(r); } else if (TAG_EQ("STR0")) { - ain->strings = read_strings(r, read_int32(r)); + ain->strings = read_vm_strings(r, read_int32(r)); } else if (TAG_EQ("FNAM")) { ain->filenames = read_strings(r, read_int32(r)); } else if (TAG_EQ("OJMP")) { diff --git a/ain.h b/ain.h index e7cf2bc..2dc19ed 100644 --- a/ain.h +++ b/ain.h @@ -21,6 +21,8 @@ #include #include +#include "vm_string.h" + struct ain; enum ain_error { @@ -160,13 +162,13 @@ struct ain { struct ain_global *globals; struct ain_initval *global_initvals; struct ain_struct *structures; - char **messages; + struct string **messages; int32_t main; int32_t msgf; struct ain_library *libraries; struct ain_switch *switches; int32_t game_version; - char **strings; + struct string **strings; char **filenames; int32_t ojmp; struct ain_function_type *function_types; diff --git a/string.c b/string.c index 54c2ceb..e49f33f 100644 --- a/string.c +++ b/string.c @@ -18,45 +18,42 @@ #include #include #include "system4.h" -#include "sys4_string.h" +#include "vm_string.h" -struct string make_string(char *str, size_t len) +struct string *make_string(const char *str, unsigned int len) { - return (struct string) { - .str = str, - .len = len, - .mutable = false - }; + struct string *s = xmalloc(sizeof(struct string) + len + 1); + s->size = len; + s->literal = false; + memcpy(s->text, str, len); + s->text[len] = '\0'; + return s; } void free_string(struct string *str) { - if (str->mutable) - free(str->str); + if (!str->literal) + free(str); } -void string_add(struct string *a, struct string *b) +struct string *string_append(struct string *a, struct string *b) { - if (a->mutable) { - a->str = xrealloc(a->str, a->len + b->len + 1); + if (!a->literal) { + a = xrealloc(a, sizeof(struct string) + a->size + b->size + 1); } else { - char *literal = a->str; - a->str = xmalloc(a->len + b->len + 1); - memcpy(a->str, literal, a->len + 1); + struct string *tmp = xmalloc(sizeof(struct string) + a->size + b->size + 1); + memcpy(tmp, a, sizeof(struct string) + a->size); + a = tmp; } - memcpy(a->str + a->len, b->str, b->len + 1); - a->len = a->len + b->len; + memcpy(a->text + a->size, b->text, b->size + 1); + a->size = a->size + b->size; + return a; } -struct string integer_to_string(int n) +struct string *integer_to_string(int n) { char buf[513]; int len = snprintf(buf, 512, "%d" ,n); buf[512] = '\0'; - - return (struct string) { - .str = xstrdup(buf), - .len = len, - .mutable = true - }; + return make_string(buf, len); } diff --git a/vm.c b/vm.c index 997a60f..b1f293e 100644 --- a/vm.c +++ b/vm.c @@ -18,7 +18,7 @@ #include #include "system4.h" -#include "sys4_string.h" +#include "vm_string.h" #include "ain.h" #include "instructions.h" #include "little_endian.h" @@ -35,7 +35,7 @@ static int stack_ptr = 0; // Separate stack for strings // Not sure exactly how System40.exe handles strings. // Further testing required to ensure this approach doesn't break anything. -static struct string string_stack[1024]; +static struct string *string_stack[1024]; static int string_stack_ptr = 0; //static struct frame *frame_stack[1024]; @@ -93,16 +93,15 @@ static int32_t stack_pop_ref(void) static void stack_push_string_literal(int32_t no) { - // FIXME: should store string length when reading AIN - string_stack[string_stack_ptr++] = make_string(ain->strings[no], strlen(ain->strings[no])); + string_stack[string_stack_ptr++] = ain->strings[no]; } static void stack_push_string(struct string *str) { - string_stack[string_stack_ptr++] = *str; + string_stack[string_stack_ptr++] = str; } -static struct string stack_pop_string(void) +static struct string *stack_pop_string(void) { string_stack_ptr--; return string_stack[string_stack_ptr]; @@ -111,12 +110,12 @@ static struct string stack_pop_string(void) static void stack_toss_string(void) { string_stack_ptr--; - free_string(&string_stack[string_stack_ptr]); + free_string(string_stack[string_stack_ptr]); } static struct string *stack_peek_string(void) { - return &string_stack[string_stack_ptr-1]; + return string_stack[string_stack_ptr-1]; } /* @@ -158,7 +157,7 @@ static void system_call(int32_t code) sys_exit(stack_pop()); break; case 0x6: // system.Output(string szText) - sys_message("%s", stack_peek_string()->str); + sys_message("%s", stack_peek_string()->text); // XXX: caller S_POPs break; case 0x14: // system.Peek() @@ -174,7 +173,7 @@ static void system_call(int32_t code) static void execute_instruction(int16_t opcode) { int32_t index, a, b, v; - struct string sa, sb; + struct string *sa, *sb; const char *opcode_name = "UNKNOWN"; switch (opcode) { // @@ -396,12 +395,11 @@ static void execute_instruction(int16_t opcode) case S_ADD: sb = stack_pop_string(); sa = stack_pop_string(); - string_add(&sa, &sb); - stack_push_string(&sa); + sa = string_append(sa, sb); + stack_push_string(sa); break; case I_STRING: - sa = integer_to_string(stack_pop()); - stack_push_string(&sa); + stack_push_string(integer_to_string(stack_pop())); break; // -- NOOPs --- case FUNC: diff --git a/sys4_string.h b/vm_string.h similarity index 80% rename from sys4_string.h rename to vm_string.h index 82f506f..7e64b6a 100644 --- a/sys4_string.h +++ b/vm_string.h @@ -21,14 +21,14 @@ #include struct string { - char *str; - size_t len; - bool mutable; + unsigned int size; + bool literal; + char text[]; }; -struct string make_string(char *str, size_t len); +struct string *make_string(const char *str, unsigned int len); void free_string(struct string *str); -void string_add(struct string *a, struct string *b); -struct string integer_to_string(int n); +struct string *string_append(struct string *a, struct string *b); +struct string *integer_to_string(int n); #endif