2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
29 int prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
31 ddef_t *PRVM_ED_FieldAtOfs(int ofs);
32 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s);
34 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
35 cvar_t prvm_boundscheck = {0, "prvm_boundscheck", "1", "enables detection of out of bounds memory access in the QuakeC code being run (in other words, prevents really exceedingly bad QuakeC code from doing nasty things to your computer)"};
36 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
37 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
38 // LordHavoc: counts usage of each QuakeC statement
39 cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
40 cvar_t prvm_tempstringmemory = {0, "prvm_tempstringmemory", "8388608", "amount of temporary string memory allowed in a single QuakeC invocation (QuakeC function call made by the engine)"};
42 //============================================================================
50 void PRVM_MEM_Alloc(void)
54 // reserve space for the null entity aka world
55 // check bound of max_edicts
56 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
57 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
59 // edictprivate_size has to be min as big prvm_edict_private_t
60 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
63 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
65 // alloc edict private space
66 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
69 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
72 for(i = 0; i < prog->max_edicts; i++)
74 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
75 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
81 PRVM_MEM_IncreaseEdicts
84 void PRVM_MEM_IncreaseEdicts(void)
87 int oldmaxedicts = prog->max_edicts;
88 void *oldedictsfields = prog->edictsfields;
89 void *oldedictprivate = prog->edictprivate;
91 if(prog->max_edicts >= prog->limit_edicts)
94 PRVM_GCALL(begin_increase_edicts)();
97 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
99 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
100 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
102 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
103 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
105 //set e and v pointers
106 for(i = 0; i < prog->max_edicts; i++)
108 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
109 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
112 PRVM_GCALL(end_increase_edicts)();
114 Mem_Free(oldedictsfields);
115 Mem_Free(oldedictprivate);
118 //============================================================================
121 int PRVM_ED_FindFieldOffset(const char *field)
124 d = PRVM_ED_FindField(field);
130 ddef_t* PRVM_ED_FindGlobal(const char *name);
131 int PRVM_ED_FindGlobalOffset(const char *global)
134 d = PRVM_ED_FindGlobal(global);
140 qboolean PRVM_ProgLoaded(int prognr)
142 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
145 return (prog_list[prognr].loaded ? TRUE : FALSE);
150 PRVM_SetProgFromString
153 // perhaps add a return value when the str doesnt exist
154 qboolean PRVM_SetProgFromString(const char *str)
157 for(; i < PRVM_MAXPROGS ; i++)
158 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
160 if(prog_list[i].loaded)
162 prog = &prog_list[i];
167 Con_Printf("%s not loaded !\n",PRVM_NAME);
172 Con_Printf("Invalid program name %s !\n", str);
181 void PRVM_SetProg(int prognr)
183 if(0 <= prognr && prognr < PRVM_MAXPROGS)
185 if(prog_list[prognr].loaded)
186 prog = &prog_list[prognr];
188 PRVM_ERROR("%i not loaded !", prognr);
191 PRVM_ERROR("Invalid program number %i", prognr);
198 Sets everything to NULL
201 void PRVM_ED_ClearEdict (prvm_edict_t *e)
203 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
204 e->priv.required->free = false;
206 // AK: Let the init_edict function determine if something needs to be initialized
207 PRVM_GCALL(init_edict)(e);
214 Either finds a free edict, or allocates a new one.
215 Try to avoid reusing an entity that was recently freed, because it
216 can cause the client to think the entity morphed into something else
217 instead of being removed and recreated, which can cause interpolated
218 angles and bad trails.
221 prvm_edict_t *PRVM_ED_Alloc (void)
226 // the client qc dont need maxclients
227 // thus it doesnt need to use svs.maxclients
228 // AK: changed i=svs.maxclients+1
229 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
230 // although the menu/client has no world
231 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
233 e = PRVM_EDICT_NUM(i);
234 // the first couple seconds of server time can involve a lot of
235 // freeing and allocating, so relax the replacement policy
236 if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
238 PRVM_ED_ClearEdict (e);
243 if (i == prog->limit_edicts)
244 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
247 if (prog->num_edicts >= prog->max_edicts)
248 PRVM_MEM_IncreaseEdicts();
250 e = PRVM_EDICT_NUM(i);
251 PRVM_ED_ClearEdict (e);
260 Marks the edict as free
261 FIXME: walk all entities and NULL out references to this entity
264 void PRVM_ED_Free (prvm_edict_t *ed)
266 // dont delete the null entity (world) or reserved edicts
267 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
270 PRVM_GCALL(free_edict)(ed);
272 ed->priv.required->free = true;
273 ed->priv.required->freetime = *prog->time;
276 //===========================================================================
283 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
288 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
290 def = &prog->globaldefs[i];
302 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
307 for (i=0 ; i<prog->progs->numfielddefs ; i++)
309 def = &prog->fielddefs[i];
321 ddef_t *PRVM_ED_FindField (const char *name)
326 for (i=0 ; i<prog->progs->numfielddefs ; i++)
328 def = &prog->fielddefs[i];
329 if (!strcmp(PRVM_GetString(def->s_name), name))
340 ddef_t *PRVM_ED_FindGlobal (const char *name)
345 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
347 def = &prog->globaldefs[i];
348 if (!strcmp(PRVM_GetString(def->s_name), name))
360 mfunction_t *PRVM_ED_FindFunction (const char *name)
365 for (i=0 ; i<prog->progs->numfunctions ; i++)
367 func = &prog->functions[i];
368 if (!strcmp(PRVM_GetString(func->s_name), name))
379 Returns a string describing *data in a type specific manner
382 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
384 static char line[MAX_INPUTLINE];
389 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
394 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
398 if (n < 0 || n >= prog->limit_edicts)
399 sprintf (line, "entity %i (invalid!)", n);
401 sprintf (line, "entity %i", n);
404 f = prog->functions + val->function;
405 sprintf (line, "%s()", PRVM_GetString(f->s_name));
408 def = PRVM_ED_FieldAtOfs ( val->_int );
409 sprintf (line, ".%s", PRVM_GetString(def->s_name));
412 sprintf (line, "void");
415 // LordHavoc: changed from %5.1f to %10.4f
416 sprintf (line, "%10.4f", val->_float);
419 // LordHavoc: changed from %5.1f to %10.4f
420 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
423 sprintf (line, "pointer");
426 sprintf (line, "bad type %i", (int) type);
437 Returns a string describing *data in a type specific manner
438 Easier to parse than PR_ValueString
441 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
443 static char line[MAX_INPUTLINE];
449 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
454 // Parse the string a bit to turn special characters
455 // (like newline, specifically) into escape codes,
456 // this fixes saving games from various mods
457 s = PRVM_GetString (val->string);
458 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
477 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
480 f = prog->functions + val->function;
481 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
484 def = PRVM_ED_FieldAtOfs ( val->_int );
485 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
488 dpsnprintf (line, sizeof (line), "void");
491 dpsnprintf (line, sizeof (line), "%f", val->_float);
494 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
497 dpsnprintf (line, sizeof (line), "bad type %i", type);
508 Returns a string with a description and the contents of a global,
509 padded to 20 field width
512 char *PRVM_GlobalString (int ofs)
518 static char line[128];
520 val = (void *)&prog->globals.generic[ofs];
521 def = PRVM_ED_GlobalAtOfs(ofs);
523 sprintf (line,"GLOBAL%i", ofs);
526 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
527 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
531 //for ( ; i<20 ; i++)
532 // strcat (line," ");
538 char *PRVM_GlobalStringNoContents (int ofs)
542 static char line[128];
544 def = PRVM_ED_GlobalAtOfs(ofs);
546 sprintf (line,"GLOBAL%i", ofs);
548 sprintf (line,"%s", PRVM_GetString(def->s_name));
551 //for ( ; i<20 ; i++)
552 // strcat (line," ");
566 // LordHavoc: optimized this to print out much more quickly (tempstring)
567 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
568 void PRVM_ED_Print(prvm_edict_t *ed)
576 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
578 if (ed->priv.required->free)
580 Con_Printf("%s: FREE\n",PRVM_NAME);
585 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
586 for (i=1 ; i<prog->progs->numfielddefs ; i++)
588 d = &prog->fielddefs[i];
589 name = PRVM_GetString(d->s_name);
590 if (name[strlen(name)-2] == '_')
591 continue; // skip _x, _y, _z vars
593 v = (int *)((char *)ed->fields.vp + d->ofs*4);
595 // if the value is still all 0, skip the field
596 type = d->type & ~DEF_SAVEGLOBAL;
598 for (j=0 ; j<prvm_type_size[type] ; j++)
601 if (j == prvm_type_size[type])
604 if (strlen(name) > sizeof(tempstring2)-4)
606 memcpy (tempstring2, name, sizeof(tempstring2)-4);
607 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
608 tempstring2[sizeof(tempstring2)-1] = 0;
611 strlcat(tempstring, name, sizeof(tempstring));
612 for (l = strlen(name);l < 14;l++)
613 strlcat(tempstring, " ", sizeof(tempstring));
614 strlcat(tempstring, " ", sizeof(tempstring));
616 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
617 if (strlen(name) > sizeof(tempstring2)-4)
619 memcpy (tempstring2, name, sizeof(tempstring2)-4);
620 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
621 tempstring2[sizeof(tempstring2)-1] = 0;
624 strlcat(tempstring, name, sizeof(tempstring));
625 strlcat(tempstring, "\n", sizeof(tempstring));
626 if (strlen(tempstring) >= sizeof(tempstring)/2)
628 Con_Print(tempstring);
633 Con_Print(tempstring);
643 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
653 if (ed->priv.required->free)
659 for (i=1 ; i<prog->progs->numfielddefs ; i++)
661 d = &prog->fielddefs[i];
662 name = PRVM_GetString(d->s_name);
663 if (name[strlen(name)-2] == '_')
664 continue; // skip _x, _y, _z vars
666 v = (int *)((char *)ed->fields.vp + d->ofs*4);
668 // if the value is still all 0, skip the field
669 type = d->type & ~DEF_SAVEGLOBAL;
670 for (j=0 ; j<prvm_type_size[type] ; j++)
673 if (j == prvm_type_size[type])
676 FS_Printf(f,"\"%s\" ",name);
677 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
683 void PRVM_ED_PrintNum (int ent)
685 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
690 PRVM_ED_PrintEdicts_f
692 For debugging, prints all the entities in the current server
695 void PRVM_ED_PrintEdicts_f (void)
701 Con_Print("prvm_edicts <program name>\n");
706 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
709 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
710 for (i=0 ; i<prog->num_edicts ; i++)
711 PRVM_ED_PrintNum (i);
720 For debugging, prints a single edict
723 void PRVM_ED_PrintEdict_f (void)
729 Con_Print("prvm_edict <program name> <edict number>\n");
734 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
737 i = atoi (Cmd_Argv(2));
738 if (i >= prog->num_edicts)
740 Con_Print("Bad edict number\n");
744 PRVM_ED_PrintNum (i);
756 // 2 possibilities : 1. just displaying the active edict count
757 // 2. making a function pointer [x]
758 void PRVM_ED_Count_f (void)
766 Con_Print("prvm_count <program name>\n");
771 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
774 if(prog->count_edicts)
775 prog->count_edicts();
779 for (i=0 ; i<prog->num_edicts ; i++)
781 ent = PRVM_EDICT_NUM(i);
782 if (ent->priv.required->free)
787 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
788 Con_Printf("active :%3i\n", active);
795 ==============================================================================
799 FIXME: need to tag constants, doesn't really work
800 ==============================================================================
808 void PRVM_ED_WriteGlobals (qfile_t *f)
816 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
818 def = &prog->globaldefs[i];
820 if ( !(def->type & DEF_SAVEGLOBAL) )
822 type &= ~DEF_SAVEGLOBAL;
824 if (type != ev_string && type != ev_float && type != ev_entity)
827 name = PRVM_GetString(def->s_name);
828 FS_Printf(f,"\"%s\" ", name);
829 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
839 void PRVM_ED_ParseGlobals (const char *data)
841 char keyname[MAX_INPUTLINE];
847 if (!COM_ParseTokenConsole(&data))
848 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
849 if (com_token[0] == '}')
852 strlcpy (keyname, com_token, sizeof(keyname));
855 if (!COM_ParseTokenConsole(&data))
856 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
858 if (com_token[0] == '}')
859 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
861 key = PRVM_ED_FindGlobal (keyname);
864 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
868 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
869 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
873 //============================================================================
880 Can parse either fields or globals
881 returns false if error
884 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
893 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
895 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
896 switch (key->type & ~DEF_SAVEGLOBAL)
899 l = (int)strlen(s) + 1;
900 val->string = PRVM_AllocString(l, &new_p);
901 for (i = 0;i < l;i++)
903 if (s[i] == '\\' && i < l-1)
908 else if (s[i] == 'r')
919 while (*s && *s <= ' ')
921 val->_float = atof(s);
925 for (i = 0;i < 3;i++)
927 while (*s && *s <= ' ')
931 val->vector[i] = atof(s);
940 while (*s && *s <= ' ')
943 if (i >= prog->limit_edicts)
944 Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, (unsigned int)MAX_EDICTS, PRVM_NAME);
945 while (i >= prog->max_edicts)
946 PRVM_MEM_IncreaseEdicts();
947 //SV_IncreaseEdicts();
948 // if SV_IncreaseEdicts was called the base pointer needs to be updated
950 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
951 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
955 def = PRVM_ED_FindField(s);
958 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
961 val->_int = def->ofs;
965 func = PRVM_ED_FindFunction(s);
968 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
971 val->function = func - prog->functions;
975 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
985 Console command to set a field of a specified edict
988 void PRVM_ED_EdictSet_f(void)
995 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1000 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1002 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1006 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1008 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1009 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1011 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1017 ====================
1020 Parses an edict out of the given string, returning the new position
1021 ed should be a properly initialized empty edict.
1022 Used for initial level load and for savegames.
1023 ====================
1025 extern cvar_t developer_entityparsing;
1026 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1036 // go through all the dictionary pairs
1040 if (!COM_ParseTokenConsole(&data))
1041 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1042 if (developer_entityparsing.integer)
1043 Con_Printf("Key: \"%s\"", com_token);
1044 if (com_token[0] == '}')
1047 // anglehack is to allow QuakeEd to write single scalar angles
1048 // and allow them to be turned into vectors. (FIXME...)
1049 if (!strcmp(com_token, "angle"))
1051 strlcpy (com_token, "angles", sizeof(com_token));
1057 // FIXME: change light to _light to get rid of this hack
1058 if (!strcmp(com_token, "light"))
1059 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1061 strlcpy (keyname, com_token, sizeof(keyname));
1063 // another hack to fix keynames with trailing spaces
1064 n = strlen(keyname);
1065 while (n && keyname[n-1] == ' ')
1072 if (!COM_ParseTokenConsole(&data))
1073 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1074 if (developer_entityparsing.integer)
1075 Con_Printf(" \"%s\"\n", com_token);
1077 if (com_token[0] == '}')
1078 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1082 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1086 // keynames with a leading underscore are used for utility comments,
1087 // and are immediately discarded by quake
1088 if (keyname[0] == '_')
1091 key = PRVM_ED_FindField (keyname);
1094 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1101 strlcpy (temp, com_token, sizeof(temp));
1102 sprintf (com_token, "0 %s 0", temp);
1105 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1106 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1110 ent->priv.required->free = true;
1118 PRVM_ED_LoadFromFile
1120 The entities are directly placed in the array, rather than allocated with
1121 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1122 number references out of order.
1124 Creates a server's entity / program execution context by
1125 parsing textual entity definitions out of an ent file.
1127 Used for both fresh maps and savegame loads. A fresh map would also need
1128 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1131 void PRVM_ED_LoadFromFile (const char *data)
1134 int parsed, inhibited, spawned, died;
1146 // parse the opening brace
1147 if (!COM_ParseTokenConsole(&data))
1149 if (com_token[0] != '{')
1150 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1152 // CHANGED: this is not conform to PR_LoadFromFile
1153 if(prog->loadintoworld)
1155 prog->loadintoworld = false;
1156 ent = PRVM_EDICT_NUM(0);
1159 ent = PRVM_ED_Alloc();
1162 if (ent != prog->edicts) // hack
1163 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1165 data = PRVM_ED_ParseEdict (data, ent);
1168 // remove the entity ?
1169 if(prog->load_edict && !prog->load_edict(ent))
1177 // immediately call spawn function, but only if there is a self global and a classname
1179 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1181 string_t handle = *(string_t*)&((unsigned char*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
1184 Con_Print("No classname for:\n");
1190 // look for the spawn function
1191 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1195 if (developer.integer) // don't confuse non-developers with errors
1197 Con_Print("No spawn function for:\n");
1205 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1206 PRVM_ExecuteProgram (func - prog->functions, "");
1210 if (ent->priv.required->free)
1214 Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
1219 typedef struct dpfield_s
1226 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1228 dpfield_t dpfields[] =
1239 void PRVM_ResetProg()
1241 PRVM_GCALL(reset_cmd)();
1242 Mem_FreePool(&prog->progs_mempool);
1243 memset(prog,0,sizeof(prvm_prog_t));
1251 void PRVM_LoadLNO( const char *progname ) {
1252 fs_offset_t filesize;
1254 unsigned int *header;
1257 FS_StripExtension( progname, filename, sizeof( filename ) );
1258 strlcat( filename, ".lno", sizeof( filename ) );
1260 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1266 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1267 <Spike> SafeWrite (h, &version, sizeof(int));
1268 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1269 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1270 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1271 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1272 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1274 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1279 header = (unsigned int *) lno;
1280 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1281 LittleLong( header[ 1 ] ) == 1 &&
1282 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1283 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1284 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1285 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1287 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1288 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1298 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field)
1302 ddef_t *infielddefs;
1303 dfunction_t *dfunctions;
1304 fs_offset_t filesize;
1306 if( prog->loaded ) {
1307 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1310 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1311 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1312 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1314 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1316 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1318 // byte swap the header
1319 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1320 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1322 if (prog->progs->version != PROG_VERSION)
1323 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1324 if (prog->progs->crc != prog->headercrc)
1325 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1327 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1328 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1330 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1331 prog->stringssize = 0;
1332 for (i = 0;i < prog->progs->numstrings;i++)
1334 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1335 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1336 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1338 prog->numknownstrings = 0;
1339 prog->maxknownstrings = 0;
1340 prog->knownstrings = NULL;
1341 prog->knownstrings_freeable = NULL;
1343 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1345 // we need to expand the fielddefs list to include all the engine fields,
1346 // so allocate a new place for it
1347 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1349 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1351 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1353 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1355 // moved edict_size calculation down below field adding code
1357 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1358 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1360 // byte swap the lumps
1361 for (i=0 ; i<prog->progs->numstatements ; i++)
1363 prog->statements[i].op = LittleShort(prog->statements[i].op);
1364 prog->statements[i].a = LittleShort(prog->statements[i].a);
1365 prog->statements[i].b = LittleShort(prog->statements[i].b);
1366 prog->statements[i].c = LittleShort(prog->statements[i].c);
1369 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1370 for (i = 0;i < prog->progs->numfunctions;i++)
1372 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1373 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1374 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1375 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1376 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1377 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1378 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1381 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1383 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1384 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1385 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1388 // copy the progs fields to the new fields list
1389 for (i = 0;i < prog->progs->numfielddefs;i++)
1391 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1392 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1393 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1394 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1395 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1398 // append the required fields
1399 for (i = 0;i < (int) numrequiredfields;i++)
1401 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1402 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1403 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1404 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1405 prog->progs->entityfields += 3;
1407 prog->progs->entityfields++;
1408 prog->progs->numfielddefs++;
1411 // check required functions
1412 for(i=0 ; i < numrequiredfunc ; i++)
1413 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1414 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1416 for (i=0 ; i<prog->progs->numglobals ; i++)
1417 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1419 // moved edict_size calculation down here, below field adding code
1420 // LordHavoc: this no longer includes the prvm_edict_t header
1421 prog->edict_size = prog->progs->entityfields * 4;
1422 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1424 // LordHavoc: bounds check anything static
1425 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1431 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1432 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1435 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1436 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1438 // global global global
1473 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1474 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1476 // global none global
1482 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1483 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1499 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1500 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1514 if ((unsigned short) st->a >= prog->progs->numglobals)
1515 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1518 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1523 PRVM_LoadLNO(filename);
1527 prog->loaded = TRUE;
1529 // set flags & ddef_ts in prog
1533 prog->self = PRVM_ED_FindGlobal("self");
1535 if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
1536 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1538 if(PRVM_ED_FindField ("chain"))
1539 prog->flag |= PRVM_FE_CHAIN;
1541 if(PRVM_ED_FindField ("classname"))
1542 prog->flag |= PRVM_FE_CLASSNAME;
1544 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1545 && prog->flag && prog->self)
1546 prog->flag |= PRVM_OP_STATE;
1548 PRVM_GCALL(init_cmd)();
1555 void PRVM_Fields_f (void)
1557 int i, j, ednum, used, usedamount;
1559 char tempstring[MAX_INPUTLINE], tempstring2[260];
1569 Con_Print("no progs loaded\n");
1576 Con_Print("prvm_fields <program name>\n");
1581 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1584 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1585 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1587 ed = PRVM_EDICT_NUM(ednum);
1588 if (ed->priv.required->free)
1590 for (i = 1;i < prog->progs->numfielddefs;i++)
1592 d = &prog->fielddefs[i];
1593 name = PRVM_GetString(d->s_name);
1594 if (name[strlen(name)-2] == '_')
1595 continue; // skip _x, _y, _z vars
1596 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1597 // if the value is still all 0, skip the field
1598 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1611 for (i = 0;i < prog->progs->numfielddefs;i++)
1613 d = &prog->fielddefs[i];
1614 name = PRVM_GetString(d->s_name);
1615 if (name[strlen(name)-2] == '_')
1616 continue; // skip _x, _y, _z vars
1617 switch(d->type & ~DEF_SAVEGLOBAL)
1620 strlcat(tempstring, "string ", sizeof(tempstring));
1623 strlcat(tempstring, "entity ", sizeof(tempstring));
1626 strlcat(tempstring, "function ", sizeof(tempstring));
1629 strlcat(tempstring, "field ", sizeof(tempstring));
1632 strlcat(tempstring, "void ", sizeof(tempstring));
1635 strlcat(tempstring, "float ", sizeof(tempstring));
1638 strlcat(tempstring, "vector ", sizeof(tempstring));
1641 strlcat(tempstring, "pointer ", sizeof(tempstring));
1644 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1645 strlcat(tempstring, tempstring2, sizeof(tempstring));
1648 if (strlen(name) > sizeof(tempstring2)-4)
1650 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1651 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1652 tempstring2[sizeof(tempstring2)-1] = 0;
1655 strlcat(tempstring, name, sizeof(tempstring));
1656 for (j = (int)strlen(name);j < 25;j++)
1657 strlcat(tempstring, " ", sizeof(tempstring));
1658 sprintf(tempstring2, "%5d", counts[i]);
1659 strlcat(tempstring, tempstring2, sizeof(tempstring));
1660 strlcat(tempstring, "\n", sizeof(tempstring));
1661 if (strlen(tempstring) >= sizeof(tempstring)/2)
1663 Con_Print(tempstring);
1669 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1673 Con_Printf("%s: %i entity fields (%i in use), totalling %i bytes per edict (%i in use), %i edicts allocated, %i bytes total spent on edict fields (%i needed)\n", PRVM_NAME, prog->progs->entityfields, used, prog->progs->entityfields * 4, usedamount * 4, prog->max_edicts, prog->progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
1678 void PRVM_Globals_f (void)
1684 Con_Print("no progs loaded\n");
1687 if(Cmd_Argc () != 2)
1689 Con_Print("prvm_globals <program name>\n");
1694 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1697 Con_Printf("%s :", PRVM_NAME);
1699 for (i = 0;i < prog->progs->numglobaldefs;i++)
1700 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1701 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1711 void PRVM_Global_f(void)
1714 if( Cmd_Argc() != 3 ) {
1715 Con_Printf( "prvm_global <program name> <global name>\n" );
1720 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1723 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1725 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1727 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1736 void PRVM_GlobalSet_f(void)
1739 if( Cmd_Argc() != 4 ) {
1740 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1745 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1748 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1750 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1752 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1761 void PRVM_Init (void)
1763 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1764 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1765 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1766 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1767 Cmd_AddCommand ("prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
1768 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1769 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1770 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1771 Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
1772 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1773 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1774 Cvar_RegisterVariable (&prvm_boundscheck);
1775 Cvar_RegisterVariable (&prvm_traceqc);
1776 Cvar_RegisterVariable (&prvm_statementprofiling);
1777 Cvar_RegisterVariable (&prvm_tempstringmemory);
1787 void PRVM_InitProg(int prognr)
1789 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1790 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1792 prog = &prog_list[prognr];
1797 memset(prog, 0, sizeof(prvm_prog_t));
1799 prog->time = &prog->_time;
1800 prog->error_cmd = Host_Error;
1803 int PRVM_GetProgNr()
1805 return prog - prog_list;
1808 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1810 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1813 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1815 _Mem_Free(buffer, filename, fileline);
1818 void _PRVM_FreeAll(const char *filename, int fileline)
1821 prog->fielddefs = NULL;
1822 prog->functions = NULL;
1823 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1826 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1827 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1829 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1834 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1836 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1840 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1843 n = e - prog->edicts;
1844 if ((unsigned int)n >= prog->limit_edicts)
1845 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1849 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1851 // return e - prog->edicts;
1854 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1855 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1856 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1859 n = e - prog->edicts;
1860 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1861 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
1862 return n;// EXPERIMENTAL
1863 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
1865 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1867 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1868 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
1869 return prog->edicts + n; // EXPERIMENTAL
1870 //return prog->edicts + ((n) / (progs->entityfields * 4));
1875 sizebuf_t vm_tempstringsbuf;
1877 const char *PRVM_GetString(int num)
1881 if (num < prog->stringssize)
1882 return prog->strings + num;
1885 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
1887 num -= prog->stringssize;
1888 if (num < vm_tempstringsbuf.cursize)
1889 return (char *)vm_tempstringsbuf.data + num;
1892 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
1899 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
1909 // special range reserved for tempstrings
1911 if (num < vm_tempstringsbuf.cursize)
1912 return (char *)vm_tempstringsbuf.data + num;
1915 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
1921 if (num < prog->numknownstrings)
1923 if (!prog->knownstrings[num])
1924 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
1925 return prog->knownstrings[num];
1929 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
1935 int PRVM_SetEngineString(const char *s)
1940 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1941 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
1942 // if it's in the tempstrings area, use a reserved range
1943 // (otherwise we'd get millions of useless string offsets cluttering the database)
1944 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
1946 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
1948 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
1950 // see if it's a known string address
1951 for (i = 0;i < prog->numknownstrings;i++)
1952 if (prog->knownstrings[i] == s)
1954 // new unknown engine string
1955 if (developer.integer >= 100)
1956 Con_Printf("new engine string %p\n", s);
1957 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
1958 if (!prog->knownstrings[i])
1960 if (i >= prog->numknownstrings)
1962 if (i >= prog->maxknownstrings)
1964 const char **oldstrings = prog->knownstrings;
1965 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
1966 prog->maxknownstrings += 128;
1967 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1968 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
1969 if (prog->numknownstrings)
1971 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1972 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
1975 prog->numknownstrings++;
1977 prog->firstfreeknownstring = i + 1;
1978 prog->knownstrings[i] = s;
1982 // temp string handling
1984 // all tempstrings go into this buffer consecutively, and it is reset
1985 // whenever PRVM_ExecuteProgram returns to the engine
1986 // (technically each PRVM_ExecuteProgram call saves the cursize value and
1987 // restores it on return, so multiple recursive calls can share the same
1989 // the buffer size is controlled by the prvm_tempstringmemory cvar, causing it
1990 // to be reallocated between invocations if the cvar has changed
1992 int PRVM_SetTempString(const char *s)
1998 size = (int)strlen(s) + 1;
1999 if (vm_tempstringsbuf.cursize + size >= vm_tempstringsbuf.maxsize)
2000 PRVM_ERROR("PRVM_SetTempString: tempstrings buffer full! (increase prvm_tempstringmemory cvar or reduce use of tempstrings in quakec code)\n");
2001 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2003 vm_tempstringsbuf.cursize += size;
2004 return PRVM_SetEngineString(t);
2007 int PRVM_AllocString(size_t bufferlength, char **pointer)
2012 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2013 if (!prog->knownstrings[i])
2015 if (i >= prog->numknownstrings)
2017 if (i >= prog->maxknownstrings)
2019 const char **oldstrings = prog->knownstrings;
2020 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2021 prog->maxknownstrings += 128;
2022 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2023 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2024 if (prog->numknownstrings)
2026 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2027 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2030 prog->numknownstrings++;
2032 prog->firstfreeknownstring = i + 1;
2033 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2034 prog->knownstrings_freeable[i] = true;
2036 *pointer = (char *)(prog->knownstrings[i]);
2040 void PRVM_FreeString(int num)
2043 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2044 else if (num >= 0 && num < prog->stringssize)
2045 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2046 else if (num < 0 && num >= -prog->numknownstrings)
2049 if (!prog->knownstrings[num])
2050 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2051 if (!prog->knownstrings[num])
2052 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2053 PRVM_Free((char *)prog->knownstrings[num]);
2054 prog->knownstrings[num] = NULL;
2055 prog->knownstrings_freeable[num] = false;
2056 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2059 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);