[gamecode] Add support for holding ephemeral strings

PR_HoldString converts ephemeral (temp and return) strings to dynamic
strings. This makes dealing with strings in progs a little easier.
This commit is contained in:
Bill Currie 2020-03-26 16:36:29 +09:00
parent b4874f7d9b
commit ec82d6b027
2 changed files with 46 additions and 2 deletions

View file

@ -1344,6 +1344,18 @@ string_t PR_NewMutableString (progs_t *pr);
*/
string_t PR_SetDynamicString (progs_t *pr, const char *s);
/** Convert an ephemeral string to a dynamic string.
Valid strings that are not ephemeral (static, dynamic, mutable) will not
be affected, but temp and return strings will be marked dynamic, requiring
a call to PR_FreeString to return their memory.
\param pr pointer to ::progs_t VM struct
\param str The string to be "held" (made non-ephemeral). Safe to call
on any valid string, but affects only ephemeral strings.
*/
void PR_HoldString (progs_t *pr, string_t str);
/** Destroy a mutable, dynamic or temporary string.
\param pr pointer to ::progs_t VM struct
\param str string index of the string to be destroyed

View file

@ -449,8 +449,8 @@ PR_SetReturnString (progs_t *pr, const char *s)
}
// grab the string ref from the oldest slot, or make a new one if the
// slot is empty
if ((sr = res->rs_slot->strref)) {
// slot is empty or the string has been held
if ((sr = res->rs_slot->strref) && sr->type != str_dynamic) {
if (sr->type != str_return || sr->rs_slot != res->rs_slot) {
PR_Error (pr, "internal string error: %d", __LINE__);
}
@ -592,6 +592,33 @@ PR_NewMutableString (progs_t *pr)
return string_index (res, sr);
}
VISIBLE void
PR_HoldString (progs_t *pr, string_t str)
{
prstr_resources_t *res = pr->pr_string_resources;
strref_t *sr = get_strref (res, str);
if (sr) {
switch (sr->type) {
case str_temp:
case str_return:
break;
case str_static:
case str_mutable:
case str_dynamic:
// non-ephemeral string, no-op
return;
default:
PR_Error (pr, "internal string error: %d", __LINE__);
}
sr->type = str_dynamic;
return;
}
if (!PR_StringValid (pr, str)) {
PR_RunError (pr, "attempt to hold invalid string %d", str);
}
}
VISIBLE void
PR_FreeString (progs_t *pr, string_t str)
{
@ -629,6 +656,11 @@ PR_FreeTempStrings (progs_t *pr)
for (sr = pr->pr_xtstr; sr; sr = t) {
t = sr->next;
if (sr->type == str_dynamic) {
// the string has been held, so simply remove the ref from the
// queue
continue;
}
if (sr->type != str_temp)
PR_Error (pr, "internal string error: %d", __LINE__);
if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr)