diff --git a/include/QF/progs.h b/include/QF/progs.h index 66009b0a7..2547b83fb 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -160,7 +160,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_SetTempString((p), s)) +#define RETURN_STRING(p, s) (R_STRING (p) = PR_SetReturnString((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))) @@ -251,9 +251,11 @@ 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_SetReturnString(progs_t *pr, const char *s); int PR_SetTempString(progs_t *pr, const char *s); void PR_MakeTempString(progs_t *pr, int str); int PR_NewString (progs_t *pr); +void PR_ClearReturnStrings (progs_t *pr); void PR_FreeString (progs_t *pr, int str); void PR_FreeTempStrings (progs_t *pr); void PR_Sprintf (progs_t *pr, struct dstring_s *result, const char *name, @@ -313,6 +315,7 @@ void PR_Cmds_Init (progs_t *pr); #define MAX_STACK_DEPTH 64 #define LOCALSTACK_SIZE 4096 +#define PR_RS_SLOTS 16 typedef struct strref_s strref_t; @@ -346,6 +349,8 @@ struct progs_s { struct dstring_mem_s *ds_mem; strref_t *static_strings; strref_t **dynamic_strings; + strref_t *return_strings[PR_RS_SLOTS]; + int rs_slot; unsigned dyn_str_size; struct hashtab_s *strref_hash; int num_strings; diff --git a/libs/gamecode/engine/pr_edict.c b/libs/gamecode/engine/pr_edict.c index 45de839ac..ab63efde8 100644 --- a/libs/gamecode/engine/pr_edict.c +++ b/libs/gamecode/engine/pr_edict.c @@ -422,8 +422,9 @@ ED_Print (progs_t *pr, edict_t *ed) continue; break; case ev_string: - if (!PR_GetString (pr, v->string_var)[0]) - continue; + if (PR_StringValid (pr, v->string_var)) + if (!PR_GetString (pr, v->string_var)[0]) + continue; break; case ev_float: if (!v->float_var) diff --git a/libs/gamecode/engine/pr_load.c b/libs/gamecode/engine/pr_load.c index 3c98e794f..37036df69 100644 --- a/libs/gamecode/engine/pr_load.c +++ b/libs/gamecode/engine/pr_load.c @@ -171,6 +171,7 @@ PR_LoadProgsFile (progs_t * pr, QFile *file, int size, int edicts, int zone) pr->free_progs_mem = free_progs_mem; PR_Resources_Clear (pr); + PR_ClearReturnStrings (pr); if (pr->progs) pr->free_progs_mem (pr, pr->progs); mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize; diff --git a/libs/gamecode/engine/pr_parse.c b/libs/gamecode/engine/pr_parse.c index 75726bc62..bb79d85a5 100644 --- a/libs/gamecode/engine/pr_parse.c +++ b/libs/gamecode/engine/pr_parse.c @@ -187,14 +187,14 @@ ED_WriteGlobals (progs_t *pr, QFile *f) } -static char * +static int ED_NewString (progs_t *pr, const char *string) { char *new, *new_p; int i, l; l = strlen (string) + 1; - new = Hunk_Alloc (l); + new = Hunk_TempAlloc (l); new_p = new; for (i = 0; i < l; i++) { @@ -208,7 +208,7 @@ ED_NewString (progs_t *pr, const char *string) *new_p++ = string[i]; } - return new; + return PR_SetString (pr, new); } @@ -232,7 +232,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) switch (key->type & ~DEF_SAVEGLOBAL) { case ev_string: - d->string_var = PR_SetString (pr, ED_NewString (pr, s)); + d->string_var = ED_NewString (pr, s); break; case ev_float: diff --git a/libs/gamecode/engine/pr_strings.c b/libs/gamecode/engine/pr_strings.c index 00d0d7304..b4c1c41f8 100644 --- a/libs/gamecode/engine/pr_strings.c +++ b/libs/gamecode/engine/pr_strings.c @@ -125,7 +125,7 @@ new_string_ref (progs_t *pr) } static void -free_string_ref (progs_t *pr, strref_t *sr) +free_string_ref (strref_t *sr) { sr->string = 0; sr->dstring = 0; @@ -169,7 +169,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_string_ref (pr, sr); + free_string_ref (sr); } } @@ -302,6 +302,41 @@ PR_SetString (progs_t *pr, const char *s) return string_index (pr, sr); } +void +PR_ClearReturnStrings (progs_t *pr) +{ + int i; + + for (i = 0; i < PR_RS_SLOTS; i++) + if (pr->return_strings[i]) + free_string_ref (pr->return_strings[i]); +} + +int +PR_SetReturnString (progs_t *pr, const char *s) +{ + strref_t *sr; + + if (!s) + s = ""; + if ((sr = Hash_Find (pr->strref_hash, s))) { + return string_index (pr, sr); + } + + if ((sr = pr->return_strings[pr->rs_slot])) { + if (sr->string) + PR_Zone_Free (pr, sr->string); + } else { + sr = new_string_ref (pr); + } + sr->string = pr_strdup(pr, s); + sr->count = 0; + + pr->return_strings[pr->rs_slot++] = sr; + pr->rs_slot %= PR_RS_SLOTS; + return string_index (pr, sr); +} + int PR_SetTempString (progs_t *pr, const char *s) { @@ -355,7 +390,7 @@ PR_FreeString (progs_t *pr, int str) dstring_delete (sr->dstring); else PR_Zone_Free (pr, sr->string); - free_string_ref (pr, sr); + free_string_ref (sr); return; } PR_RunError (pr, "attempt to free invalid string %d", str); @@ -369,7 +404,7 @@ PR_FreeTempStrings (progs_t *pr) for (sr = pr->pr_xtstr; sr; sr = t) { t = sr->next; PR_Zone_Free (pr, sr->string); - free_string_ref (pr, sr); + free_string_ref (sr); } pr->pr_xtstr = 0; }