/* Copyright (C) 1996-2001 Id Software, Inc. Copyright (C) 2002-2009 John Fitzgibbons and others Copyright (C) 2010-2014 QuakeSpasm developers Copyright (C) 2019 Alison G. Watson 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 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "q_defs.h" char const *pr_strings; char const **pr_knownstrings; int32_t pr_maxknownstrings; int32_t pr_numknownstrings; /* ============ PR_ValueString (etype_t type, eval_t *val) Returns a string describing *data in a type specific manner ============= */ const char *PR_ValueString(int32_t type, eval_t *val) { static char line[512]; ddef_t *def; dfunction_t *f; type &= ~DEF_SAVEGLOBAL; switch(type) { case ev_string: sprintf(line, "%s", PR_GetString(val->string)); break; case ev_entity: sprintf(line, "entity %" PRIi32, NumForEdict(ProgEdict(val->edict))); break; case ev_function: f = pr_functions + val->func; sprintf(line, "%s()", PR_GetString(f->s_name)); break; case ev_field: def = ED_FieldAtOfs(val->field); sprintf(line, ".%s", PR_GetString(def->s_name)); break; case ev_void: sprintf(line, "void"); break; case ev_float: sprintf(line, "%5.1f", val->flt); break; case ev_vector: sprintf(line, "'%5.1f %5.1f %5.1f'", val->vec[0], val->vec[1], val->vec[2]); break; case ev_pointer: sprintf(line, "pointer"); break; default: sprintf(line, "bad type %" PRIi32, type); break; } return line; } /* ============ PR_UglyValueString (etype_t type, eval_t *val) Returns a string describing *data in a type specific manner Easier to parse than PR_ValueString ============= */ const char *PR_UglyValueString(int32_t type, eval_t *val) { static char line[512]; ddef_t *def; dfunction_t *f; type &= ~DEF_SAVEGLOBAL; switch(type) { case ev_string: sprintf(line, "%s", PR_GetString(val->string)); break; case ev_entity: sprintf(line, "%" PRIi32, NumForEdict(ProgEdict(val->edict))); break; case ev_function: f = pr_functions + val->func; sprintf(line, "%s", PR_GetString(f->s_name)); break; case ev_field: def = ED_FieldAtOfs(val->field); sprintf(line, "%s", PR_GetString(def->s_name)); break; case ev_void: sprintf(line, "void"); break; case ev_float: sprintf(line, "%f", val->flt); break; case ev_vector: sprintf(line, "%f %f %f", val->vec[0], val->vec[1], val->vec[2]); break; default: sprintf(line, "bad type %" PRIi32, type); break; } return line; } /* ============ PR_GlobalString Returns a string with a description and the contents of a global, padded to 20 field width ============ */ const char *PR_GlobalString(int32_t ofs) { static char line[512]; const char *s; int32_t i; ddef_t *def; void *val; val = G_Void(ofs); def = ED_GlobalAtOfs(ofs); if(!def) sprintf(line, "%" PRIi32 "(?)", ofs); else { s = PR_ValueString(def->type, (eval_t *)val); sprintf(line, "%" PRIi32 "(%s)%s", ofs, PR_GetString(def->s_name), s); } i = strlen(line); for(; i < 20; i++) strcat(line, " "); strcat(line, " "); return line; } const char *PR_GlobalStringNoContents(int32_t ofs) { static char line[512]; int32_t i; ddef_t *def; def = ED_GlobalAtOfs(ofs); if(!def) sprintf(line, "%" PRIi32 "(?)", ofs); else sprintf(line, "%" PRIi32 "(%s)", ofs, PR_GetString(def->s_name)); i = strlen(line); for(; i < 20; i++) strcat(line, " "); strcat(line, " "); return line; } //=========================================================================== static void PR_AllocStringSlots(void) { pr_maxknownstrings += 256; Con_DPrintf2("PR_AllocStringSlots: realloc'ing for %" PRIi32 " slots\n", pr_maxknownstrings); pr_knownstrings = Z_Realloc(pr_knownstrings, pr_maxknownstrings * sizeof(*pr_knownstrings)); } const char *PR_GetString(int32_t num) { if(num >= 0 && num < progs.numstrings) return pr_strings + num; else if(num < 0 && num >= -pr_numknownstrings) { if(!pr_knownstrings[-1 - num]) { Host_Error("PR_GetString: attempt to get a non-existent string %" PRIi32 "\n", num); return ""; } return pr_knownstrings[-1 - num]; } else { Host_Error("PR_GetString: invalid string offset %" PRIi32 "\n", num); return ""; } } int32_t PR_SetEngineString(const char *s) { int32_t i; if(!s) return 0; if(s >= pr_strings && s <= pr_strings + progs.numstrings - 2) return (int32_t)(s - pr_strings); for(i = 0; i < pr_numknownstrings; i++) { if(pr_knownstrings[i] == s) return -1 - i; } if(i >= pr_maxknownstrings) PR_AllocStringSlots(); pr_numknownstrings++; pr_knownstrings[i] = s; return -1 - i; } int32_t PR_AllocString(int32_t size, char **ptr) { int32_t i; if(!size) return 0; for(i = 0; i < pr_numknownstrings; i++) { if(!pr_knownstrings[i]) break; } if(i >= pr_maxknownstrings) PR_AllocStringSlots(); pr_numknownstrings++; pr_knownstrings[i] = (char *)Hunk_AllocName(size, "string"); if(ptr) *ptr = (char *) pr_knownstrings[i]; return -1 - i; }