diff --git a/include/progs.h b/include/progs.h index 18bc7ec94..cfd24c057 100644 --- a/include/progs.h +++ b/include/progs.h @@ -79,6 +79,7 @@ void PR_Init_Cvars (void); void PR_ExecuteProgram (progs_t *pr, func_t fnum); void PR_LoadProgs (progs_t *pr, char *progsname); +void PR_LoadStrings (progs_t *pr); void PR_Profile_f (void); @@ -179,6 +180,13 @@ typedef struct { dfunction_t *f; } prstack_t; +typedef struct strref_s { + struct strref_s *next; + struct strref_s *prev; + char *string; + int count; +} strref_t; + struct progs_s { dprograms_t *progs; @@ -186,6 +194,12 @@ struct progs_s { struct hashtab_s *global_hash; struct hashtab_s *field_hash; + // garbage collected strings + strref_t *static_strings; + strref_t dynamic_strings[2]; // 0 = head, 1 = tail + struct hashtab_s *strref_hash; + int num_strings; + dfunction_t *pr_functions; char *pr_strings; int pr_stringsize; diff --git a/libs/gamecode/Makefile.am b/libs/gamecode/Makefile.am index d917abc38..8fc7f9c23 100644 --- a/libs/gamecode/Makefile.am +++ b/libs/gamecode/Makefile.am @@ -1,6 +1,6 @@ noinst_LIBRARIES = libqfgamecode.a -libqfgamecode_a_SOURCES = pr_edict.c pr_exec.c +libqfgamecode_a_SOURCES = pr_edict.c pr_exec.c pr_strings.c all-local: ../libqfgamecode.a diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index b34fa1662..780ab6702 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -1052,6 +1052,9 @@ PR_LoadProgs (progs_t * pr, char *progsname) if ((pr->fields.think = ED_GetFieldIndex (pr, "think")) == -1) PR_Error (pr, "%s: undefined field: think", progsname); + // initialise the strings managment code + PR_LoadStrings (pr); + // LordHavoc: bounds check anything static for (i = 0, st = pr->pr_statements; i < pr->progs->numstatements; i++, st++) { switch (st->op) { diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index b2c86562b..b661d03bb 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -960,35 +960,3 @@ PR_ExecuteProgram (progs_t * pr, func_t fnum) } } } - -char * -PR_GetString (progs_t * pr, int num) -{ - if (num < 0) { - //Con_DPrintf("GET:%d == %s\n", num, pr->pr_strtbl[-num]); - return pr->pr_strtbl[-num]; - } - return pr->pr_strings + num; -} - -int -PR_SetString (progs_t * pr, char *s) -{ - int i = s - pr->pr_strings; - - if (i < 0 || i > pr->pr_stringsize) { - for (i = 1; i <= pr->num_prstr; i++) - if (pr->pr_strtbl[i] == s - || strequal (pr->pr_strtbl[i], s)) - break; - if (i < pr->num_prstr) - return -i; - if (pr->num_prstr == MAX_PRSTR - 1) - Sys_Error ("MAX_PRSTR"); - pr->num_prstr++; - pr->pr_strtbl[pr->num_prstr] = s; - //Con_DPrintf("SET:%d == %s\n", -pr->num_prstr, s); - return -pr->num_prstr; - } - return (int) (s - pr->pr_strings); -} diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c new file mode 100644 index 000000000..2477627f7 --- /dev/null +++ b/libs/gamecode/pr_strings.c @@ -0,0 +1,134 @@ +/* + pr_strings.c + + progs string managment + + Copyright (C) 1996-1997 Id Software, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include + +#include "hash.h" +#include "progs.h" + +static char * +strref_get_key (void *_sr, void *notused) +{ + strref_t *sr = (strref_t*)_sr; + return sr->string; +} + +static void +strref_free (void *_sr, void *_pr) +{ + progs_t *pr = (progs_t*)_pr; + strref_t *sr = (strref_t*)_sr; + + // 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); + + sr->next->prev = sr->prev; + sr->prev->next = sr->next; + + free (sr); + } +} + +void +PR_LoadStrings (progs_t *pr) +{ + int count = 0; + char *end = pr->pr_strings + pr->pr_stringsize; + char *str = pr->pr_strings; + + while (str < end) { + count++; + str += strlen (str) + 1; + } + if (pr->strref_hash) { + Hash_FlushTable (pr->strref_hash); + } else { + pr->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, pr); + } + + pr->dynamic_strings[0].next = &pr->dynamic_strings[1]; + pr->dynamic_strings[0].prev = 0; + pr->dynamic_strings[1].next = 0; + pr->dynamic_strings[1].prev = &pr->dynamic_strings[1]; + + if (pr->static_strings) + free (pr->static_strings); + pr->static_strings = calloc (count, sizeof (strref_t)); + count = 0; + str = pr->pr_strings; + while (str < end) { + pr->static_strings[count].string = str; + str += strlen (str) + 1; + Hash_Add (pr->strref_hash, &pr->static_strings[count]); + count++; + } + pr->num_strings = count; +} + +char * +PR_GetString (progs_t *pr, int num) +{ + return pr->pr_strings + num; +} + +int +PR_SetString (progs_t *pr, char *s) +{ + strref_t *sr = Hash_Find (pr->strref_hash, s); + + if (sr) { + s = sr->string; + } else { + sr = malloc (sizeof (strref_t)); + sr->string = strdup(s); + sr->count = 0; + + sr->next = pr->dynamic_strings[0].next; + sr->prev = pr->dynamic_strings[0].next->prev; + + pr->dynamic_strings[0].next->prev = sr; + pr->dynamic_strings[0].next = sr; + + Hash_Add (pr->strref_hash, sr); + + s = sr->string; + } + return (int) (s - pr->pr_strings); +} diff --git a/libs/util/hash.c b/libs/util/hash.c index b52f387be..ae670c6d1 100644 --- a/libs/util/hash.c +++ b/libs/util/hash.c @@ -98,7 +98,7 @@ Hash_FlushTable (hashtab_t *tab) while (tab->tab[i]) { hashlink_t *t = tab->tab[i]->next; if (tab->free_ele) - tab->free_ele (&tab->tab[i]->data, tab->user_data); + tab->free_ele (tab->tab[i]->data, tab->user_data); free (tab->tab[i]); tab->tab[i] = t; }