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)"};
41 //============================================================================
49 void PRVM_MEM_Alloc(void)
53 // reserve space for the null entity aka world
54 // check bound of max_edicts
55 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
56 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
58 // edictprivate_size has to be min as big prvm_edict_private_t
59 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
62 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
64 // alloc edict private space
65 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
68 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
71 for(i = 0; i < prog->max_edicts; i++)
73 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
74 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
80 PRVM_MEM_IncreaseEdicts
83 void PRVM_MEM_IncreaseEdicts(void)
86 int oldmaxedicts = prog->max_edicts;
87 void *oldedictsfields = prog->edictsfields;
88 void *oldedictprivate = prog->edictprivate;
90 if(prog->max_edicts >= prog->limit_edicts)
93 PRVM_GCALL(begin_increase_edicts)();
96 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
98 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
99 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
101 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
102 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
104 //set e and v pointers
105 for(i = 0; i < prog->max_edicts; i++)
107 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
108 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
111 PRVM_GCALL(end_increase_edicts)();
113 Mem_Free(oldedictsfields);
114 Mem_Free(oldedictprivate);
117 //============================================================================
120 int PRVM_ED_FindFieldOffset(const char *field)
123 d = PRVM_ED_FindField(field);
129 ddef_t* PRVM_ED_FindGlobal(const char *name);
130 int PRVM_ED_FindGlobalOffset(const char *global)
133 d = PRVM_ED_FindGlobal(global);
139 qboolean PRVM_ProgLoaded(int prognr)
141 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
144 return (prog_list[prognr].loaded ? TRUE : FALSE);
149 PRVM_SetProgFromString
152 // perhaps add a return value when the str doesnt exist
153 qboolean PRVM_SetProgFromString(const char *str)
156 for(; i < PRVM_MAXPROGS ; i++)
157 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
159 if(prog_list[i].loaded)
161 prog = &prog_list[i];
166 Con_Printf("%s not loaded !\n",PRVM_NAME);
171 Con_Printf("Invalid program name %s !\n", str);
180 void PRVM_SetProg(int prognr)
182 if(0 <= prognr && prognr < PRVM_MAXPROGS)
184 if(prog_list[prognr].loaded)
185 prog = &prog_list[prognr];
187 PRVM_ERROR("%i not loaded !", prognr);
190 PRVM_ERROR("Invalid program number %i", prognr);
197 Sets everything to NULL
200 void PRVM_ED_ClearEdict (prvm_edict_t *e)
202 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
203 e->priv.required->free = false;
205 // AK: Let the init_edict function determine if something needs to be initialized
206 PRVM_GCALL(init_edict)(e);
213 Either finds a free edict, or allocates a new one.
214 Try to avoid reusing an entity that was recently freed, because it
215 can cause the client to think the entity morphed into something else
216 instead of being removed and recreated, which can cause interpolated
217 angles and bad trails.
220 prvm_edict_t *PRVM_ED_Alloc (void)
225 // the client qc dont need maxclients
226 // thus it doesnt need to use svs.maxclients
227 // AK: changed i=svs.maxclients+1
228 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
229 // although the menu/client has no world
230 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
232 e = PRVM_EDICT_NUM(i);
233 // the first couple seconds of server time can involve a lot of
234 // freeing and allocating, so relax the replacement policy
235 if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
237 PRVM_ED_ClearEdict (e);
242 if (i == prog->limit_edicts)
243 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
246 if (prog->num_edicts >= prog->max_edicts)
247 PRVM_MEM_IncreaseEdicts();
249 e = PRVM_EDICT_NUM(i);
250 PRVM_ED_ClearEdict (e);
259 Marks the edict as free
260 FIXME: walk all entities and NULL out references to this entity
263 void PRVM_ED_Free (prvm_edict_t *ed)
265 // dont delete the null entity (world) or reserved edicts
266 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
269 PRVM_GCALL(free_edict)(ed);
271 ed->priv.required->free = true;
272 ed->priv.required->freetime = *prog->time;
275 //===========================================================================
282 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
287 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
289 def = &prog->globaldefs[i];
301 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
306 for (i=0 ; i<prog->progs->numfielddefs ; i++)
308 def = &prog->fielddefs[i];
320 ddef_t *PRVM_ED_FindField (const char *name)
325 for (i=0 ; i<prog->progs->numfielddefs ; i++)
327 def = &prog->fielddefs[i];
328 if (!strcmp(PRVM_GetString(def->s_name), name))
339 ddef_t *PRVM_ED_FindGlobal (const char *name)
344 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
346 def = &prog->globaldefs[i];
347 if (!strcmp(PRVM_GetString(def->s_name), name))
359 mfunction_t *PRVM_ED_FindFunction (const char *name)
364 for (i=0 ; i<prog->progs->numfunctions ; i++)
366 func = &prog->functions[i];
367 if (!strcmp(PRVM_GetString(func->s_name), name))
378 Returns a string describing *data in a type specific manner
381 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
383 static char line[MAX_INPUTLINE];
388 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
393 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
397 if (n < 0 || n >= prog->limit_edicts)
398 sprintf (line, "entity %i (invalid!)", n);
400 sprintf (line, "entity %i", n);
403 f = prog->functions + val->function;
404 sprintf (line, "%s()", PRVM_GetString(f->s_name));
407 def = PRVM_ED_FieldAtOfs ( val->_int );
408 sprintf (line, ".%s", PRVM_GetString(def->s_name));
411 sprintf (line, "void");
414 // LordHavoc: changed from %5.1f to %10.4f
415 sprintf (line, "%10.4f", val->_float);
418 // LordHavoc: changed from %5.1f to %10.4f
419 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
422 sprintf (line, "pointer");
425 sprintf (line, "bad type %i", (int) type);
436 Returns a string describing *data in a type specific manner
437 Easier to parse than PR_ValueString
440 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
442 static char line[MAX_INPUTLINE];
448 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
453 // Parse the string a bit to turn special characters
454 // (like newline, specifically) into escape codes,
455 // this fixes saving games from various mods
456 s = PRVM_GetString (val->string);
457 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
476 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
479 f = prog->functions + val->function;
480 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
483 def = PRVM_ED_FieldAtOfs ( val->_int );
484 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
487 dpsnprintf (line, sizeof (line), "void");
490 dpsnprintf (line, sizeof (line), "%f", val->_float);
493 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
496 dpsnprintf (line, sizeof (line), "bad type %i", type);
507 Returns a string with a description and the contents of a global,
508 padded to 20 field width
511 char *PRVM_GlobalString (int ofs)
517 static char line[128];
519 val = (void *)&prog->globals.generic[ofs];
520 def = PRVM_ED_GlobalAtOfs(ofs);
522 sprintf (line,"GLOBAL%i", ofs);
525 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
526 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
530 //for ( ; i<20 ; i++)
531 // strcat (line," ");
537 char *PRVM_GlobalStringNoContents (int ofs)
541 static char line[128];
543 def = PRVM_ED_GlobalAtOfs(ofs);
545 sprintf (line,"GLOBAL%i", ofs);
547 sprintf (line,"%s", PRVM_GetString(def->s_name));
550 //for ( ; i<20 ; i++)
551 // strcat (line," ");
565 // LordHavoc: optimized this to print out much more quickly (tempstring)
566 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
567 void PRVM_ED_Print(prvm_edict_t *ed)
575 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
577 if (ed->priv.required->free)
579 Con_Printf("%s: FREE\n",PRVM_NAME);
584 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
585 for (i=1 ; i<prog->progs->numfielddefs ; i++)
587 d = &prog->fielddefs[i];
588 name = PRVM_GetString(d->s_name);
589 if (name[strlen(name)-2] == '_')
590 continue; // skip _x, _y, _z vars
592 v = (int *)((char *)ed->fields.vp + d->ofs*4);
594 // if the value is still all 0, skip the field
595 type = d->type & ~DEF_SAVEGLOBAL;
597 for (j=0 ; j<prvm_type_size[type] ; j++)
600 if (j == prvm_type_size[type])
603 if (strlen(name) > sizeof(tempstring2)-4)
605 memcpy (tempstring2, name, sizeof(tempstring2)-4);
606 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
607 tempstring2[sizeof(tempstring2)-1] = 0;
610 strlcat(tempstring, name, sizeof(tempstring));
611 for (l = strlen(name);l < 14;l++)
612 strlcat(tempstring, " ", sizeof(tempstring));
613 strlcat(tempstring, " ", sizeof(tempstring));
615 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
616 if (strlen(name) > sizeof(tempstring2)-4)
618 memcpy (tempstring2, name, sizeof(tempstring2)-4);
619 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
620 tempstring2[sizeof(tempstring2)-1] = 0;
623 strlcat(tempstring, name, sizeof(tempstring));
624 strlcat(tempstring, "\n", sizeof(tempstring));
625 if (strlen(tempstring) >= sizeof(tempstring)/2)
627 Con_Print(tempstring);
632 Con_Print(tempstring);
642 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
652 if (ed->priv.required->free)
658 for (i=1 ; i<prog->progs->numfielddefs ; i++)
660 d = &prog->fielddefs[i];
661 name = PRVM_GetString(d->s_name);
662 if (name[strlen(name)-2] == '_')
663 continue; // skip _x, _y, _z vars
665 v = (int *)((char *)ed->fields.vp + d->ofs*4);
667 // if the value is still all 0, skip the field
668 type = d->type & ~DEF_SAVEGLOBAL;
669 for (j=0 ; j<prvm_type_size[type] ; j++)
672 if (j == prvm_type_size[type])
675 FS_Printf(f,"\"%s\" ",name);
676 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
682 void PRVM_ED_PrintNum (int ent)
684 PRVM_ED_Print(PRVM_EDICT_NUM(ent));
689 PRVM_ED_PrintEdicts_f
691 For debugging, prints all the entities in the current server
694 void PRVM_ED_PrintEdicts_f (void)
700 Con_Print("prvm_edicts <program name>\n");
705 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
708 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
709 for (i=0 ; i<prog->num_edicts ; i++)
710 PRVM_ED_PrintNum (i);
719 For debugging, prints a single edict
722 void PRVM_ED_PrintEdict_f (void)
728 Con_Print("prvm_edict <program name> <edict number>\n");
733 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
736 i = atoi (Cmd_Argv(2));
737 if (i >= prog->num_edicts)
739 Con_Print("Bad edict number\n");
743 PRVM_ED_PrintNum (i);
755 // 2 possibilities : 1. just displaying the active edict count
756 // 2. making a function pointer [x]
757 void PRVM_ED_Count_f (void)
765 Con_Print("prvm_count <program name>\n");
770 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
773 if(prog->count_edicts)
774 prog->count_edicts();
778 for (i=0 ; i<prog->num_edicts ; i++)
780 ent = PRVM_EDICT_NUM(i);
781 if (ent->priv.required->free)
786 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
787 Con_Printf("active :%3i\n", active);
794 ==============================================================================
798 FIXME: need to tag constants, doesn't really work
799 ==============================================================================
807 void PRVM_ED_WriteGlobals (qfile_t *f)
815 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
817 def = &prog->globaldefs[i];
819 if ( !(def->type & DEF_SAVEGLOBAL) )
821 type &= ~DEF_SAVEGLOBAL;
823 if (type != ev_string && type != ev_float && type != ev_entity)
826 name = PRVM_GetString(def->s_name);
827 FS_Printf(f,"\"%s\" ", name);
828 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
838 void PRVM_ED_ParseGlobals (const char *data)
840 char keyname[MAX_INPUTLINE];
846 if (!COM_ParseTokenConsole(&data))
847 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
848 if (com_token[0] == '}')
851 strlcpy (keyname, com_token, sizeof(keyname));
854 if (!COM_ParseTokenConsole(&data))
855 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
857 if (com_token[0] == '}')
858 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
860 key = PRVM_ED_FindGlobal (keyname);
863 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
867 if (!PRVM_ED_ParseEpair(NULL, key, com_token))
868 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
872 //============================================================================
879 Can parse either fields or globals
880 returns false if error
883 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
892 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
894 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
895 switch (key->type & ~DEF_SAVEGLOBAL)
898 l = (int)strlen(s) + 1;
899 val->string = PRVM_AllocString(l, &new_p);
900 for (i = 0;i < l;i++)
902 if (s[i] == '\\' && i < l-1)
907 else if (s[i] == 'r')
918 while (*s && *s <= ' ')
920 val->_float = atof(s);
924 for (i = 0;i < 3;i++)
926 while (*s && *s <= ' ')
930 val->vector[i] = atof(s);
939 while (*s && *s <= ' ')
942 if (i >= prog->limit_edicts)
943 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);
944 while (i >= prog->max_edicts)
945 PRVM_MEM_IncreaseEdicts();
946 //SV_IncreaseEdicts();
947 // if SV_IncreaseEdicts was called the base pointer needs to be updated
949 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
950 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
954 def = PRVM_ED_FindField(s);
957 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
960 val->_int = def->ofs;
964 func = PRVM_ED_FindFunction(s);
967 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
970 val->function = func - prog->functions;
974 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
984 Console command to set a field of a specified edict
987 void PRVM_ED_EdictSet_f(void)
994 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
999 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1001 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1005 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1007 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1008 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1010 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
1016 ====================
1019 Parses an edict out of the given string, returning the new position
1020 ed should be a properly initialized empty edict.
1021 Used for initial level load and for savegames.
1022 ====================
1024 extern cvar_t developer_entityparsing;
1025 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1035 // go through all the dictionary pairs
1039 if (!COM_ParseTokenConsole(&data))
1040 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1041 if (developer_entityparsing.integer)
1042 Con_Printf("Key: \"%s\"", com_token);
1043 if (com_token[0] == '}')
1046 // anglehack is to allow QuakeEd to write single scalar angles
1047 // and allow them to be turned into vectors. (FIXME...)
1048 if (!strcmp(com_token, "angle"))
1050 strlcpy (com_token, "angles", sizeof(com_token));
1056 // FIXME: change light to _light to get rid of this hack
1057 if (!strcmp(com_token, "light"))
1058 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1060 strlcpy (keyname, com_token, sizeof(keyname));
1062 // another hack to fix keynames with trailing spaces
1063 n = strlen(keyname);
1064 while (n && keyname[n-1] == ' ')
1071 if (!COM_ParseTokenConsole(&data))
1072 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1073 if (developer_entityparsing.integer)
1074 Con_Printf(" \"%s\"\n", com_token);
1076 if (com_token[0] == '}')
1077 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1081 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1085 // keynames with a leading underscore are used for utility comments,
1086 // and are immediately discarded by quake
1087 if (keyname[0] == '_')
1090 key = PRVM_ED_FindField (keyname);
1093 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1100 strlcpy (temp, com_token, sizeof(temp));
1101 sprintf (com_token, "0 %s 0", temp);
1104 if (!PRVM_ED_ParseEpair(ent, key, com_token))
1105 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1109 ent->priv.required->free = true;
1117 PRVM_ED_LoadFromFile
1119 The entities are directly placed in the array, rather than allocated with
1120 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1121 number references out of order.
1123 Creates a server's entity / program execution context by
1124 parsing textual entity definitions out of an ent file.
1126 Used for both fresh maps and savegame loads. A fresh map would also need
1127 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1130 void PRVM_ED_LoadFromFile (const char *data)
1133 int parsed, inhibited, spawned, died;
1145 // parse the opening brace
1146 if (!COM_ParseTokenConsole(&data))
1148 if (com_token[0] != '{')
1149 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1151 // CHANGED: this is not conform to PR_LoadFromFile
1152 if(prog->loadintoworld)
1154 prog->loadintoworld = false;
1155 ent = PRVM_EDICT_NUM(0);
1158 ent = PRVM_ED_Alloc();
1161 if (ent != prog->edicts) // hack
1162 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1164 data = PRVM_ED_ParseEdict (data, ent);
1167 // remove the entity ?
1168 if(prog->load_edict && !prog->load_edict(ent))
1176 // immediately call spawn function, but only if there is a self global and a classname
1178 if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
1180 string_t handle = *(string_t*)&((unsigned char*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
1183 Con_Print("No classname for:\n");
1189 // look for the spawn function
1190 func = PRVM_ED_FindFunction (PRVM_GetString(handle));
1194 if (developer.integer) // don't confuse non-developers with errors
1196 Con_Print("No spawn function for:\n");
1204 PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
1205 PRVM_ExecuteProgram (func - prog->functions, "");
1209 if (ent->priv.required->free)
1213 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);
1218 typedef struct dpfield_s
1225 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1227 dpfield_t dpfields[] =
1238 void PRVM_ResetProg()
1240 PRVM_GCALL(reset_cmd)();
1241 Mem_FreePool(&prog->progs_mempool);
1242 memset(prog,0,sizeof(prvm_prog_t));
1250 void PRVM_LoadLNO( const char *progname ) {
1251 fs_offset_t filesize;
1253 unsigned int *header;
1256 FS_StripExtension( progname, filename, sizeof( filename ) );
1257 strlcat( filename, ".lno", sizeof( filename ) );
1259 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1265 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1266 <Spike> SafeWrite (h, &version, sizeof(int));
1267 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1268 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1269 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1270 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1271 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1273 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1278 header = (unsigned int *) lno;
1279 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1280 LittleLong( header[ 1 ] ) == 1 &&
1281 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1282 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1283 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1284 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1286 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1287 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1297 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field)
1301 ddef_t *infielddefs;
1302 dfunction_t *dfunctions;
1303 fs_offset_t filesize;
1305 if( prog->loaded ) {
1306 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1309 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1310 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1311 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1313 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1315 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1317 // byte swap the header
1318 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1319 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1321 if (prog->progs->version != PROG_VERSION)
1322 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1323 if (prog->progs->crc != prog->headercrc)
1324 PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename);
1326 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1327 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1329 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1330 prog->stringssize = 0;
1331 for (i = 0;i < prog->progs->numstrings;i++)
1333 if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize)
1334 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1335 prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1;
1337 prog->numknownstrings = 0;
1338 prog->maxknownstrings = 0;
1339 prog->knownstrings = NULL;
1340 prog->knownstrings_freeable = NULL;
1342 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1344 // we need to expand the fielddefs list to include all the engine fields,
1345 // so allocate a new place for it
1346 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1348 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1350 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1352 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1354 // moved edict_size calculation down below field adding code
1356 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1357 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1359 // byte swap the lumps
1360 for (i=0 ; i<prog->progs->numstatements ; i++)
1362 prog->statements[i].op = LittleShort(prog->statements[i].op);
1363 prog->statements[i].a = LittleShort(prog->statements[i].a);
1364 prog->statements[i].b = LittleShort(prog->statements[i].b);
1365 prog->statements[i].c = LittleShort(prog->statements[i].c);
1368 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1369 for (i = 0;i < prog->progs->numfunctions;i++)
1371 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1372 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1373 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1374 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1375 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1376 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1377 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1380 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1382 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1383 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1384 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1387 // copy the progs fields to the new fields list
1388 for (i = 0;i < prog->progs->numfielddefs;i++)
1390 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1391 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1392 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1393 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1394 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1397 // append the required fields
1398 for (i = 0;i < (int) numrequiredfields;i++)
1400 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1401 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1402 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1403 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1404 prog->progs->entityfields += 3;
1406 prog->progs->entityfields++;
1407 prog->progs->numfielddefs++;
1410 // check required functions
1411 for(i=0 ; i < numrequiredfunc ; i++)
1412 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1413 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1415 for (i=0 ; i<prog->progs->numglobals ; i++)
1416 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1418 // moved edict_size calculation down here, below field adding code
1419 // LordHavoc: this no longer includes the prvm_edict_t header
1420 prog->edict_size = prog->progs->entityfields * 4;
1421 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1423 // LordHavoc: bounds check anything static
1424 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1430 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1431 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1434 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1435 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1437 // global global global
1472 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1473 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1475 // global none global
1481 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1482 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1498 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1499 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1513 if ((unsigned short) st->a >= prog->progs->numglobals)
1514 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1517 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1522 PRVM_LoadLNO(filename);
1526 prog->loaded = TRUE;
1528 // set flags & ddef_ts in prog
1532 prog->self = PRVM_ED_FindGlobal("self");
1534 if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
1535 prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
1537 if(PRVM_ED_FindField ("chain"))
1538 prog->flag |= PRVM_FE_CHAIN;
1540 if(PRVM_ED_FindField ("classname"))
1541 prog->flag |= PRVM_FE_CLASSNAME;
1543 if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
1544 && prog->flag && prog->self)
1545 prog->flag |= PRVM_OP_STATE;
1547 PRVM_GCALL(init_cmd)();
1554 void PRVM_Fields_f (void)
1556 int i, j, ednum, used, usedamount;
1558 char tempstring[MAX_INPUTLINE], tempstring2[260];
1568 Con_Print("no progs loaded\n");
1575 Con_Print("prvm_fields <program name>\n");
1580 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1583 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1584 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1586 ed = PRVM_EDICT_NUM(ednum);
1587 if (ed->priv.required->free)
1589 for (i = 1;i < prog->progs->numfielddefs;i++)
1591 d = &prog->fielddefs[i];
1592 name = PRVM_GetString(d->s_name);
1593 if (name[strlen(name)-2] == '_')
1594 continue; // skip _x, _y, _z vars
1595 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1596 // if the value is still all 0, skip the field
1597 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1610 for (i = 0;i < prog->progs->numfielddefs;i++)
1612 d = &prog->fielddefs[i];
1613 name = PRVM_GetString(d->s_name);
1614 if (name[strlen(name)-2] == '_')
1615 continue; // skip _x, _y, _z vars
1616 switch(d->type & ~DEF_SAVEGLOBAL)
1619 strlcat(tempstring, "string ", sizeof(tempstring));
1622 strlcat(tempstring, "entity ", sizeof(tempstring));
1625 strlcat(tempstring, "function ", sizeof(tempstring));
1628 strlcat(tempstring, "field ", sizeof(tempstring));
1631 strlcat(tempstring, "void ", sizeof(tempstring));
1634 strlcat(tempstring, "float ", sizeof(tempstring));
1637 strlcat(tempstring, "vector ", sizeof(tempstring));
1640 strlcat(tempstring, "pointer ", sizeof(tempstring));
1643 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1644 strlcat(tempstring, tempstring2, sizeof(tempstring));
1647 if (strlen(name) > sizeof(tempstring2)-4)
1649 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1650 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1651 tempstring2[sizeof(tempstring2)-1] = 0;
1654 strlcat(tempstring, name, sizeof(tempstring));
1655 for (j = (int)strlen(name);j < 25;j++)
1656 strlcat(tempstring, " ", sizeof(tempstring));
1657 sprintf(tempstring2, "%5d", counts[i]);
1658 strlcat(tempstring, tempstring2, sizeof(tempstring));
1659 strlcat(tempstring, "\n", sizeof(tempstring));
1660 if (strlen(tempstring) >= sizeof(tempstring)/2)
1662 Con_Print(tempstring);
1668 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1672 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);
1677 void PRVM_Globals_f (void)
1683 Con_Print("no progs loaded\n");
1686 if(Cmd_Argc () != 2)
1688 Con_Print("prvm_globals <program name>\n");
1693 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1696 Con_Printf("%s :", PRVM_NAME);
1698 for (i = 0;i < prog->progs->numglobaldefs;i++)
1699 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1700 Con_Printf("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4);
1710 void PRVM_Global_f(void)
1713 if( Cmd_Argc() != 3 ) {
1714 Con_Printf( "prvm_global <program name> <global name>\n" );
1719 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1722 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1724 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1726 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
1735 void PRVM_GlobalSet_f(void)
1738 if( Cmd_Argc() != 4 ) {
1739 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
1744 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
1747 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
1749 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
1751 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
1760 void PRVM_Init (void)
1762 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
1763 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "set a property on an entity number in the selected VM (server, client, menu)");
1764 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
1765 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
1766 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)");
1767 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
1768 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
1769 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
1770 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)");
1771 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
1772 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
1773 Cvar_RegisterVariable (&prvm_boundscheck);
1774 Cvar_RegisterVariable (&prvm_traceqc);
1775 Cvar_RegisterVariable (&prvm_statementprofiling);
1785 void PRVM_InitProg(int prognr)
1787 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
1788 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
1790 prog = &prog_list[prognr];
1795 memset(prog, 0, sizeof(prvm_prog_t));
1797 prog->time = &prog->_time;
1798 prog->error_cmd = Host_Error;
1801 int PRVM_GetProgNr()
1803 return prog - prog_list;
1806 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
1808 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
1811 void _PRVM_Free(void *buffer, const char *filename, int fileline)
1813 _Mem_Free(buffer, filename, fileline);
1816 void _PRVM_FreeAll(const char *filename, int fileline)
1819 prog->fielddefs = NULL;
1820 prog->functions = NULL;
1821 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
1824 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
1825 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
1827 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
1832 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
1834 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
1838 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
1841 n = e - prog->edicts;
1842 if ((unsigned int)n >= prog->limit_edicts)
1843 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
1847 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
1849 // return e - prog->edicts;
1852 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
1853 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
1854 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
1857 n = e - prog->edicts;
1858 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1859 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
1860 return n;// EXPERIMENTAL
1861 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
1863 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
1865 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
1866 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
1867 return prog->edicts + n; // EXPERIMENTAL
1868 //return prog->edicts + ((n) / (progs->entityfields * 4));
1873 sizebuf_t vm_tempstringsbuf;
1875 const char *PRVM_GetString(int num)
1879 if (num < prog->stringssize)
1880 return prog->strings + num;
1883 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
1885 num -= prog->stringssize;
1886 if (num < vm_tempstringsbuf.cursize)
1887 return (char *)vm_tempstringsbuf.data + num;
1890 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
1897 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
1907 // special range reserved for tempstrings
1909 if (num < vm_tempstringsbuf.cursize)
1910 return (char *)vm_tempstringsbuf.data + num;
1913 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
1919 if (num < prog->numknownstrings)
1921 if (!prog->knownstrings[num])
1922 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
1923 return prog->knownstrings[num];
1927 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
1933 int PRVM_SetEngineString(const char *s)
1938 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
1939 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
1940 // if it's in the tempstrings area, use a reserved range
1941 // (otherwise we'd get millions of useless string offsets cluttering the database)
1942 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
1944 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
1946 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
1948 // see if it's a known string address
1949 for (i = 0;i < prog->numknownstrings;i++)
1950 if (prog->knownstrings[i] == s)
1952 // new unknown engine string
1953 if (developer.integer >= 100)
1954 Con_Printf("new engine string %p\n", s);
1955 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
1956 if (!prog->knownstrings[i])
1958 if (i >= prog->numknownstrings)
1960 if (i >= prog->maxknownstrings)
1962 const char **oldstrings = prog->knownstrings;
1963 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
1964 prog->maxknownstrings += 128;
1965 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
1966 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
1967 if (prog->numknownstrings)
1969 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
1970 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
1973 prog->numknownstrings++;
1975 prog->firstfreeknownstring = i + 1;
1976 prog->knownstrings[i] = s;
1980 // temp string handling
1982 // all tempstrings go into this buffer consecutively, and it is reset
1983 // whenever PRVM_ExecuteProgram returns to the engine
1984 // (technically each PRVM_ExecuteProgram call saves the cursize value and
1985 // restores it on return, so multiple recursive calls can share the same
1987 // the buffer size is automatically grown as needed
1989 int PRVM_SetTempString(const char *s)
1995 size = (int)strlen(s) + 1;
1996 if (developer.integer >= 300)
1997 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
1998 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2000 sizebuf_t old = vm_tempstringsbuf;
2001 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2002 PRVM_ERROR("PRVM_SetTempString: ran out of tempstring memory! (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", vm_tempstringsbuf.cursize, size);
2003 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2004 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2005 vm_tempstringsbuf.maxsize *= 2;
2006 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2008 if (developer.integer >= 100)
2009 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2010 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2012 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2017 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2019 vm_tempstringsbuf.cursize += size;
2020 return PRVM_SetEngineString(t);
2023 int PRVM_AllocString(size_t bufferlength, char **pointer)
2028 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2029 if (!prog->knownstrings[i])
2031 if (i >= prog->numknownstrings)
2033 if (i >= prog->maxknownstrings)
2035 const char **oldstrings = prog->knownstrings;
2036 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2037 prog->maxknownstrings += 128;
2038 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2039 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2040 if (prog->numknownstrings)
2042 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2043 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2046 prog->numknownstrings++;
2048 prog->firstfreeknownstring = i + 1;
2049 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2050 prog->knownstrings_freeable[i] = true;
2052 *pointer = (char *)(prog->knownstrings[i]);
2056 void PRVM_FreeString(int num)
2059 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2060 else if (num >= 0 && num < prog->stringssize)
2061 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2062 else if (num < 0 && num >= -prog->numknownstrings)
2065 if (!prog->knownstrings[num])
2066 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2067 if (!prog->knownstrings[num])
2068 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2069 PRVM_Free((char *)prog->knownstrings[num]);
2070 prog->knownstrings[num] = NULL;
2071 prog->knownstrings_freeable[num] = false;
2072 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2075 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);