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, qboolean parsebackslash);
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 #ifdef PRVM_BOUNDSCHECK_CVAR
36 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)"};
38 // LordHavoc: prints every opcode as it executes - warning: this is significant spew
39 cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
40 // LordHavoc: counts usage of each QuakeC statement
41 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)"};
42 cvar_t prvm_backtraceforwarnings = {0, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
44 extern sizebuf_t vm_tempstringsbuf;
46 //============================================================================
54 void PRVM_MEM_Alloc(void)
58 // reserve space for the null entity aka world
59 // check bound of max_edicts
60 prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
61 prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
63 // edictprivate_size has to be min as big prvm_edict_private_t
64 prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
67 prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
69 // alloc edict private space
70 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
73 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
76 for(i = 0; i < prog->max_edicts; i++)
78 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
79 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
85 PRVM_MEM_IncreaseEdicts
88 void PRVM_MEM_IncreaseEdicts(void)
91 int oldmaxedicts = prog->max_edicts;
92 void *oldedictsfields = prog->edictsfields;
93 void *oldedictprivate = prog->edictprivate;
95 if(prog->max_edicts >= prog->limit_edicts)
98 PRVM_GCALL(begin_increase_edicts)();
101 prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
103 prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
104 prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
106 memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
107 memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
109 //set e and v pointers
110 for(i = 0; i < prog->max_edicts; i++)
112 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char *)prog->edictprivate + i * prog->edictprivate_size);
113 prog->edicts[i].fields.vp = (void*)((unsigned char *)prog->edictsfields + i * prog->edict_size);
116 PRVM_GCALL(end_increase_edicts)();
118 Mem_Free(oldedictsfields);
119 Mem_Free(oldedictprivate);
122 //============================================================================
125 int PRVM_ED_FindFieldOffset(const char *field)
128 d = PRVM_ED_FindField(field);
134 int PRVM_ED_FindGlobalOffset(const char *global)
137 d = PRVM_ED_FindGlobal(global);
143 func_t PRVM_ED_FindFunctionOffset(const char *function)
146 f = PRVM_ED_FindFunction(function);
149 return (func_t)(f - prog->functions);
152 qboolean PRVM_ProgLoaded(int prognr)
154 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
157 return (prog_list[prognr].loaded ? TRUE : FALSE);
162 PRVM_SetProgFromString
165 // perhaps add a return value when the str doesnt exist
166 qboolean PRVM_SetProgFromString(const char *str)
169 for(; i < PRVM_MAXPROGS ; i++)
170 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
172 if(prog_list[i].loaded)
174 prog = &prog_list[i];
179 Con_Printf("%s not loaded !\n",PRVM_NAME);
184 Con_Printf("Invalid program name %s !\n", str);
193 void PRVM_SetProg(int prognr)
195 if(0 <= prognr && prognr < PRVM_MAXPROGS)
197 if(prog_list[prognr].loaded)
198 prog = &prog_list[prognr];
200 PRVM_ERROR("%i not loaded !", prognr);
203 PRVM_ERROR("Invalid program number %i", prognr);
210 Sets everything to NULL
213 void PRVM_ED_ClearEdict (prvm_edict_t *e)
215 memset (e->fields.vp, 0, prog->progs->entityfields * 4);
216 e->priv.required->free = false;
218 // AK: Let the init_edict function determine if something needs to be initialized
219 PRVM_GCALL(init_edict)(e);
226 Either finds a free edict, or allocates a new one.
227 Try to avoid reusing an entity that was recently freed, because it
228 can cause the client to think the entity morphed into something else
229 instead of being removed and recreated, which can cause interpolated
230 angles and bad trails.
233 prvm_edict_t *PRVM_ED_Alloc (void)
238 // the client qc dont need maxclients
239 // thus it doesnt need to use svs.maxclients
240 // AK: changed i=svs.maxclients+1
241 // AK: changed so the edict 0 wont spawn -> used as reserved/world entity
242 // although the menu/client has no world
243 for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
245 e = PRVM_EDICT_NUM(i);
246 // the first couple seconds of server time can involve a lot of
247 // freeing and allocating, so relax the replacement policy
248 if (e->priv.required->free && ( e->priv.required->freetime < 2 || prog->globaloffsets.time < 0 || (PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float - e->priv.required->freetime) > 0.5 ) )
250 PRVM_ED_ClearEdict (e);
255 if (i == prog->limit_edicts)
256 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
259 if (prog->num_edicts >= prog->max_edicts)
260 PRVM_MEM_IncreaseEdicts();
262 e = PRVM_EDICT_NUM(i);
263 PRVM_ED_ClearEdict (e);
272 Marks the edict as free
273 FIXME: walk all entities and NULL out references to this entity
276 void PRVM_ED_Free (prvm_edict_t *ed)
278 // dont delete the null entity (world) or reserved edicts
279 if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
282 PRVM_GCALL(free_edict)(ed);
284 ed->priv.required->free = true;
285 ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
288 //===========================================================================
295 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
300 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
302 def = &prog->globaldefs[i];
314 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
319 for (i=0 ; i<prog->progs->numfielddefs ; i++)
321 def = &prog->fielddefs[i];
333 ddef_t *PRVM_ED_FindField (const char *name)
338 for (i=0 ; i<prog->progs->numfielddefs ; i++)
340 def = &prog->fielddefs[i];
341 if (!strcmp(PRVM_GetString(def->s_name), name))
352 ddef_t *PRVM_ED_FindGlobal (const char *name)
357 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
359 def = &prog->globaldefs[i];
360 if (!strcmp(PRVM_GetString(def->s_name), name))
372 mfunction_t *PRVM_ED_FindFunction (const char *name)
377 for (i=0 ; i<prog->progs->numfunctions ; i++)
379 func = &prog->functions[i];
380 if (!strcmp(PRVM_GetString(func->s_name), name))
391 Returns a string describing *data in a type specific manner
394 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
396 static char line[MAX_INPUTLINE];
401 type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
406 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
410 if (n < 0 || n >= prog->limit_edicts)
411 sprintf (line, "entity %i (invalid!)", n);
413 sprintf (line, "entity %i", n);
416 f = prog->functions + val->function;
417 sprintf (line, "%s()", PRVM_GetString(f->s_name));
420 def = PRVM_ED_FieldAtOfs ( val->_int );
421 sprintf (line, ".%s", PRVM_GetString(def->s_name));
424 sprintf (line, "void");
427 // LordHavoc: changed from %5.1f to %10.4f
428 sprintf (line, "%10.4f", val->_float);
431 // LordHavoc: changed from %5.1f to %10.4f
432 sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
435 sprintf (line, "pointer");
438 sprintf (line, "bad type %i", (int) type);
449 Returns a string describing *data in a type specific manner
450 Easier to parse than PR_ValueString
453 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
455 static char line[MAX_INPUTLINE];
461 type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
466 // Parse the string a bit to turn special characters
467 // (like newline, specifically) into escape codes,
468 // this fixes saving games from various mods
469 s = PRVM_GetString (val->string);
470 for (i = 0;i < (int)sizeof(line) - 2 && *s;)
489 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
492 f = prog->functions + val->function;
493 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
496 def = PRVM_ED_FieldAtOfs ( val->_int );
497 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
500 dpsnprintf (line, sizeof (line), "void");
503 dpsnprintf (line, sizeof (line), "%f", val->_float);
506 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
509 dpsnprintf (line, sizeof (line), "bad type %i", type);
520 Returns a string with a description and the contents of a global,
521 padded to 20 field width
524 char *PRVM_GlobalString (int ofs)
530 static char line[128];
532 val = (void *)&prog->globals.generic[ofs];
533 def = PRVM_ED_GlobalAtOfs(ofs);
535 sprintf (line,"GLOBAL%i", ofs);
538 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
539 sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s);
543 //for ( ; i<20 ; i++)
544 // strcat (line," ");
550 char *PRVM_GlobalStringNoContents (int ofs)
554 static char line[128];
556 def = PRVM_ED_GlobalAtOfs(ofs);
558 sprintf (line,"GLOBAL%i", ofs);
560 sprintf (line,"%s", PRVM_GetString(def->s_name));
563 //for ( ; i<20 ; i++)
564 // strcat (line," ");
578 // LordHavoc: optimized this to print out much more quickly (tempstring)
579 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
580 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
588 char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
590 if (ed->priv.required->free)
592 Con_Printf("%s: FREE\n",PRVM_NAME);
597 sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
598 for (i=1 ; i<prog->progs->numfielddefs ; i++)
600 d = &prog->fielddefs[i];
601 name = PRVM_GetString(d->s_name);
602 if (name[strlen(name)-2] == '_')
603 continue; // skip _x, _y, _z vars
605 // Check Field Name Wildcard
606 if(wildcard_fieldname)
607 if( !matchpattern(name, wildcard_fieldname, 1) )
608 // Didn't match; skip
611 v = (int *)((char *)ed->fields.vp + d->ofs*4);
613 // if the value is still all 0, skip the field
614 type = d->type & ~DEF_SAVEGLOBAL;
616 for (j=0 ; j<prvm_type_size[type] ; j++)
619 if (j == prvm_type_size[type])
622 if (strlen(name) > sizeof(tempstring2)-4)
624 memcpy (tempstring2, name, sizeof(tempstring2)-4);
625 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
626 tempstring2[sizeof(tempstring2)-1] = 0;
629 strlcat(tempstring, name, sizeof(tempstring));
630 for (l = strlen(name);l < 14;l++)
631 strlcat(tempstring, " ", sizeof(tempstring));
632 strlcat(tempstring, " ", sizeof(tempstring));
634 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
635 if (strlen(name) > sizeof(tempstring2)-4)
637 memcpy (tempstring2, name, sizeof(tempstring2)-4);
638 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
639 tempstring2[sizeof(tempstring2)-1] = 0;
642 strlcat(tempstring, name, sizeof(tempstring));
643 strlcat(tempstring, "\n", sizeof(tempstring));
644 if (strlen(tempstring) >= sizeof(tempstring)/2)
646 Con_Print(tempstring);
651 Con_Print(tempstring);
661 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
671 if (ed->priv.required->free)
677 for (i=1 ; i<prog->progs->numfielddefs ; i++)
679 d = &prog->fielddefs[i];
680 name = PRVM_GetString(d->s_name);
681 if (name[strlen(name)-2] == '_')
682 continue; // skip _x, _y, _z vars
684 v = (int *)((char *)ed->fields.vp + d->ofs*4);
686 // if the value is still all 0, skip the field
687 type = d->type & ~DEF_SAVEGLOBAL;
688 for (j=0 ; j<prvm_type_size[type] ; j++)
691 if (j == prvm_type_size[type])
694 FS_Printf(f,"\"%s\" ",name);
695 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
701 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
703 PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
708 PRVM_ED_PrintEdicts_f
710 For debugging, prints all the entities in the current server
713 void PRVM_ED_PrintEdicts_f (void)
716 const char *wildcard_fieldname;
718 if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
720 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
725 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
729 wildcard_fieldname = Cmd_Argv(2);
731 wildcard_fieldname = NULL;
733 Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
734 for (i=0 ; i<prog->num_edicts ; i++)
735 PRVM_ED_PrintNum (i, wildcard_fieldname);
744 For debugging, prints a single edict
747 void PRVM_ED_PrintEdict_f (void)
750 const char *wildcard_fieldname;
752 if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
754 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
759 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
762 i = atoi (Cmd_Argv(2));
763 if (i >= prog->num_edicts)
765 Con_Print("Bad edict number\n");
770 // Optional Wildcard Provided
771 wildcard_fieldname = Cmd_Argv(3);
774 wildcard_fieldname = NULL;
775 PRVM_ED_PrintNum (i, wildcard_fieldname);
787 // 2 possibilities : 1. just displaying the active edict count
788 // 2. making a function pointer [x]
789 void PRVM_ED_Count_f (void)
797 Con_Print("prvm_count <program name>\n");
802 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
805 if(prog->count_edicts)
806 prog->count_edicts();
810 for (i=0 ; i<prog->num_edicts ; i++)
812 ent = PRVM_EDICT_NUM(i);
813 if (ent->priv.required->free)
818 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
819 Con_Printf("active :%3i\n", active);
826 ==============================================================================
830 FIXME: need to tag constants, doesn't really work
831 ==============================================================================
839 void PRVM_ED_WriteGlobals (qfile_t *f)
847 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
849 def = &prog->globaldefs[i];
851 if ( !(def->type & DEF_SAVEGLOBAL) )
853 type &= ~DEF_SAVEGLOBAL;
855 if (type != ev_string && type != ev_float && type != ev_entity)
858 name = PRVM_GetString(def->s_name);
859 FS_Printf(f,"\"%s\" ", name);
860 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
870 void PRVM_ED_ParseGlobals (const char *data)
872 char keyname[MAX_INPUTLINE];
878 if (!COM_ParseToken_Simple(&data, false, false))
879 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
880 if (com_token[0] == '}')
883 strlcpy (keyname, com_token, sizeof(keyname));
886 if (!COM_ParseToken_Simple(&data, false, true))
887 PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
889 if (com_token[0] == '}')
890 PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
892 key = PRVM_ED_FindGlobal (keyname);
895 Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
899 if (!PRVM_ED_ParseEpair(NULL, key, com_token, false))
900 PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
904 //============================================================================
911 Can parse either fields or globals
912 returns false if error
915 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
924 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
926 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
927 switch (key->type & ~DEF_SAVEGLOBAL)
930 l = (int)strlen(s) + 1;
931 val->string = PRVM_AllocString(l, &new_p);
932 for (i = 0;i < l;i++)
934 if (s[i] == '\\' && i < l-1 && s[i] == 'n' && parsebackslash)
939 else if (s[i] == '\\' && i < l-1 && s[i] == 'r' && parsebackslash)
950 while (*s && *s <= ' ')
952 val->_float = atof(s);
956 for (i = 0;i < 3;i++)
958 while (*s && *s <= ' ')
962 val->vector[i] = atof(s);
971 while (*s && *s <= ' ')
974 if (i >= prog->limit_edicts)
975 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);
976 while (i >= prog->max_edicts)
977 PRVM_MEM_IncreaseEdicts();
978 // if IncreaseEdicts was called the base pointer needs to be updated
980 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
981 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
987 Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
990 def = PRVM_ED_FindField(s + 1);
993 Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
996 val->_int = def->ofs;
1000 func = PRVM_ED_FindFunction(s);
1003 Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1006 val->function = func - prog->functions;
1010 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1020 Console command to send a string to QC function GameCommand of the
1024 sv_cmd adminmsg 3 "do not teamkill"
1025 cl_cmd someclientcommand
1026 menu_cmd somemenucommand
1028 All progs can support this extension; sg calls it in server QC, cg in client
1032 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1036 Con_Printf("%s text...\n", whichcmd);
1041 if(!PRVM_SetProgFromString(whichprogs))
1042 // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1043 // also, it makes printing error messages easier!
1045 Con_Printf("%s program not loaded.\n", whichprogs);
1049 if(!prog->funcoffsets.GameCommand)
1051 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1055 int restorevm_tempstringsbuf_cursize;
1060 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1061 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1062 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1063 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1068 void PRVM_GameCommand_Server_f(void)
1070 PRVM_GameCommand("server", "sv_cmd");
1072 void PRVM_GameCommand_Client_f(void)
1074 PRVM_GameCommand("client", "cl_cmd");
1076 void PRVM_GameCommand_Menu_f(void)
1078 PRVM_GameCommand("menu", "menu_cmd");
1085 Console command to set a field of a specified edict
1088 void PRVM_ED_EdictSet_f(void)
1095 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1100 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1102 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1106 ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1108 if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1109 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1111 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1117 ====================
1120 Parses an edict out of the given string, returning the new position
1121 ed should be a properly initialized empty edict.
1122 Used for initial level load and for savegames.
1123 ====================
1125 extern cvar_t developer_entityparsing;
1126 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1136 // go through all the dictionary pairs
1140 if (!COM_ParseToken_Simple(&data, false, false))
1141 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1142 if (developer_entityparsing.integer)
1143 Con_Printf("Key: \"%s\"", com_token);
1144 if (com_token[0] == '}')
1147 // anglehack is to allow QuakeEd to write single scalar angles
1148 // and allow them to be turned into vectors. (FIXME...)
1149 if (!strcmp(com_token, "angle"))
1151 strlcpy (com_token, "angles", sizeof(com_token));
1157 // FIXME: change light to _light to get rid of this hack
1158 if (!strcmp(com_token, "light"))
1159 strlcpy (com_token, "light_lev", sizeof(com_token)); // hack for single light def
1161 strlcpy (keyname, com_token, sizeof(keyname));
1163 // another hack to fix keynames with trailing spaces
1164 n = strlen(keyname);
1165 while (n && keyname[n-1] == ' ')
1172 if (!COM_ParseToken_Simple(&data, false, false))
1173 PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1174 if (developer_entityparsing.integer)
1175 Con_Printf(" \"%s\"\n", com_token);
1177 if (com_token[0] == '}')
1178 PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1182 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1186 // keynames with a leading underscore are used for utility comments,
1187 // and are immediately discarded by quake
1188 if (keyname[0] == '_')
1191 key = PRVM_ED_FindField (keyname);
1194 Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1201 strlcpy (temp, com_token, sizeof(temp));
1202 sprintf (com_token, "0 %s 0", temp);
1205 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1206 PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1210 ent->priv.required->free = true;
1218 PRVM_ED_LoadFromFile
1220 The entities are directly placed in the array, rather than allocated with
1221 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1222 number references out of order.
1224 Creates a server's entity / program execution context by
1225 parsing textual entity definitions out of an ent file.
1227 Used for both fresh maps and savegame loads. A fresh map would also need
1228 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1231 void PRVM_ED_LoadFromFile (const char *data)
1234 int parsed, inhibited, spawned, died;
1235 const char *funcname;
1247 // parse the opening brace
1248 if (!COM_ParseToken_Simple(&data, false, false))
1250 if (com_token[0] != '{')
1251 PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1253 // CHANGED: this is not conform to PR_LoadFromFile
1254 if(prog->loadintoworld)
1256 prog->loadintoworld = false;
1257 ent = PRVM_EDICT_NUM(0);
1260 ent = PRVM_ED_Alloc();
1263 if (ent != prog->edicts) // hack
1264 memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1266 data = PRVM_ED_ParseEdict (data, ent);
1269 // remove the entity ?
1270 if(prog->load_edict && !prog->load_edict(ent))
1278 // immediately call spawn function, but only if there is a self global and a classname
1280 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1282 string_t handle = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1285 Con_Print("No classname for:\n");
1286 PRVM_ED_Print(ent, NULL);
1291 // look for the spawn function
1292 funcname = PRVM_GetString(handle);
1293 func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1295 func = PRVM_ED_FindFunction (funcname);
1299 // check for OnEntityNoSpawnFunction
1300 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1303 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1304 PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1308 if (developer.integer) // don't confuse non-developers with errors
1310 Con_Print("No spawn function for:\n");
1311 PRVM_ED_Print(ent, NULL);
1320 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1321 PRVM_ExecuteProgram (func - prog->functions, "");
1326 if (ent->priv.required->free)
1330 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);
1333 void PRVM_FindOffsets(void)
1335 // field and global searches use -1 for NULL
1336 memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1337 memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1338 // functions use 0 for NULL
1339 memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1341 // server and client qc use a lot of similar fields, so this is combined
1342 prog->fieldoffsets.SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
1343 prog->fieldoffsets.Version = PRVM_ED_FindFieldOffset("Version");
1344 prog->fieldoffsets.alpha = PRVM_ED_FindFieldOffset("alpha");
1345 prog->fieldoffsets.ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
1346 prog->fieldoffsets.ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1347 prog->fieldoffsets.ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1348 prog->fieldoffsets.ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
1349 prog->fieldoffsets.ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
1350 prog->fieldoffsets.ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
1351 prog->fieldoffsets.ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
1352 prog->fieldoffsets.angles = PRVM_ED_FindFieldOffset("angles");
1353 prog->fieldoffsets.button3 = PRVM_ED_FindFieldOffset("button3");
1354 prog->fieldoffsets.button4 = PRVM_ED_FindFieldOffset("button4");
1355 prog->fieldoffsets.button5 = PRVM_ED_FindFieldOffset("button5");
1356 prog->fieldoffsets.button6 = PRVM_ED_FindFieldOffset("button6");
1357 prog->fieldoffsets.button7 = PRVM_ED_FindFieldOffset("button7");
1358 prog->fieldoffsets.button8 = PRVM_ED_FindFieldOffset("button8");
1359 prog->fieldoffsets.button9 = PRVM_ED_FindFieldOffset("button9");
1360 prog->fieldoffsets.button10 = PRVM_ED_FindFieldOffset("button10");
1361 prog->fieldoffsets.button11 = PRVM_ED_FindFieldOffset("button11");
1362 prog->fieldoffsets.button12 = PRVM_ED_FindFieldOffset("button12");
1363 prog->fieldoffsets.button13 = PRVM_ED_FindFieldOffset("button13");
1364 prog->fieldoffsets.button14 = PRVM_ED_FindFieldOffset("button14");
1365 prog->fieldoffsets.button15 = PRVM_ED_FindFieldOffset("button15");
1366 prog->fieldoffsets.button16 = PRVM_ED_FindFieldOffset("button16");
1367 prog->fieldoffsets.buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
1368 prog->fieldoffsets.buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
1369 prog->fieldoffsets.chain = PRVM_ED_FindFieldOffset("chain");
1370 prog->fieldoffsets.classname = PRVM_ED_FindFieldOffset("classname");
1371 prog->fieldoffsets.clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
1372 prog->fieldoffsets.color = PRVM_ED_FindFieldOffset("color");
1373 prog->fieldoffsets.colormod = PRVM_ED_FindFieldOffset("colormod");
1374 prog->fieldoffsets.contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
1375 prog->fieldoffsets.cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
1376 prog->fieldoffsets.cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
1377 prog->fieldoffsets.cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1378 prog->fieldoffsets.cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1379 prog->fieldoffsets.cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
1380 prog->fieldoffsets.customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
1381 prog->fieldoffsets.dimension_hit = PRVM_ED_FindFieldOffset("dimension_hit");
1382 prog->fieldoffsets.dimension_solid = PRVM_ED_FindFieldOffset("dimension_solid");
1383 prog->fieldoffsets.disableclientprediction = PRVM_ED_FindFieldOffset("disableclientprediction");
1384 prog->fieldoffsets.dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1385 prog->fieldoffsets.drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
1386 prog->fieldoffsets.exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1387 prog->fieldoffsets.fatness = PRVM_ED_FindFieldOffset("fatness");
1388 prog->fieldoffsets.forceshader = PRVM_ED_FindFieldOffset("forceshader");
1389 prog->fieldoffsets.frame = PRVM_ED_FindFieldOffset("frame");
1390 prog->fieldoffsets.frame1time = PRVM_ED_FindFieldOffset("frame1time");
1391 prog->fieldoffsets.frame2 = PRVM_ED_FindFieldOffset("frame2");
1392 prog->fieldoffsets.frame2time = PRVM_ED_FindFieldOffset("frame2time");
1393 prog->fieldoffsets.fullbright = PRVM_ED_FindFieldOffset("fullbright");
1394 prog->fieldoffsets.glow_color = PRVM_ED_FindFieldOffset("glow_color");
1395 prog->fieldoffsets.glow_size = PRVM_ED_FindFieldOffset("glow_size");
1396 prog->fieldoffsets.glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
1397 prog->fieldoffsets.gravity = PRVM_ED_FindFieldOffset("gravity");
1398 prog->fieldoffsets.groundentity = PRVM_ED_FindFieldOffset("groundentity");
1399 prog->fieldoffsets.hull = PRVM_ED_FindFieldOffset("hull");
1400 prog->fieldoffsets.ideal_yaw = PRVM_ED_FindFieldOffset("ideal_yaw");
1401 prog->fieldoffsets.idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
1402 prog->fieldoffsets.items2 = PRVM_ED_FindFieldOffset("items2");
1403 prog->fieldoffsets.lerpfrac = PRVM_ED_FindFieldOffset("lerpfrac");
1404 prog->fieldoffsets.light_lev = PRVM_ED_FindFieldOffset("light_lev");
1405 prog->fieldoffsets.message = PRVM_ED_FindFieldOffset("message");
1406 prog->fieldoffsets.modelflags = PRVM_ED_FindFieldOffset("modelflags");
1407 prog->fieldoffsets.movement = PRVM_ED_FindFieldOffset("movement");
1408 prog->fieldoffsets.movetypesteplandevent = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1409 prog->fieldoffsets.netaddress = PRVM_ED_FindFieldOffset("netaddress");
1410 prog->fieldoffsets.nextthink = PRVM_ED_FindFieldOffset("nextthink");
1411 prog->fieldoffsets.nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
1412 prog->fieldoffsets.pflags = PRVM_ED_FindFieldOffset("pflags");
1413 prog->fieldoffsets.ping = PRVM_ED_FindFieldOffset("ping");
1414 prog->fieldoffsets.pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
1415 prog->fieldoffsets.playermodel = PRVM_ED_FindFieldOffset("playermodel");
1416 prog->fieldoffsets.playerskin = PRVM_ED_FindFieldOffset("playerskin");
1417 prog->fieldoffsets.pmodel = PRVM_ED_FindFieldOffset("pmodel");
1418 prog->fieldoffsets.punchvector = PRVM_ED_FindFieldOffset("punchvector");
1419 prog->fieldoffsets.renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1420 prog->fieldoffsets.renderflags = PRVM_ED_FindFieldOffset("renderflags");
1421 prog->fieldoffsets.rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1422 prog->fieldoffsets.scale = PRVM_ED_FindFieldOffset("scale");
1423 prog->fieldoffsets.style = PRVM_ED_FindFieldOffset("style");
1424 prog->fieldoffsets.tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
1425 prog->fieldoffsets.tag_index = PRVM_ED_FindFieldOffset("tag_index");
1426 prog->fieldoffsets.think = PRVM_ED_FindFieldOffset("think");
1427 prog->fieldoffsets.viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
1428 prog->fieldoffsets.viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
1429 prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed");
1430 prog->fieldoffsets.clientcamera = PRVM_ED_FindFieldOffset("clientcamera");
1431 prog->funcoffsets.CSQC_ConsoleCommand = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1432 prog->funcoffsets.CSQC_Ent_Remove = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1433 prog->funcoffsets.CSQC_Ent_Update = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1434 prog->funcoffsets.CSQC_Ent_Spawn = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1435 prog->funcoffsets.CSQC_Event = PRVM_ED_FindFunctionOffset("CSQC_Event");
1436 prog->funcoffsets.CSQC_Event_Sound = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1437 prog->funcoffsets.CSQC_Init = PRVM_ED_FindFunctionOffset("CSQC_Init");
1438 prog->funcoffsets.CSQC_InputEvent = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1439 prog->funcoffsets.CSQC_Parse_CenterPrint = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1440 prog->funcoffsets.CSQC_Parse_Print = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1441 prog->funcoffsets.CSQC_Parse_StuffCmd = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1442 prog->funcoffsets.CSQC_Parse_TempEntity = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1443 prog->funcoffsets.CSQC_Shutdown = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1444 prog->funcoffsets.CSQC_UpdateView = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1445 prog->funcoffsets.Gecko_Query = PRVM_ED_FindFunctionOffset("Gecko_Query");
1446 prog->funcoffsets.EndFrame = PRVM_ED_FindFunctionOffset("EndFrame");
1447 prog->funcoffsets.RestoreGame = PRVM_ED_FindFunctionOffset("RestoreGame");
1448 prog->funcoffsets.SV_ChangeTeam = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1449 prog->funcoffsets.SV_ParseClientCommand = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1450 prog->funcoffsets.SV_PlayerPhysics = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1451 prog->funcoffsets.SV_OnEntityNoSpawnFunction = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1452 prog->funcoffsets.GameCommand = PRVM_ED_FindFunctionOffset("GameCommand");
1453 prog->funcoffsets.SV_Shutdown = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1454 prog->globaloffsets.SV_InitCmd = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1455 prog->globaloffsets.self = PRVM_ED_FindGlobalOffset("self");
1456 prog->globaloffsets.time = PRVM_ED_FindGlobalOffset("time");
1457 prog->globaloffsets.v_forward = PRVM_ED_FindGlobalOffset("v_forward");
1458 prog->globaloffsets.v_right = PRVM_ED_FindGlobalOffset("v_right");
1459 prog->globaloffsets.v_up = PRVM_ED_FindGlobalOffset("v_up");
1460 prog->globaloffsets.view_angles = PRVM_ED_FindGlobalOffset("view_angles");
1461 prog->globaloffsets.trace_allsolid = PRVM_ED_FindGlobalOffset("trace_allsolid");
1462 prog->globaloffsets.trace_startsolid = PRVM_ED_FindGlobalOffset("trace_startsolid");
1463 prog->globaloffsets.trace_fraction = PRVM_ED_FindGlobalOffset("trace_fraction");
1464 prog->globaloffsets.trace_inwater = PRVM_ED_FindGlobalOffset("trace_inwater");
1465 prog->globaloffsets.trace_inopen = PRVM_ED_FindGlobalOffset("trace_inopen");
1466 prog->globaloffsets.trace_endpos = PRVM_ED_FindGlobalOffset("trace_endpos");
1467 prog->globaloffsets.trace_plane_normal = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1468 prog->globaloffsets.trace_plane_dist = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1469 prog->globaloffsets.trace_ent = PRVM_ED_FindGlobalOffset("trace_ent");
1470 prog->globaloffsets.trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1471 prog->globaloffsets.trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1472 prog->globaloffsets.trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1473 prog->globaloffsets.trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1474 prog->globaloffsets.intermission = PRVM_ED_FindGlobalOffset("intermission");
1475 prog->globaloffsets.coop = PRVM_ED_FindGlobalOffset("coop");
1476 prog->globaloffsets.deathmatch = PRVM_ED_FindGlobalOffset("deathmatch");
1477 prog->globaloffsets.dmg_take = PRVM_ED_FindGlobalOffset("dmg_take");
1478 prog->globaloffsets.dmg_save = PRVM_ED_FindGlobalOffset("dmg_save");
1479 prog->globaloffsets.dmg_origin = PRVM_ED_FindGlobalOffset("dmg_origin");
1480 prog->globaloffsets.sb_showscores = PRVM_ED_FindGlobalOffset("sb_showscores");
1481 prog->globaloffsets.drawfont = PRVM_ED_FindGlobalOffset("drawfont");
1483 // menu qc only uses some functions, nothing else
1484 prog->funcoffsets.m_draw = PRVM_ED_FindFunctionOffset("m_draw");
1485 prog->funcoffsets.m_init = PRVM_ED_FindFunctionOffset("m_init");
1486 prog->funcoffsets.m_keydown = PRVM_ED_FindFunctionOffset("m_keydown");
1487 prog->funcoffsets.m_keyup = PRVM_ED_FindFunctionOffset("m_keyup");
1488 prog->funcoffsets.m_shutdown = PRVM_ED_FindFunctionOffset("m_shutdown");
1489 prog->funcoffsets.m_toggle = PRVM_ED_FindFunctionOffset("m_toggle");
1494 typedef struct dpfield_s
1501 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1503 dpfield_t dpfields[] =
1514 void PRVM_ResetProg()
1516 PRVM_GCALL(reset_cmd)();
1517 Mem_FreePool(&prog->progs_mempool);
1518 memset(prog,0,sizeof(prvm_prog_t));
1519 prog->starttime = Sys_DoubleTime();
1527 void PRVM_LoadLNO( const char *progname ) {
1528 fs_offset_t filesize;
1530 unsigned int *header;
1533 FS_StripExtension( progname, filename, sizeof( filename ) );
1534 strlcat( filename, ".lno", sizeof( filename ) );
1536 lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1542 <Spike> SafeWrite (h, &lnotype, sizeof(int));
1543 <Spike> SafeWrite (h, &version, sizeof(int));
1544 <Spike> SafeWrite (h, &numglobaldefs, sizeof(int));
1545 <Spike> SafeWrite (h, &numpr_globals, sizeof(int));
1546 <Spike> SafeWrite (h, &numfielddefs, sizeof(int));
1547 <Spike> SafeWrite (h, &numstatements, sizeof(int));
1548 <Spike> SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1550 if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1555 header = (unsigned int *) lno;
1556 if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1557 LittleLong( header[ 1 ] ) == 1 &&
1558 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1559 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1560 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1561 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1563 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1564 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1574 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1578 ddef_t *infielddefs;
1579 dfunction_t *dfunctions;
1580 fs_offset_t filesize;
1582 if( prog->loaded ) {
1583 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1586 prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1587 if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1588 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1590 Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1592 prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1594 // byte swap the header
1595 for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1596 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1598 if (prog->progs->version != PROG_VERSION)
1599 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1600 if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1601 PRVM_ERROR ("%s: %s system vars have been modified (CRC of progs.dat systemvars %i != engine %i), progdefs.h is out of date", PRVM_NAME, filename, prog->progs->crc, prog->headercrc);
1603 //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1604 dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1606 if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1607 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1608 prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1609 prog->stringssize = prog->progs->numstrings;
1611 prog->numknownstrings = 0;
1612 prog->maxknownstrings = 0;
1613 prog->knownstrings = NULL;
1614 prog->knownstrings_freeable = NULL;
1616 Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1618 prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1620 // we need to expand the fielddefs list to include all the engine fields,
1621 // so allocate a new place for it
1622 infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1624 prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1626 prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1628 prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1630 // moved edict_size calculation down below field adding code
1632 //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1633 prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1635 // byte swap the lumps
1636 for (i=0 ; i<prog->progs->numstatements ; i++)
1638 prog->statements[i].op = LittleShort(prog->statements[i].op);
1639 prog->statements[i].a = LittleShort(prog->statements[i].a);
1640 prog->statements[i].b = LittleShort(prog->statements[i].b);
1641 prog->statements[i].c = LittleShort(prog->statements[i].c);
1644 prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1645 for (i = 0;i < prog->progs->numfunctions;i++)
1647 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1648 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1649 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1650 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1651 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1652 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1653 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1656 for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1658 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1659 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1660 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1663 // copy the progs fields to the new fields list
1664 for (i = 0;i < prog->progs->numfielddefs;i++)
1666 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1667 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1668 PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1669 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1670 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1673 // append the required fields
1674 for (i = 0;i < (int) numrequiredfields;i++)
1676 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1677 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1678 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1679 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1680 prog->progs->entityfields += 3;
1682 prog->progs->entityfields++;
1683 prog->progs->numfielddefs++;
1686 // check required functions
1687 for(i=0 ; i < numrequiredfunc ; i++)
1688 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1689 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1691 // check required globals
1692 for(i=0 ; i < numrequiredglobals ; i++)
1693 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1694 PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1696 for (i=0 ; i<prog->progs->numglobals ; i++)
1697 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1699 // moved edict_size calculation down here, below field adding code
1700 // LordHavoc: this no longer includes the prvm_edict_t header
1701 prog->edict_size = prog->progs->entityfields * 4;
1702 prog->edictareasize = prog->edict_size * prog->limit_edicts;
1704 // LordHavoc: bounds check anything static
1705 for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1711 if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1712 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1715 if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1716 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1718 // global global global
1753 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1754 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1756 // global none global
1762 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1763 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1779 if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1780 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1794 if ((unsigned short) st->a >= prog->progs->numglobals)
1795 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1798 Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1803 PRVM_LoadLNO(filename);
1807 prog->loaded = TRUE;
1809 // set flags & ddef_ts in prog
1815 PRVM_GCALL(init_cmd)();
1822 void PRVM_Fields_f (void)
1824 int i, j, ednum, used, usedamount;
1826 char tempstring[MAX_INPUTLINE], tempstring2[260];
1836 Con_Print("no progs loaded\n");
1843 Con_Print("prvm_fields <program name>\n");
1848 if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1851 counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1852 for (ednum = 0;ednum < prog->max_edicts;ednum++)
1854 ed = PRVM_EDICT_NUM(ednum);
1855 if (ed->priv.required->free)
1857 for (i = 1;i < prog->progs->numfielddefs;i++)
1859 d = &prog->fielddefs[i];
1860 name = PRVM_GetString(d->s_name);
1861 if (name[strlen(name)-2] == '_')
1862 continue; // skip _x, _y, _z vars
1863 v = (int *)((char *)ed->fields.vp + d->ofs*4);
1864 // if the value is still all 0, skip the field
1865 for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1878 for (i = 0;i < prog->progs->numfielddefs;i++)
1880 d = &prog->fielddefs[i];
1881 name = PRVM_GetString(d->s_name);
1882 if (name[strlen(name)-2] == '_')
1883 continue; // skip _x, _y, _z vars
1884 switch(d->type & ~DEF_SAVEGLOBAL)
1887 strlcat(tempstring, "string ", sizeof(tempstring));
1890 strlcat(tempstring, "entity ", sizeof(tempstring));
1893 strlcat(tempstring, "function ", sizeof(tempstring));
1896 strlcat(tempstring, "field ", sizeof(tempstring));
1899 strlcat(tempstring, "void ", sizeof(tempstring));
1902 strlcat(tempstring, "float ", sizeof(tempstring));
1905 strlcat(tempstring, "vector ", sizeof(tempstring));
1908 strlcat(tempstring, "pointer ", sizeof(tempstring));
1911 sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1912 strlcat(tempstring, tempstring2, sizeof(tempstring));
1915 if (strlen(name) > sizeof(tempstring2)-4)
1917 memcpy (tempstring2, name, sizeof(tempstring2)-4);
1918 tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1919 tempstring2[sizeof(tempstring2)-1] = 0;
1922 strlcat(tempstring, name, sizeof(tempstring));
1923 for (j = (int)strlen(name);j < 25;j++)
1924 strlcat(tempstring, " ", sizeof(tempstring));
1925 sprintf(tempstring2, "%5d", counts[i]);
1926 strlcat(tempstring, tempstring2, sizeof(tempstring));
1927 strlcat(tempstring, "\n", sizeof(tempstring));
1928 if (strlen(tempstring) >= sizeof(tempstring)/2)
1930 Con_Print(tempstring);
1936 usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1940 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);
1945 void PRVM_Globals_f (void)
1948 const char *wildcard;
1954 Con_Print("no progs loaded\n");
1957 if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
1959 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
1964 if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1967 if( Cmd_Argc() == 3)
1968 wildcard = Cmd_Argv(2);
1972 Con_Printf("%s :", PRVM_NAME);
1974 for (i = 0;i < prog->progs->numglobaldefs;i++)
1977 if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
1982 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1984 Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
1994 void PRVM_Global_f(void)
1997 if( Cmd_Argc() != 3 ) {
1998 Con_Printf( "prvm_global <program name> <global name>\n" );
2003 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2006 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2008 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2010 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2019 void PRVM_GlobalSet_f(void)
2022 if( Cmd_Argc() != 4 ) {
2023 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2028 if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2031 global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2033 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2035 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2044 void PRVM_Init (void)
2046 Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2047 Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2048 Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2049 Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2050 Cmd_AddCommand ("prvm_callprofile", PRVM_CallProfile_f, "prints execution statistics about the most time consuming QuakeC calls from the engine in the selected VM (server, client, menu)");
2051 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)");
2052 Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2053 Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2054 Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2055 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)");
2056 Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2057 Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2058 Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2059 Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2060 // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
2061 #ifdef PRVM_BOUNDSCHECK_CVAR
2062 Cvar_RegisterVariable (&prvm_boundscheck);
2064 Cvar_RegisterVariable (&prvm_traceqc);
2065 Cvar_RegisterVariable (&prvm_statementprofiling);
2066 Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2076 void PRVM_InitProg(int prognr)
2078 if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2079 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2081 prog = &prog_list[prognr];
2086 memset(prog, 0, sizeof(prvm_prog_t));
2087 prog->starttime = Sys_DoubleTime();
2089 prog->error_cmd = Host_Error;
2092 int PRVM_GetProgNr()
2094 return prog - prog_list;
2097 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2099 return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2102 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2104 _Mem_Free(buffer, filename, fileline);
2107 void _PRVM_FreeAll(const char *filename, int fileline)
2110 prog->fielddefs = NULL;
2111 prog->functions = NULL;
2112 _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2115 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2116 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2118 PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2123 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2125 PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2129 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2132 n = e - prog->edicts;
2133 if ((unsigned int)n >= prog->limit_edicts)
2134 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2138 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2140 // return e - prog->edicts;
2143 //#define PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2144 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2145 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2148 n = e - prog->edicts;
2149 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2150 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2151 return n;// EXPERIMENTAL
2152 //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2154 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2156 if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2157 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2158 return prog->edicts + n; // EXPERIMENTAL
2159 //return prog->edicts + ((n) / (progs->entityfields * 4));
2164 sizebuf_t vm_tempstringsbuf;
2166 const char *PRVM_GetString(int num)
2170 if (num < prog->stringssize)
2171 return prog->strings + num;
2174 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2176 num -= prog->stringssize;
2177 if (num < vm_tempstringsbuf.cursize)
2178 return (char *)vm_tempstringsbuf.data + num;
2181 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2188 VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2198 // special range reserved for tempstrings
2200 if (num < vm_tempstringsbuf.cursize)
2201 return (char *)vm_tempstringsbuf.data + num;
2204 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2210 if (num < prog->numknownstrings)
2212 if (!prog->knownstrings[num])
2213 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2214 return prog->knownstrings[num];
2218 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2224 int PRVM_SetEngineString(const char *s)
2229 if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2230 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2231 // if it's in the tempstrings area, use a reserved range
2232 // (otherwise we'd get millions of useless string offsets cluttering the database)
2233 if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2235 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2237 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2239 // see if it's a known string address
2240 for (i = 0;i < prog->numknownstrings;i++)
2241 if (prog->knownstrings[i] == s)
2243 // new unknown engine string
2244 if (developer.integer >= 200)
2245 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2246 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2247 if (!prog->knownstrings[i])
2249 if (i >= prog->numknownstrings)
2251 if (i >= prog->maxknownstrings)
2253 const char **oldstrings = prog->knownstrings;
2254 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2255 prog->maxknownstrings += 128;
2256 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2257 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2258 if (prog->numknownstrings)
2260 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2261 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2264 prog->numknownstrings++;
2266 prog->firstfreeknownstring = i + 1;
2267 prog->knownstrings[i] = s;
2271 // temp string handling
2273 // all tempstrings go into this buffer consecutively, and it is reset
2274 // whenever PRVM_ExecuteProgram returns to the engine
2275 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2276 // restores it on return, so multiple recursive calls can share the same
2278 // the buffer size is automatically grown as needed
2280 int PRVM_SetTempString(const char *s)
2286 size = (int)strlen(s) + 1;
2287 if (developer.integer >= 300)
2288 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2289 if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2291 sizebuf_t old = vm_tempstringsbuf;
2292 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2293 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);
2294 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2295 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2296 vm_tempstringsbuf.maxsize *= 2;
2297 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2299 if (developer.integer >= 100)
2300 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2301 vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2303 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2308 t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2310 vm_tempstringsbuf.cursize += size;
2311 return PRVM_SetEngineString(t);
2314 int PRVM_AllocString(size_t bufferlength, char **pointer)
2319 for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2320 if (!prog->knownstrings[i])
2322 if (i >= prog->numknownstrings)
2324 if (i >= prog->maxknownstrings)
2326 const char **oldstrings = prog->knownstrings;
2327 const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2328 prog->maxknownstrings += 128;
2329 prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2330 prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2331 if (prog->numknownstrings)
2333 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2334 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2337 prog->numknownstrings++;
2339 prog->firstfreeknownstring = i + 1;
2340 prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2341 prog->knownstrings_freeable[i] = true;
2343 *pointer = (char *)(prog->knownstrings[i]);
2347 void PRVM_FreeString(int num)
2350 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2351 else if (num >= 0 && num < prog->stringssize)
2352 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2353 else if (num < 0 && num >= -prog->numknownstrings)
2356 if (!prog->knownstrings[num])
2357 PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2358 if (!prog->knownstrings[num])
2359 PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2360 PRVM_Free((char *)prog->knownstrings[num]);
2361 prog->knownstrings[num] = NULL;
2362 prog->knownstrings_freeable[num] = false;
2363 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2366 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);