diff --git a/include/QF/progs.h b/include/QF/progs.h index 628070307..7564ab36d 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -156,7 +156,7 @@ qboolean PR_EdictValid (progs_t *pr, int e); #define R_FUNCTION(p) R_var (p, func) #define R_POINTER(p) R_var (p, pointer) -#define RETURN_STRING(p, s) (R_STRING (p) = PR_SetString((p), s)) +#define RETURN_STRING(p, s) (R_STRING (p) = PR_SetTempString((p), s)) #define RETURN_EDICT(p, e) (R_STRING (p) = EDICT_TO_PROG(p, e)) #define RETURN_POINTER(pr,p) (R_POINTER (pr) = POINTER_TO_PROG (pr, p)) #define RETURN_VECTOR(p, v) (VectorCopy (v, R_VECTOR (p))) @@ -221,7 +221,12 @@ int PR_InitRuntime (progs_t *pr); qboolean PR_StringValid (progs_t *pr, int num); const char *PR_GetString(progs_t *pr, int num); +struct dstring_s *PR_GetDString(progs_t *pr, int num); int PR_SetString(progs_t *pr, const char *s); +int PR_SetTempString(progs_t *pr, const char *s); +int PR_NewString (progs_t *pr); +void PR_FreeString (progs_t *pr, int str); +void PR_FreeTempStrings (progs_t *pr); void PR_GarbageCollect (progs_t *pr); // @@ -282,14 +287,9 @@ void PR_Cmds_Init (progs_t *pr); typedef struct { int s; dfunction_t *f; + struct strref_s *tstr; } prstack_t; -typedef struct strref_s { - struct strref_s *next; - char *string; - int count; -} strref_t; - struct progs_s { const char *progs_name; dprograms_t *progs; @@ -308,12 +308,14 @@ struct progs_s { pr_load_func_t **load_funcs; // garbage collected strings - strref_t *static_strings; - strref_t **dynamic_strings; - strref_t *free_string_refs; + struct dstring_mem_s *ds_mem; + struct strref_s *static_strings; + struct strref_s **dynamic_strings; + struct strref_s *free_string_refs; unsigned dyn_str_size; struct hashtab_s *strref_hash; int num_strings; + struct strref_s *pr_xtstr; dfunction_t *pr_functions; char *pr_strings; diff --git a/libs/gamecode/engine/pr_exec.c b/libs/gamecode/engine/pr_exec.c index b06f9136c..a00cf9bde 100644 --- a/libs/gamecode/engine/pr_exec.c +++ b/libs/gamecode/engine/pr_exec.c @@ -137,6 +137,7 @@ PR_EnterFunction (progs_t * pr, dfunction_t *f) pr->pr_xfunction = f; pr->pr_xstatement = f->first_statement - 1; // offset the st++ + pr->pr_xtstr = 0; return; } @@ -158,10 +159,14 @@ PR_LeaveFunction (progs_t * pr) &pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c); + if (pr->pr_xtstr) + PR_FreeTempStrings (pr); + // up stack pr->pr_depth--; pr->pr_xfunction = pr->pr_stack[pr->pr_depth].f; pr->pr_xstatement = pr->pr_stack[pr->pr_depth].s; + pr->pr_xtstr = pr->pr_stack[pr->pr_depth].tstr; } #define OPA (*op_a) @@ -280,7 +285,7 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) char *c = Hunk_TempAlloc (size); strcpy (c, a); strcpy (c + lena, b); - OPC.string_var = PR_SetString (pr, c); + OPC.string_var = PR_SetTempString (pr, c); } break; case OP_SUB_F: diff --git a/libs/gamecode/engine/pr_load.c b/libs/gamecode/engine/pr_load.c index 54360dc89..3c98e794f 100644 --- a/libs/gamecode/engine/pr_load.c +++ b/libs/gamecode/engine/pr_load.c @@ -99,16 +99,14 @@ free_progs_mem (progs_t *pr, void *mem) void PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) { - unsigned int i; + unsigned i; + int mem_size; dprograms_t progs; pr->progs = 0; if (Qread (file, &progs, sizeof (progs)) != sizeof (progs)) PR_Error (pr, "error reading header"); - pr->progs_size = size; - Sys_DPrintf ("Programs occupy %iK.\n", size / 1024); - // store prog crc pr->crc = CRC_Block ((byte*)&progs, sizeof (progs)); @@ -137,6 +135,7 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) // size of progs themselves pr->progs_size = size; + Sys_DPrintf ("Programs occupy %iK.\n", size / 1024); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned @@ -174,10 +173,11 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) PR_Resources_Clear (pr); if (pr->progs) pr->free_progs_mem (pr, pr->progs); - pr->progs = pr->allocate_progs_mem (pr, pr->progs_size + pr->zone_size - + pr->pr_edictareasize); + mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize; + pr->progs = pr->allocate_progs_mem (pr, mem_size + 1); if (!pr->progs) return; + ((byte *) pr->progs)[mem_size] = 0; memcpy (pr->progs, &progs, sizeof (progs)); Qread (file, pr->progs + 1, size - sizeof (progs)); @@ -194,7 +194,7 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) pr->pr_functions = (dfunction_t *) ((byte *) pr->progs + pr->progs->ofs_functions); pr->pr_strings = (char *) pr->progs + pr->progs->ofs_strings; - pr->pr_stringsize = pr->progs->numstrings; + pr->pr_stringsize = (char *) pr->zone + pr->zone_size - (char *) pr->progs; pr->pr_globaldefs = (ddef_t *) ((byte *) pr->progs + pr->progs->ofs_globaldefs); pr->pr_fielddefs = diff --git a/libs/gamecode/engine/pr_strings.c b/libs/gamecode/engine/pr_strings.c index 9f02d6336..57b7ae7ad 100644 --- a/libs/gamecode/engine/pr_strings.c +++ b/libs/gamecode/engine/pr_strings.c @@ -41,9 +41,37 @@ static __attribute__ ((unused)) const char rcsid[] = #include #include +#include "QF/dstring.h" #include "QF/hash.h" #include "QF/progs.h" +typedef struct strref_s { + struct strref_s *next; + char *string; + dstring_t *dstring; + int count; +} strref_t; + +static void * +pr_strings_alloc (void *_pr, size_t size) +{ + progs_t *pr = (progs_t *) _pr; + return PR_Zone_Malloc (pr, size); +} + +static void +pr_strings_free (void *_pr, void *ptr) +{ + progs_t *pr = (progs_t *) _pr; + PR_Zone_Free (pr, ptr); +} + +static void * +pr_strings_realloc (void *_pr, void *ptr, size_t size) +{ + progs_t *pr = (progs_t *) _pr; + return PR_Zone_Realloc (pr, ptr, size); +} static strref_t * new_string_ref (progs_t *pr) @@ -74,6 +102,7 @@ static void free_string_ref (progs_t *pr, strref_t *sr) { sr->string = 0; + sr->dstring = 0; sr->next = pr->free_string_refs; pr->free_string_refs = sr; } @@ -110,7 +139,7 @@ strref_free (void *_sr, void *_pr) // free the string and ref only if it's not a static string if (sr < pr->static_strings || sr >= pr->static_strings + pr->num_strings) { - free (sr->string); + PR_Zone_Free (pr, sr->string); free_string_ref (pr, sr); } } @@ -126,6 +155,14 @@ PR_LoadStrings (progs_t *pr) count++; str += strlen (str) + 1; } + + if (!pr->ds_mem) { + pr->ds_mem = malloc (sizeof (dstring_mem_t)); + pr->ds_mem->alloc = pr_strings_alloc; + pr->ds_mem->free = pr_strings_free; + pr->ds_mem->realloc = pr_strings_realloc; + pr->ds_mem->data = pr; + } if (pr->strref_hash) { Hash_FlushTable (pr->strref_hash); } else { @@ -138,7 +175,7 @@ PR_LoadStrings (progs_t *pr) if (pr->static_strings) free (pr->static_strings); - pr->static_strings = calloc (count, sizeof (strref_t)); + pr->static_strings = malloc (count * sizeof (strref_t)); count = 0; str = pr->pr_strings; while (str < end) { @@ -198,8 +235,8 @@ PR_GarbageCollect (progs_t *pr) } } -static inline char * -get_string (progs_t *pr, int num) +static inline strref_t * +get_strref (progs_t *pr, int num) { if (num < 0) { unsigned int row = ~num / 1024; @@ -208,7 +245,22 @@ get_string (progs_t *pr, int num) if (row >= pr->dyn_str_size) return 0; - return pr->dynamic_strings[row][num].string; + return &pr->dynamic_strings[row][num]; + } else { + return 0; + } +} + +static inline const char * +get_string (progs_t *pr, int num) +{ + if (num < 0) { + strref_t *ref = get_strref (pr, num); + if (!ref) + return 0; + if (ref->dstring) + return ref->dstring->str; + return ref->string; } else { if (num >= pr->pr_stringsize) return 0; @@ -225,24 +277,95 @@ PR_StringValid (progs_t *pr, int num) const char * PR_GetString (progs_t *pr, int num) { - char *str; + const char *str; str = get_string (pr, num); if (str) return str; - PR_RunError (pr, "Invalid string offset %u", num); + PR_RunError (pr, "Invalid string offset %d", num); +} + +dstring_t * +PR_GetDString (progs_t *pr, int num) +{ + strref_t *ref = get_strref (pr, num); + if (ref) { + if (ref->dstring) + return ref->dstring; + PR_RunError (pr, "not a dstring: %d", num); + } + PR_RunError (pr, "Invalid string offset: %d", num); +} + +static inline char * +pr_strdup (progs_t *pr, const char *s) +{ + size_t len = strlen (s) + 1; + char *new = PR_Zone_Malloc (pr, len); + strcpy (new, s); + return new; } int PR_SetString (progs_t *pr, const char *s) { - strref_t *sr = Hash_Find (pr->strref_hash, s); + strref_t *sr = Hash_Find (pr->strref_hash, s); if (!sr) { sr = new_string_ref (pr); - sr->string = strdup(s); + sr->string = pr_strdup(pr, s); sr->count = 0; Hash_Add (pr->strref_hash, sr); } return string_index (pr, sr); } + +int +PR_SetTempString (progs_t *pr, const char *s) +{ + strref_t *sr; + + sr = new_string_ref (pr); + sr->string = pr_strdup(pr, s); + sr->count = 0; + sr->next = pr->pr_xtstr; + pr->pr_xtstr = sr; + return string_index (pr, sr); +} + +int +PR_NewString (progs_t *pr) +{ + strref_t *sr = new_string_ref (pr); + sr->dstring = _dstring_newstr (pr->ds_mem); + return string_index (pr, sr); +} + +void +PR_FreeString (progs_t *pr, int str) +{ + strref_t *sr = get_strref (pr, str); + + if (sr) { + if (sr->dstring) + dstring_delete (sr->dstring); + else + PR_Zone_Free (pr, sr->string); + free_string_ref (pr, sr); + return; + } + PR_RunError (pr, "attempt to free invalid string %d", str); +} + +void +PR_FreeTempStrings (progs_t *pr) +{ + strref_t *sr, *t; + + for (sr = pr->pr_xtstr; sr; sr = t) { + t = sr->next; + PR_Zone_Free (pr, sr->string); + free_string_ref (pr, sr); + } + pr->pr_xtstr = 0; +} diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index de6e0d364..d18523e8a 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -140,13 +140,8 @@ load_progs (const char *name) pr.progs_name = name; PR_LoadProgsFile (&pr, file, size, 1, 1024 * 1024); Qclose (file); - if (!PR_ResolveGlobals (&pr)) + if (!PR_RunLoadFuncs (&pr)) PR_Error (&pr, "unable to load %s", pr.progs_name); - PR_LoadStrings (&pr); - PR_LoadDebug (&pr); - PR_Check_Opcodes (&pr); - PR_RelocateBuiltins (&pr); - PR_InitRuntime (&pr); return 1; } diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc index 01f606f96..74b199b7b 100644 --- a/tools/qwaq/main.qc +++ b/tools/qwaq/main.qc @@ -1,3 +1,13 @@ +void () test_str = +{ + local string a,b,c,d; + a = "testing "; + b = "temp "; + c = "strings "; + d = "\n"; + print (a + b + c + d); +}; + integer (integer argc, string []argv) main = { local integer i; @@ -35,5 +45,6 @@ integer (integer argc, string []argv) main = print ("Object instances do not repond to `run:with:me:'\n"); } else print ("did not find selector for `run:with:me:'\n"); + test_str (); return 0; };