]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
fix two warnings
[divverent/darkplaces.git] / prvm_edict.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // AK new vm
21
22 #include "quakedef.h"
23 #include "progsvm.h"
24
25 prvm_prog_t *prog;
26
27 static prvm_prog_t prog_list[PRVM_MAXPROGS];
28
29 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
30
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);
33
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)"};
37 #endif
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"};
43
44 extern sizebuf_t vm_tempstringsbuf;
45
46 //============================================================================
47 // mempool handling
48
49 /*
50 ===============
51 PRVM_MEM_Alloc
52 ===============
53 */
54 void PRVM_MEM_Alloc(void)
55 {
56         int i;
57
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);
62
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));
65
66         // alloc edicts
67         prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
68
69         // alloc edict private space
70         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
71
72         // alloc edict fields
73         prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
74
75         // set edict pointers
76         for(i = 0; i < prog->max_edicts; i++)
77         {
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);
80         }
81 }
82
83 /*
84 ===============
85 PRVM_MEM_IncreaseEdicts
86 ===============
87 */
88 void PRVM_MEM_IncreaseEdicts(void)
89 {
90         int             i;
91         int             oldmaxedicts = prog->max_edicts;
92         void    *oldedictsfields = prog->edictsfields;
93         void    *oldedictprivate = prog->edictprivate;
94
95         if(prog->max_edicts >= prog->limit_edicts)
96                 return;
97
98         PRVM_GCALL(begin_increase_edicts)();
99
100         // increase edicts
101         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
102
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);
105
106         memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
107         memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
108
109         //set e and v pointers
110         for(i = 0; i < prog->max_edicts; i++)
111         {
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);
114         }
115
116         PRVM_GCALL(end_increase_edicts)();
117
118         Mem_Free(oldedictsfields);
119         Mem_Free(oldedictprivate);
120 }
121
122 //============================================================================
123 // normal prvm
124
125 int PRVM_ED_FindFieldOffset(const char *field)
126 {
127         ddef_t *d;
128         d = PRVM_ED_FindField(field);
129         if (!d)
130                 return -1;
131         return d->ofs;
132 }
133
134 int PRVM_ED_FindGlobalOffset(const char *global)
135 {
136         ddef_t *d;
137         d = PRVM_ED_FindGlobal(global);
138         if (!d)
139                 return -1;
140         return d->ofs;
141 }
142
143 func_t PRVM_ED_FindFunctionOffset(const char *function)
144 {
145         mfunction_t *f;
146         f = PRVM_ED_FindFunction(function);
147         if (!f)
148                 return 0;
149         return (func_t)(f - prog->functions);
150 }
151
152 qboolean PRVM_ProgLoaded(int prognr)
153 {
154         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
155                 return FALSE;
156
157         return (prog_list[prognr].loaded ? TRUE : FALSE);
158 }
159
160 /*
161 =================
162 PRVM_SetProgFromString
163 =================
164 */
165 // perhaps add a return value when the str doesnt exist
166 qboolean PRVM_SetProgFromString(const char *str)
167 {
168         int i = 0;
169         for(; i < PRVM_MAXPROGS ; i++)
170                 if(prog_list[i].name && !strcmp(prog_list[i].name,str))
171                 {
172                         if(prog_list[i].loaded)
173                         {
174                                 prog = &prog_list[i];
175                                 return TRUE;
176                         }
177                         else
178                         {
179                                 Con_Printf("%s not loaded !\n",PRVM_NAME);
180                                 return FALSE;
181                         }
182                 }
183
184         Con_Printf("Invalid program name %s !\n", str);
185         return FALSE;
186 }
187
188 /*
189 =================
190 PRVM_SetProg
191 =================
192 */
193 void PRVM_SetProg(int prognr)
194 {
195         if(0 <= prognr && prognr < PRVM_MAXPROGS)
196         {
197                 if(prog_list[prognr].loaded)
198                         prog = &prog_list[prognr];
199                 else
200                         PRVM_ERROR("%i not loaded !", prognr);
201                 return;
202         }
203         PRVM_ERROR("Invalid program number %i", prognr);
204 }
205
206 /*
207 =================
208 PRVM_ED_ClearEdict
209
210 Sets everything to NULL
211 =================
212 */
213 void PRVM_ED_ClearEdict (prvm_edict_t *e)
214 {
215         memset (e->fields.vp, 0, prog->progs->entityfields * 4);
216         e->priv.required->free = false;
217
218         // AK: Let the init_edict function determine if something needs to be initialized
219         PRVM_GCALL(init_edict)(e);
220 }
221
222 /*
223 =================
224 PRVM_ED_Alloc
225
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.
231 =================
232 */
233 prvm_edict_t *PRVM_ED_Alloc (void)
234 {
235         int                     i;
236         prvm_edict_t            *e;
237
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++)
244         {
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 ) )
249                 {
250                         PRVM_ED_ClearEdict (e);
251                         return e;
252                 }
253         }
254
255         if (i == prog->limit_edicts)
256                 PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME);
257
258         prog->num_edicts++;
259         if (prog->num_edicts >= prog->max_edicts)
260                 PRVM_MEM_IncreaseEdicts();
261
262         e = PRVM_EDICT_NUM(i);
263         PRVM_ED_ClearEdict (e);
264
265         return e;
266 }
267
268 /*
269 =================
270 PRVM_ED_Free
271
272 Marks the edict as free
273 FIXME: walk all entities and NULL out references to this entity
274 =================
275 */
276 void PRVM_ED_Free (prvm_edict_t *ed)
277 {
278         // dont delete the null entity (world) or reserved edicts
279         if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
280                 return;
281
282         PRVM_GCALL(free_edict)(ed);
283
284         ed->priv.required->free = true;
285         ed->priv.required->freetime = prog->globaloffsets.time >= 0 ? PRVM_GLOBALFIELDVALUE(prog->globaloffsets.time)->_float : 0;
286 }
287
288 //===========================================================================
289
290 /*
291 ============
292 PRVM_ED_GlobalAtOfs
293 ============
294 */
295 ddef_t *PRVM_ED_GlobalAtOfs (int ofs)
296 {
297         ddef_t          *def;
298         int                     i;
299
300         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
301         {
302                 def = &prog->globaldefs[i];
303                 if (def->ofs == ofs)
304                         return def;
305         }
306         return NULL;
307 }
308
309 /*
310 ============
311 PRVM_ED_FieldAtOfs
312 ============
313 */
314 ddef_t *PRVM_ED_FieldAtOfs (int ofs)
315 {
316         ddef_t          *def;
317         int                     i;
318
319         for (i=0 ; i<prog->progs->numfielddefs ; i++)
320         {
321                 def = &prog->fielddefs[i];
322                 if (def->ofs == ofs)
323                         return def;
324         }
325         return NULL;
326 }
327
328 /*
329 ============
330 PRVM_ED_FindField
331 ============
332 */
333 ddef_t *PRVM_ED_FindField (const char *name)
334 {
335         ddef_t *def;
336         int i;
337
338         for (i=0 ; i<prog->progs->numfielddefs ; i++)
339         {
340                 def = &prog->fielddefs[i];
341                 if (!strcmp(PRVM_GetString(def->s_name), name))
342                         return def;
343         }
344         return NULL;
345 }
346
347 /*
348 ============
349 PRVM_ED_FindGlobal
350 ============
351 */
352 ddef_t *PRVM_ED_FindGlobal (const char *name)
353 {
354         ddef_t *def;
355         int i;
356
357         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
358         {
359                 def = &prog->globaldefs[i];
360                 if (!strcmp(PRVM_GetString(def->s_name), name))
361                         return def;
362         }
363         return NULL;
364 }
365
366
367 /*
368 ============
369 PRVM_ED_FindFunction
370 ============
371 */
372 mfunction_t *PRVM_ED_FindFunction (const char *name)
373 {
374         mfunction_t             *func;
375         int                             i;
376
377         for (i=0 ; i<prog->progs->numfunctions ; i++)
378         {
379                 func = &prog->functions[i];
380                 if (!strcmp(PRVM_GetString(func->s_name), name))
381                         return func;
382         }
383         return NULL;
384 }
385
386
387 /*
388 ============
389 PRVM_ValueString
390
391 Returns a string describing *data in a type specific manner
392 =============
393 */
394 char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
395 {
396         static char line[MAX_INPUTLINE];
397         ddef_t *def;
398         mfunction_t *f;
399         int n;
400
401         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
402
403         switch (type)
404         {
405         case ev_string:
406                 strlcpy (line, PRVM_GetString (val->string), sizeof (line));
407                 break;
408         case ev_entity:
409                 n = val->edict;
410                 if (n < 0 || n >= prog->limit_edicts)
411                         dpsnprintf (line, sizeof(line), "entity %i (invalid!)", n);
412                 else
413                         dpsnprintf (line, sizeof(line), "entity %i", n);
414                 break;
415         case ev_function:
416                 f = prog->functions + val->function;
417                 dpsnprintf (line, sizeof(line), "%s()", PRVM_GetString(f->s_name));
418                 break;
419         case ev_field:
420                 def = PRVM_ED_FieldAtOfs ( val->_int );
421                 dpsnprintf (line, sizeof(line), ".%s", PRVM_GetString(def->s_name));
422                 break;
423         case ev_void:
424                 dpsnprintf (line, sizeof(line), "void");
425                 break;
426         case ev_float:
427                 // LordHavoc: changed from %5.1f to %10.4f
428                 dpsnprintf (line, sizeof(line), "%10.4f", val->_float);
429                 break;
430         case ev_vector:
431                 // LordHavoc: changed from %5.1f to %10.4f
432                 dpsnprintf (line, sizeof(line), "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]);
433                 break;
434         case ev_pointer:
435                 dpsnprintf (line, sizeof(line), "pointer");
436                 break;
437         default:
438                 dpsnprintf (line, sizeof(line), "bad type %i", (int) type);
439                 break;
440         }
441
442         return line;
443 }
444
445 /*
446 ============
447 PRVM_UglyValueString
448
449 Returns a string describing *data in a type specific manner
450 Easier to parse than PR_ValueString
451 =============
452 */
453 char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
454 {
455         static char line[MAX_INPUTLINE];
456         int i;
457         const char *s;
458         ddef_t *def;
459         mfunction_t *f;
460
461         type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
462
463         switch (type)
464         {
465         case ev_string:
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;)
471                 {
472                         if (*s == '\n')
473                         {
474                                 line[i++] = '\\';
475                                 line[i++] = 'n';
476                         }
477                         else if (*s == '\r')
478                         {
479                                 line[i++] = '\\';
480                                 line[i++] = 'r';
481                         }
482                         else if (*s == '\\')
483                         {
484                                 line[i++] = '\\';
485                                 line[i++] = '\\';
486                         }
487                         else
488                                 line[i++] = *s;
489                         s++;
490                 }
491                 line[i] = '\0';
492                 break;
493         case ev_entity:
494                 dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
495                 break;
496         case ev_function:
497                 f = prog->functions + val->function;
498                 strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
499                 break;
500         case ev_field:
501                 def = PRVM_ED_FieldAtOfs ( val->_int );
502                 dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
503                 break;
504         case ev_void:
505                 dpsnprintf (line, sizeof (line), "void");
506                 break;
507         case ev_float:
508                 dpsnprintf (line, sizeof (line), "%f", val->_float);
509                 break;
510         case ev_vector:
511                 dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
512                 break;
513         default:
514                 dpsnprintf (line, sizeof (line), "bad type %i", type);
515                 break;
516         }
517
518         return line;
519 }
520
521 /*
522 ============
523 PRVM_GlobalString
524
525 Returns a string with a description and the contents of a global,
526 padded to 20 field width
527 ============
528 */
529 char *PRVM_GlobalString (int ofs)
530 {
531         char    *s;
532         //size_t        i;
533         ddef_t  *def;
534         void    *val;
535         static char     line[128];
536
537         val = (void *)&prog->globals.generic[ofs];
538         def = PRVM_ED_GlobalAtOfs(ofs);
539         if (!def)
540                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
541         else
542         {
543                 s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val);
544                 dpsnprintf (line, sizeof(line), "%s (=%s)", PRVM_GetString(def->s_name), s);
545         }
546
547         //i = strlen(line);
548         //for ( ; i<20 ; i++)
549         //      strcat (line," ");
550         //strcat (line," ");
551
552         return line;
553 }
554
555 char *PRVM_GlobalStringNoContents (int ofs)
556 {
557         //size_t        i;
558         ddef_t  *def;
559         static char     line[128];
560
561         def = PRVM_ED_GlobalAtOfs(ofs);
562         if (!def)
563                 dpsnprintf (line, sizeof(line), "GLOBAL%i", ofs);
564         else
565                 dpsnprintf (line, sizeof(line), "%s", PRVM_GetString(def->s_name));
566
567         //i = strlen(line);
568         //for ( ; i<20 ; i++)
569         //      strcat (line," ");
570         //strcat (line," ");
571
572         return line;
573 }
574
575
576 /*
577 =============
578 PRVM_ED_Print
579
580 For debugging
581 =============
582 */
583 // LordHavoc: optimized this to print out much more quickly (tempstring)
584 // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
585 void PRVM_ED_Print(prvm_edict_t *ed, const char *wildcard_fieldname)
586 {
587         size_t  l;
588         ddef_t  *d;
589         int             *v;
590         int             i, j;
591         const char      *name;
592         int             type;
593         char    tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
594
595         if (ed->priv.required->free)
596         {
597                 Con_Printf("%s: FREE\n",PRVM_NAME);
598                 return;
599         }
600
601         tempstring[0] = 0;
602         dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed));
603         for (i=1 ; i<prog->progs->numfielddefs ; i++)
604         {
605                 d = &prog->fielddefs[i];
606                 name = PRVM_GetString(d->s_name);
607                 if (name[strlen(name)-2] == '_')
608                         continue;       // skip _x, _y, _z vars
609
610                 // Check Field Name Wildcard
611                 if(wildcard_fieldname)
612                         if( !matchpattern(name, wildcard_fieldname, 1) )
613                                 // Didn't match; skip
614                                 continue;
615
616                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
617
618         // if the value is still all 0, skip the field
619                 type = d->type & ~DEF_SAVEGLOBAL;
620
621                 for (j=0 ; j<prvm_type_size[type] ; j++)
622                         if (v[j])
623                                 break;
624                 if (j == prvm_type_size[type])
625                         continue;
626
627                 if (strlen(name) > sizeof(tempstring2)-4)
628                 {
629                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
630                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
631                         tempstring2[sizeof(tempstring2)-1] = 0;
632                         name = tempstring2;
633                 }
634                 strlcat(tempstring, name, sizeof(tempstring));
635                 for (l = strlen(name);l < 14;l++)
636                         strlcat(tempstring, " ", sizeof(tempstring));
637                 strlcat(tempstring, " ", sizeof(tempstring));
638
639                 name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v);
640                 if (strlen(name) > sizeof(tempstring2)-4)
641                 {
642                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
643                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
644                         tempstring2[sizeof(tempstring2)-1] = 0;
645                         name = tempstring2;
646                 }
647                 strlcat(tempstring, name, sizeof(tempstring));
648                 strlcat(tempstring, "\n", sizeof(tempstring));
649                 if (strlen(tempstring) >= sizeof(tempstring)/2)
650                 {
651                         Con_Print(tempstring);
652                         tempstring[0] = 0;
653                 }
654         }
655         if (tempstring[0])
656                 Con_Print(tempstring);
657 }
658
659 /*
660 =============
661 PRVM_ED_Write
662
663 For savegames
664 =============
665 */
666 void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
667 {
668         ddef_t  *d;
669         int             *v;
670         int             i, j;
671         const char      *name;
672         int             type;
673
674         FS_Print(f, "{\n");
675
676         if (ed->priv.required->free)
677         {
678                 FS_Print(f, "}\n");
679                 return;
680         }
681
682         for (i=1 ; i<prog->progs->numfielddefs ; i++)
683         {
684                 d = &prog->fielddefs[i];
685                 name = PRVM_GetString(d->s_name);
686                 if (name[strlen(name)-2] == '_')
687                         continue;       // skip _x, _y, _z vars
688
689                 v = (int *)((char *)ed->fields.vp + d->ofs*4);
690
691         // if the value is still all 0, skip the field
692                 type = d->type & ~DEF_SAVEGLOBAL;
693                 for (j=0 ; j<prvm_type_size[type] ; j++)
694                         if (v[j])
695                                 break;
696                 if (j == prvm_type_size[type])
697                         continue;
698
699                 FS_Printf(f,"\"%s\" ",name);
700                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)d->type, (prvm_eval_t *)v));
701         }
702
703         FS_Print(f, "}\n");
704 }
705
706 void PRVM_ED_PrintNum (int ent, const char *wildcard_fieldname)
707 {
708         PRVM_ED_Print(PRVM_EDICT_NUM(ent), wildcard_fieldname);
709 }
710
711 /*
712 =============
713 PRVM_ED_PrintEdicts_f
714
715 For debugging, prints all the entities in the current server
716 =============
717 */
718 void PRVM_ED_PrintEdicts_f (void)
719 {
720         int             i;
721         const char *wildcard_fieldname;
722
723         if(Cmd_Argc() < 2 || Cmd_Argc() > 3)
724         {
725                 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
726                 return;
727         }
728
729         PRVM_Begin;
730         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
731                 return;
732
733         if( Cmd_Argc() == 3)
734                 wildcard_fieldname = Cmd_Argv(2);
735         else
736                 wildcard_fieldname = NULL;
737
738         Con_Printf("%s: %i entities\n", PRVM_NAME, prog->num_edicts);
739         for (i=0 ; i<prog->num_edicts ; i++)
740                 PRVM_ED_PrintNum (i, wildcard_fieldname);
741
742         PRVM_End;
743 }
744
745 /*
746 =============
747 PRVM_ED_PrintEdict_f
748
749 For debugging, prints a single edict
750 =============
751 */
752 void PRVM_ED_PrintEdict_f (void)
753 {
754         int             i;
755         const char      *wildcard_fieldname;
756
757         if(Cmd_Argc() < 3 || Cmd_Argc() > 4)
758         {
759                 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
760                 return;
761         }
762
763         PRVM_Begin;
764         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
765                 return;
766
767         i = atoi (Cmd_Argv(2));
768         if (i >= prog->num_edicts)
769         {
770                 Con_Print("Bad edict number\n");
771                 PRVM_End;
772                 return;
773         }
774         if( Cmd_Argc() == 4)
775                 // Optional Wildcard Provided
776                 wildcard_fieldname = Cmd_Argv(3);
777         else
778                 // Use All
779                 wildcard_fieldname = NULL;
780         PRVM_ED_PrintNum (i, wildcard_fieldname);
781
782         PRVM_End;
783 }
784
785 /*
786 =============
787 PRVM_ED_Count
788
789 For debugging
790 =============
791 */
792 // 2 possibilities : 1. just displaying the active edict count
793 //                                       2. making a function pointer [x]
794 void PRVM_ED_Count_f (void)
795 {
796         int             i;
797         prvm_edict_t    *ent;
798         int             active;
799
800         if(Cmd_Argc() != 2)
801         {
802                 Con_Print("prvm_count <program name>\n");
803                 return;
804         }
805
806         PRVM_Begin;
807         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
808                 return;
809
810         if(prog->count_edicts)
811                 prog->count_edicts();
812         else
813         {
814                 active = 0;
815                 for (i=0 ; i<prog->num_edicts ; i++)
816                 {
817                         ent = PRVM_EDICT_NUM(i);
818                         if (ent->priv.required->free)
819                                 continue;
820                         active++;
821                 }
822
823                 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
824                 Con_Printf("active    :%3i\n", active);
825         }
826
827         PRVM_End;
828 }
829
830 /*
831 ==============================================================================
832
833                                         ARCHIVING GLOBALS
834
835 FIXME: need to tag constants, doesn't really work
836 ==============================================================================
837 */
838
839 /*
840 =============
841 PRVM_ED_WriteGlobals
842 =============
843 */
844 void PRVM_ED_WriteGlobals (qfile_t *f)
845 {
846         ddef_t          *def;
847         int                     i;
848         const char              *name;
849         int                     type;
850
851         FS_Print(f,"{\n");
852         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
853         {
854                 def = &prog->globaldefs[i];
855                 type = def->type;
856                 if ( !(def->type & DEF_SAVEGLOBAL) )
857                         continue;
858                 type &= ~DEF_SAVEGLOBAL;
859
860                 if (type != ev_string && type != ev_float && type != ev_entity)
861                         continue;
862
863                 name = PRVM_GetString(def->s_name);
864                 FS_Printf(f,"\"%s\" ", name);
865                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs]));
866         }
867         FS_Print(f,"}\n");
868 }
869
870 /*
871 =============
872 PRVM_ED_ParseGlobals
873 =============
874 */
875 void PRVM_ED_ParseGlobals (const char *data)
876 {
877         char keyname[MAX_INPUTLINE];
878         ddef_t *key;
879
880         while (1)
881         {
882                 // parse key
883                 if (!COM_ParseToken_Simple(&data, false, false))
884                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
885                 if (com_token[0] == '}')
886                         break;
887
888                 strlcpy (keyname, com_token, sizeof(keyname));
889
890                 // parse value
891                 if (!COM_ParseToken_Simple(&data, false, true))
892                         PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace");
893
894                 if (com_token[0] == '}')
895                         PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data");
896
897                 key = PRVM_ED_FindGlobal (keyname);
898                 if (!key)
899                 {
900                         Con_DPrintf("'%s' is not a global on %s\n", keyname, PRVM_NAME);
901                         continue;
902                 }
903
904                 if (!PRVM_ED_ParseEpair(NULL, key, com_token, true))
905                         PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error");
906         }
907 }
908
909 //============================================================================
910
911
912 /*
913 =============
914 PRVM_ED_ParseEval
915
916 Can parse either fields or globals
917 returns false if error
918 =============
919 */
920 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
921 {
922         int i, l;
923         char *new_p;
924         ddef_t *def;
925         prvm_eval_t *val;
926         mfunction_t *func;
927
928         if (ent)
929                 val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
930         else
931                 val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs);
932         switch (key->type & ~DEF_SAVEGLOBAL)
933         {
934         case ev_string:
935                 l = (int)strlen(s) + 1;
936                 val->string = PRVM_AllocString(l, &new_p);
937                 for (i = 0;i < l;i++)
938                 {
939                         if (s[i] == '\\' && s[i+1] && parsebackslash)
940                         {
941                                 i++;
942                                 if (s[i] == 'n')
943                                         *new_p++ = '\n';
944                                 else if (s[i] == 'r')
945                                         *new_p++ = '\r';
946                                 else
947                                         *new_p++ = s[i];
948                         }
949                         else
950                                 *new_p++ = s[i];
951                 }
952                 break;
953
954         case ev_float:
955                 while (*s && *s <= ' ')
956                         s++;
957                 val->_float = atof(s);
958                 break;
959
960         case ev_vector:
961                 for (i = 0;i < 3;i++)
962                 {
963                         while (*s && *s <= ' ')
964                                 s++;
965                         if (!*s)
966                                 break;
967                         val->vector[i] = atof(s);
968                         while (*s > ' ')
969                                 s++;
970                         if (!*s)
971                                 break;
972                 }
973                 break;
974
975         case ev_entity:
976                 while (*s && *s <= ' ')
977                         s++;
978                 i = atoi(s);
979                 if (i >= prog->limit_edicts)
980                         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);
981                 while (i >= prog->max_edicts)
982                         PRVM_MEM_IncreaseEdicts();
983                 // if IncreaseEdicts was called the base pointer needs to be updated
984                 if (ent)
985                         val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
986                 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
987                 break;
988
989         case ev_field:
990                 if (*s != '.')
991                 {
992                         Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, PRVM_NAME);
993                         return false;
994                 }
995                 def = PRVM_ED_FindField(s + 1);
996                 if (!def)
997                 {
998                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
999                         return false;
1000                 }
1001                 val->_int = def->ofs;
1002                 break;
1003
1004         case ev_function:
1005                 func = PRVM_ED_FindFunction(s);
1006                 if (!func)
1007                 {
1008                         Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME);
1009                         return false;
1010                 }
1011                 val->function = func - prog->functions;
1012                 break;
1013
1014         default:
1015                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME);
1016                 return false;
1017         }
1018         return true;
1019 }
1020
1021 /*
1022 =============
1023 PRVM_GameCommand_f
1024
1025 Console command to send a string to QC function GameCommand of the
1026 indicated progs
1027
1028 Usage:
1029   sv_cmd adminmsg 3 "do not teamkill"
1030   cl_cmd someclientcommand
1031   menu_cmd somemenucommand
1032
1033 All progs can support this extension; sg calls it in server QC, cg in client
1034 QC, mg in menu QC.
1035 =============
1036 */
1037 void PRVM_GameCommand(const char *whichprogs, const char *whichcmd)
1038 {
1039         if(Cmd_Argc() < 1)
1040         {
1041                 Con_Printf("%s text...\n", whichcmd);
1042                 return;
1043         }
1044
1045         PRVM_Begin;
1046         if(!PRVM_SetProgFromString(whichprogs))
1047         // note: this is not PRVM_SetProg because that one aborts "hard" using PRVM_Error
1048         // also, it makes printing error messages easier!
1049         {
1050                 Con_Printf("%s program not loaded.\n", whichprogs);
1051                 return;
1052         }
1053
1054         if(!prog->funcoffsets.GameCommand)
1055         {
1056                 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1057         }
1058         else
1059         {
1060                 int restorevm_tempstringsbuf_cursize;
1061                 const char *s;
1062
1063                 s = Cmd_Args();
1064
1065                 restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1066                 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s ? s : "");
1067                 PRVM_ExecuteProgram (prog->funcoffsets.GameCommand, "QC function GameCommand is missing");
1068                 vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1069         }
1070
1071         PRVM_End;
1072 }
1073 void PRVM_GameCommand_Server_f(void)
1074 {
1075         PRVM_GameCommand("server", "sv_cmd");
1076 }
1077 void PRVM_GameCommand_Client_f(void)
1078 {
1079         PRVM_GameCommand("client", "cl_cmd");
1080 }
1081 void PRVM_GameCommand_Menu_f(void)
1082 {
1083         PRVM_GameCommand("menu", "menu_cmd");
1084 }
1085
1086 /*
1087 =============
1088 PRVM_ED_EdictSet_f
1089
1090 Console command to set a field of a specified edict
1091 =============
1092 */
1093 void PRVM_ED_EdictSet_f(void)
1094 {
1095         prvm_edict_t *ed;
1096         ddef_t *key;
1097
1098         if(Cmd_Argc() != 5)
1099         {
1100                 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1101                 return;
1102         }
1103
1104         PRVM_Begin;
1105         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1106         {
1107                 Con_Printf("Wrong program name %s !\n", Cmd_Argv(1));
1108                 return;
1109         }
1110
1111         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
1112
1113         if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
1114                 Con_Printf("Key %s not found !\n", Cmd_Argv(3));
1115         else
1116                 PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4), true);
1117
1118         PRVM_End;
1119 }
1120
1121 /*
1122 ====================
1123 PRVM_ED_ParseEdict
1124
1125 Parses an edict out of the given string, returning the new position
1126 ed should be a properly initialized empty edict.
1127 Used for initial level load and for savegames.
1128 ====================
1129 */
1130 extern cvar_t developer_entityparsing;
1131 const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
1132 {
1133         ddef_t *key;
1134         qboolean anglehack;
1135         qboolean init;
1136         char keyname[256];
1137         size_t n;
1138
1139         init = false;
1140
1141 // go through all the dictionary pairs
1142         while (1)
1143         {
1144         // parse key
1145                 if (!COM_ParseToken_Simple(&data, false, false))
1146                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1147                 if (developer_entityparsing.integer)
1148                         Con_Printf("Key: \"%s\"", com_token);
1149                 if (com_token[0] == '}')
1150                         break;
1151
1152                 // anglehack is to allow QuakeEd to write single scalar angles
1153                 // and allow them to be turned into vectors. (FIXME...)
1154                 if (!strcmp(com_token, "angle"))
1155                 {
1156                         strlcpy (com_token, "angles", sizeof(com_token));
1157                         anglehack = true;
1158                 }
1159                 else
1160                         anglehack = false;
1161
1162                 // FIXME: change light to _light to get rid of this hack
1163                 if (!strcmp(com_token, "light"))
1164                         strlcpy (com_token, "light_lev", sizeof(com_token));    // hack for single light def
1165
1166                 strlcpy (keyname, com_token, sizeof(keyname));
1167
1168                 // another hack to fix keynames with trailing spaces
1169                 n = strlen(keyname);
1170                 while (n && keyname[n-1] == ' ')
1171                 {
1172                         keyname[n-1] = 0;
1173                         n--;
1174                 }
1175
1176         // parse value
1177                 if (!COM_ParseToken_Simple(&data, false, false))
1178                         PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace");
1179                 if (developer_entityparsing.integer)
1180                         Con_Printf(" \"%s\"\n", com_token);
1181
1182                 if (com_token[0] == '}')
1183                         PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data");
1184
1185                 init = true;
1186
1187                 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1188                 if (!keyname[0])
1189                         continue;
1190
1191 // keynames with a leading underscore are used for utility comments,
1192 // and are immediately discarded by quake
1193                 if (keyname[0] == '_')
1194                         continue;
1195
1196                 key = PRVM_ED_FindField (keyname);
1197                 if (!key)
1198                 {
1199                         Con_DPrintf("%s: '%s' is not a field\n", PRVM_NAME, keyname);
1200                         continue;
1201                 }
1202
1203                 if (anglehack)
1204                 {
1205                         char    temp[32];
1206                         strlcpy (temp, com_token, sizeof(temp));
1207                         dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
1208                 }
1209
1210                 if (!PRVM_ED_ParseEpair(ent, key, com_token, strcmp(keyname, "wad") != 0))
1211                         PRVM_ERROR ("PRVM_ED_ParseEdict: parse error");
1212         }
1213
1214         if (!init)
1215                 ent->priv.required->free = true;
1216
1217         return data;
1218 }
1219
1220
1221 /*
1222 ================
1223 PRVM_ED_LoadFromFile
1224
1225 The entities are directly placed in the array, rather than allocated with
1226 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1227 number references out of order.
1228
1229 Creates a server's entity / program execution context by
1230 parsing textual entity definitions out of an ent file.
1231
1232 Used for both fresh maps and savegame loads.  A fresh map would also need
1233 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1234 ================
1235 */
1236 void PRVM_ED_LoadFromFile (const char *data)
1237 {
1238         prvm_edict_t *ent;
1239         int parsed, inhibited, spawned, died;
1240         const char *funcname;
1241         mfunction_t *func;
1242
1243         parsed = 0;
1244         inhibited = 0;
1245         spawned = 0;
1246         died = 0;
1247
1248
1249 // parse ents
1250         while (1)
1251         {
1252 // parse the opening brace
1253                 if (!COM_ParseToken_Simple(&data, false, false))
1254                         break;
1255                 if (com_token[0] != '{')
1256                         PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
1257
1258                 // CHANGED: this is not conform to PR_LoadFromFile
1259                 if(prog->loadintoworld)
1260                 {
1261                         prog->loadintoworld = false;
1262                         ent = PRVM_EDICT_NUM(0);
1263                 }
1264                 else
1265                         ent = PRVM_ED_Alloc();
1266
1267                 // clear it
1268                 if (ent != prog->edicts)        // hack
1269                         memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
1270
1271                 data = PRVM_ED_ParseEdict (data, ent);
1272                 parsed++;
1273
1274                 // remove the entity ?
1275                 if(prog->load_edict && !prog->load_edict(ent))
1276                 {
1277                         PRVM_ED_Free(ent);
1278                         inhibited++;
1279                         continue;
1280                 }
1281
1282 //
1283 // immediately call spawn function, but only if there is a self global and a classname
1284 //
1285                 if(prog->globaloffsets.self >= 0 && prog->fieldoffsets.classname >= 0)
1286                 {
1287                         string_t handle =  PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.classname)->string;
1288                         if (!handle)
1289                         {
1290                                 Con_Print("No classname for:\n");
1291                                 PRVM_ED_Print(ent, NULL);
1292                                 PRVM_ED_Free (ent);
1293                                 continue;
1294                         }
1295
1296                         // look for the spawn function
1297                         funcname = PRVM_GetString(handle);
1298                         func = PRVM_ED_FindFunction (va("spawnfunc_%s", funcname));
1299                         if(!func)
1300                                 if(prog->globaloffsets.require_spawnfunc_prefix < 0)
1301                                         func = PRVM_ED_FindFunction (funcname);
1302
1303                         if (!func)
1304                         {
1305                                 // check for OnEntityNoSpawnFunction
1306                                 if (prog->funcoffsets.SV_OnEntityNoSpawnFunction)
1307                                 {
1308                                         // self = ent
1309                                         PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1310                                         PRVM_ExecuteProgram (prog->funcoffsets.SV_OnEntityNoSpawnFunction, "QC function SV_OnEntityNoSpawnFunction is missing");
1311                                 }
1312                                 else
1313                                 {
1314                                         if (developer.integer) // don't confuse non-developers with errors
1315                                         {
1316                                                 Con_Print("No spawn function for:\n");
1317                                                 PRVM_ED_Print(ent, NULL);
1318                                         }
1319                                         PRVM_ED_Free (ent);
1320                                         continue;
1321                                 }
1322                         }
1323                         else
1324                         {
1325                                 // self = ent
1326                                 PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict = PRVM_EDICT_TO_PROG(ent);
1327                                 PRVM_ExecuteProgram (func - prog->functions, "");
1328                         }
1329                 }
1330
1331                 spawned++;
1332                 if (ent->priv.required->free)
1333                         died++;
1334         }
1335
1336         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);
1337 }
1338
1339 void PRVM_FindOffsets(void)
1340 {
1341         // field and global searches use -1 for NULL
1342         memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1343         memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1344         // functions use 0 for NULL
1345         memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1346
1347         // server and client qc use a lot of similar fields, so this is combined
1348         prog->fieldoffsets.SendEntity                     = PRVM_ED_FindFieldOffset("SendEntity");
1349         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1350         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1351         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1352         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1353         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1354         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1355         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1356         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1357         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1358         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1359         prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
1360         prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
1361         prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
1362         prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
1363         prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
1364         prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
1365         prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
1366         prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
1367         prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
1368         prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
1369         prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
1370         prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
1371         prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
1372         prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
1373         prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1374         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1375         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1376         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1377         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1378         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1379         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1380         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1381         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1382         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1383         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1384         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1385         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1386         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1387         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1388         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1389         prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
1390         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1391         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1392         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1393         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1394         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1395         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1396         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1397         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1398         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1399         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1400         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1401         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1402         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1403         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1404         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1405         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1406         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1407         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1408         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1409         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1410         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1411         prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
1412         prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
1413         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1414         prog->fieldoffsets.movetypesteplandevent          = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1415         prog->fieldoffsets.netaddress                     = PRVM_ED_FindFieldOffset("netaddress");
1416         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1417         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1418         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1419         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1420         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1421         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1422         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1423         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1424         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1425         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1426         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1427         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1428         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1429         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1430         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1431         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1432         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1433         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1434         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1435         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1436         prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
1437         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1438         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1439         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1440         prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1441         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1442         prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1443         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1444         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1445         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1446         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1447         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1448         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1449         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1450         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1451         prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
1452         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1453         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1454         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1455         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1456         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1457         prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1458         prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
1459         prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1460         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1461         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1462         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1463         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1464         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1465         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1466         prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
1467         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1468         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1469         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1470         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1471         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1472         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1473         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1474         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1475         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1476         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1477         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1478         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1479         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1480         prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
1481         prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
1482         prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
1483         prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
1484         prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
1485         prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
1486         prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
1487         prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
1488         prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1489
1490         // menu qc only uses some functions, nothing else
1491         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1492         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1493         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1494         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1495         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1496         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1497 }
1498
1499 // not used
1500 /*
1501 typedef struct dpfield_s
1502 {
1503         int type;
1504         char *string;
1505 }
1506 dpfield_t;
1507
1508 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1509
1510 dpfield_t dpfields[] =
1511 {
1512 };
1513 */
1514
1515 /*
1516 ===============
1517 PRVM_ResetProg
1518 ===============
1519 */
1520
1521 void PRVM_ResetProg()
1522 {
1523         PRVM_GCALL(reset_cmd)();
1524         Mem_FreePool(&prog->progs_mempool);
1525         memset(prog,0,sizeof(prvm_prog_t));
1526         prog->starttime = Sys_DoubleTime();
1527 }
1528
1529 /*
1530 ===============
1531 PRVM_LoadLNO
1532 ===============
1533 */
1534 void PRVM_LoadLNO( const char *progname ) {
1535         fs_offset_t filesize;
1536         unsigned char *lno;
1537         unsigned int *header;
1538         char filename[512];
1539
1540         FS_StripExtension( progname, filename, sizeof( filename ) );
1541         strlcat( filename, ".lno", sizeof( filename ) );
1542
1543         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1544         if( !lno ) {
1545                 return;
1546         }
1547
1548 /*
1549 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1550 <Spike>    SafeWrite (h, &version, sizeof(int));
1551 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1552 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1553 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1554 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1555 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1556 */
1557         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1558                 Mem_Free(lno);
1559                 return;
1560         }
1561
1562         header = (unsigned int *) lno;
1563         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1564                 LittleLong( header[ 1 ] ) == 1 &&
1565                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1566                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1567                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1568                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1569         {
1570                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1571                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1572         }
1573         Mem_Free( lno );
1574 }
1575
1576 /*
1577 ===============
1578 PRVM_LoadProgs
1579 ===============
1580 */
1581 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1582 {
1583         int i;
1584         dstatement_t *st;
1585         ddef_t *infielddefs;
1586         dfunction_t *dfunctions;
1587         fs_offset_t filesize;
1588
1589         if( prog->loaded ) {
1590                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1591         }
1592
1593         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1594         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1595                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1596
1597         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1598
1599         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1600
1601 // byte swap the header
1602         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1603                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1604
1605         if (prog->progs->version != PROG_VERSION)
1606                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1607         if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1608                 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);
1609
1610         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1611         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1612
1613         if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1614                 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1615         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1616         prog->stringssize = prog->progs->numstrings;
1617
1618         prog->numknownstrings = 0;
1619         prog->maxknownstrings = 0;
1620         prog->knownstrings = NULL;
1621         prog->knownstrings_freeable = NULL;
1622
1623         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1624
1625         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1626
1627         // we need to expand the fielddefs list to include all the engine fields,
1628         // so allocate a new place for it
1629         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1630         //                                                                                              ( + DPFIELDS                       )
1631         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1632
1633         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1634
1635         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1636
1637         // moved edict_size calculation down below field adding code
1638
1639         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1640         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1641
1642 // byte swap the lumps
1643         for (i=0 ; i<prog->progs->numstatements ; i++)
1644         {
1645                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1646                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1647                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1648                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1649         }
1650
1651         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1652         for (i = 0;i < prog->progs->numfunctions;i++)
1653         {
1654                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1655                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1656                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1657                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1658                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1659                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1660                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1661         }
1662
1663         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1664         {
1665                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1666                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1667                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1668         }
1669
1670         // copy the progs fields to the new fields list
1671         for (i = 0;i < prog->progs->numfielddefs;i++)
1672         {
1673                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1674                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1675                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1676                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1677                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1678         }
1679
1680         // append the required fields
1681         for (i = 0;i < (int) numrequiredfields;i++)
1682         {
1683                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1684                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1685                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1686                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1687                         prog->progs->entityfields += 3;
1688                 else
1689                         prog->progs->entityfields++;
1690                 prog->progs->numfielddefs++;
1691         }
1692
1693         // check required functions
1694         for(i=0 ; i < numrequiredfunc ; i++)
1695                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1696                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1697
1698         // check required globals
1699         for(i=0 ; i < numrequiredglobals ; i++)
1700                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1701                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1702
1703         for (i=0 ; i<prog->progs->numglobals ; i++)
1704                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1705
1706         // moved edict_size calculation down here, below field adding code
1707         // LordHavoc: this no longer includes the prvm_edict_t header
1708         prog->edict_size = prog->progs->entityfields * 4;
1709         prog->edictareasize = prog->edict_size * prog->limit_edicts;
1710
1711         // LordHavoc: bounds check anything static
1712         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1713         {
1714                 switch (st->op)
1715                 {
1716                 case OP_IF:
1717                 case OP_IFNOT:
1718                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1719                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1720                         break;
1721                 case OP_GOTO:
1722                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1723                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1724                         break;
1725                 // global global global
1726                 case OP_ADD_F:
1727                 case OP_ADD_V:
1728                 case OP_SUB_F:
1729                 case OP_SUB_V:
1730                 case OP_MUL_F:
1731                 case OP_MUL_V:
1732                 case OP_MUL_FV:
1733                 case OP_MUL_VF:
1734                 case OP_DIV_F:
1735                 case OP_BITAND:
1736                 case OP_BITOR:
1737                 case OP_GE:
1738                 case OP_LE:
1739                 case OP_GT:
1740                 case OP_LT:
1741                 case OP_AND:
1742                 case OP_OR:
1743                 case OP_EQ_F:
1744                 case OP_EQ_V:
1745                 case OP_EQ_S:
1746                 case OP_EQ_E:
1747                 case OP_EQ_FNC:
1748                 case OP_NE_F:
1749                 case OP_NE_V:
1750                 case OP_NE_S:
1751                 case OP_NE_E:
1752                 case OP_NE_FNC:
1753                 case OP_ADDRESS:
1754                 case OP_LOAD_F:
1755                 case OP_LOAD_FLD:
1756                 case OP_LOAD_ENT:
1757                 case OP_LOAD_S:
1758                 case OP_LOAD_FNC:
1759                 case OP_LOAD_V:
1760                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1761                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1762                         break;
1763                 // global none global
1764                 case OP_NOT_F:
1765                 case OP_NOT_V:
1766                 case OP_NOT_S:
1767                 case OP_NOT_FNC:
1768                 case OP_NOT_ENT:
1769                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1770                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1771                         break;
1772                 // 2 globals
1773                 case OP_STOREP_F:
1774                 case OP_STOREP_ENT:
1775                 case OP_STOREP_FLD:
1776                 case OP_STOREP_S:
1777                 case OP_STOREP_FNC:
1778                 case OP_STORE_F:
1779                 case OP_STORE_ENT:
1780                 case OP_STORE_FLD:
1781                 case OP_STORE_S:
1782                 case OP_STORE_FNC:
1783                 case OP_STATE:
1784                 case OP_STOREP_V:
1785                 case OP_STORE_V:
1786                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1787                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1788                         break;
1789                 // 1 global
1790                 case OP_CALL0:
1791                 case OP_CALL1:
1792                 case OP_CALL2:
1793                 case OP_CALL3:
1794                 case OP_CALL4:
1795                 case OP_CALL5:
1796                 case OP_CALL6:
1797                 case OP_CALL7:
1798                 case OP_CALL8:
1799                 case OP_DONE:
1800                 case OP_RETURN:
1801                         if ((unsigned short) st->a >= prog->progs->numglobals)
1802                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1803                         break;
1804                 default:
1805                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1806                         break;
1807                 }
1808         }
1809
1810         PRVM_LoadLNO(filename);
1811
1812         PRVM_Init_Exec();
1813
1814         prog->loaded = TRUE;
1815
1816         // set flags & ddef_ts in prog
1817
1818         prog->flag = 0;
1819
1820         PRVM_FindOffsets();
1821
1822         PRVM_GCALL(init_cmd)();
1823
1824         // init mempools
1825         PRVM_MEM_Alloc();
1826 }
1827
1828
1829 void PRVM_Fields_f (void)
1830 {
1831         int i, j, ednum, used, usedamount;
1832         int *counts;
1833         char tempstring[MAX_INPUTLINE], tempstring2[260];
1834         const char *name;
1835         prvm_edict_t *ed;
1836         ddef_t *d;
1837         int *v;
1838
1839         // TODO
1840         /*
1841         if (!sv.active)
1842         {
1843                 Con_Print("no progs loaded\n");
1844                 return;
1845         }
1846         */
1847
1848         if(Cmd_Argc() != 2)
1849         {
1850                 Con_Print("prvm_fields <program name>\n");
1851                 return;
1852         }
1853
1854         PRVM_Begin;
1855         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1856                 return;
1857
1858         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1859         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1860         {
1861                 ed = PRVM_EDICT_NUM(ednum);
1862                 if (ed->priv.required->free)
1863                         continue;
1864                 for (i = 1;i < prog->progs->numfielddefs;i++)
1865                 {
1866                         d = &prog->fielddefs[i];
1867                         name = PRVM_GetString(d->s_name);
1868                         if (name[strlen(name)-2] == '_')
1869                                 continue;       // skip _x, _y, _z vars
1870                         v = (int *)((char *)ed->fields.vp + d->ofs*4);
1871                         // if the value is still all 0, skip the field
1872                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1873                         {
1874                                 if (v[j])
1875                                 {
1876                                         counts[i]++;
1877                                         break;
1878                                 }
1879                         }
1880                 }
1881         }
1882         used = 0;
1883         usedamount = 0;
1884         tempstring[0] = 0;
1885         for (i = 0;i < prog->progs->numfielddefs;i++)
1886         {
1887                 d = &prog->fielddefs[i];
1888                 name = PRVM_GetString(d->s_name);
1889                 if (name[strlen(name)-2] == '_')
1890                         continue;       // skip _x, _y, _z vars
1891                 switch(d->type & ~DEF_SAVEGLOBAL)
1892                 {
1893                 case ev_string:
1894                         strlcat(tempstring, "string   ", sizeof(tempstring));
1895                         break;
1896                 case ev_entity:
1897                         strlcat(tempstring, "entity   ", sizeof(tempstring));
1898                         break;
1899                 case ev_function:
1900                         strlcat(tempstring, "function ", sizeof(tempstring));
1901                         break;
1902                 case ev_field:
1903                         strlcat(tempstring, "field    ", sizeof(tempstring));
1904                         break;
1905                 case ev_void:
1906                         strlcat(tempstring, "void     ", sizeof(tempstring));
1907                         break;
1908                 case ev_float:
1909                         strlcat(tempstring, "float    ", sizeof(tempstring));
1910                         break;
1911                 case ev_vector:
1912                         strlcat(tempstring, "vector   ", sizeof(tempstring));
1913                         break;
1914                 case ev_pointer:
1915                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
1916                         break;
1917                 default:
1918                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1919                         strlcat(tempstring, tempstring2, sizeof(tempstring));
1920                         break;
1921                 }
1922                 if (strlen(name) > sizeof(tempstring2)-4)
1923                 {
1924                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
1925                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1926                         tempstring2[sizeof(tempstring2)-1] = 0;
1927                         name = tempstring2;
1928                 }
1929                 strlcat(tempstring, name, sizeof(tempstring));
1930                 for (j = (int)strlen(name);j < 25;j++)
1931                         strlcat(tempstring, " ", sizeof(tempstring));
1932                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
1933                 strlcat(tempstring, tempstring2, sizeof(tempstring));
1934                 strlcat(tempstring, "\n", sizeof(tempstring));
1935                 if (strlen(tempstring) >= sizeof(tempstring)/2)
1936                 {
1937                         Con_Print(tempstring);
1938                         tempstring[0] = 0;
1939                 }
1940                 if (counts[i])
1941                 {
1942                         used++;
1943                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1944                 }
1945         }
1946         Mem_Free(counts);
1947         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);
1948
1949         PRVM_End;
1950 }
1951
1952 void PRVM_Globals_f (void)
1953 {
1954         int i;
1955         const char *wildcard;
1956         int numculled;
1957                 numculled = 0;
1958         // TODO
1959         /*if (!sv.active)
1960         {
1961                 Con_Print("no progs loaded\n");
1962                 return;
1963         }*/
1964         if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
1965         {
1966                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
1967                 return;
1968         }
1969
1970         PRVM_Begin;
1971         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
1972                 return;
1973
1974         if( Cmd_Argc() == 3)
1975                 wildcard = Cmd_Argv(2);
1976         else
1977                 wildcard = NULL;
1978
1979         Con_Printf("%s :", PRVM_NAME);
1980
1981         for (i = 0;i < prog->progs->numglobaldefs;i++)
1982         {
1983                 if(wildcard)
1984                         if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
1985                         {
1986                                 numculled++;
1987                                 continue;
1988                         }
1989                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
1990         }
1991         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
1992
1993         PRVM_End;
1994 }
1995
1996 /*
1997 ===============
1998 PRVM_Global
1999 ===============
2000 */
2001 void PRVM_Global_f(void)
2002 {
2003         ddef_t *global;
2004         if( Cmd_Argc() != 3 ) {
2005                 Con_Printf( "prvm_global <program name> <global name>\n" );
2006                 return;
2007         }
2008
2009         PRVM_Begin;
2010         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2011                 return;
2012
2013         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2014         if( !global )
2015                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2016         else
2017                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2018         PRVM_End;
2019 }
2020
2021 /*
2022 ===============
2023 PRVM_GlobalSet
2024 ===============
2025 */
2026 void PRVM_GlobalSet_f(void)
2027 {
2028         ddef_t *global;
2029         if( Cmd_Argc() != 4 ) {
2030                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2031                 return;
2032         }
2033
2034         PRVM_Begin;
2035         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2036                 return;
2037
2038         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2039         if( !global )
2040                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2041         else
2042                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2043         PRVM_End;
2044 }
2045
2046 /*
2047 ===============
2048 PRVM_Init
2049 ===============
2050 */
2051 void PRVM_Init (void)
2052 {
2053         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2054         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2055         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2056         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2057         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)");
2058         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)");
2059         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2060         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2061         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2062         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)");
2063         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2064         Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2065         Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2066         Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2067         // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
2068 #ifdef PRVM_BOUNDSCHECK_CVAR
2069         Cvar_RegisterVariable (&prvm_boundscheck);
2070 #endif
2071         Cvar_RegisterVariable (&prvm_traceqc);
2072         Cvar_RegisterVariable (&prvm_statementprofiling);
2073         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2074
2075         //VM_Cmd_Init();
2076 }
2077
2078 /*
2079 ===============
2080 PRVM_InitProg
2081 ===============
2082 */
2083 void PRVM_InitProg(int prognr)
2084 {
2085         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2086                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2087
2088         prog = &prog_list[prognr];
2089
2090         if(prog->loaded)
2091                 PRVM_ResetProg();
2092
2093         memset(prog, 0, sizeof(prvm_prog_t));
2094         prog->starttime = Sys_DoubleTime();
2095
2096         prog->error_cmd = Host_Error;
2097 }
2098
2099 int PRVM_GetProgNr()
2100 {
2101         return prog - prog_list;
2102 }
2103
2104 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2105 {
2106         return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2107 }
2108
2109 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2110 {
2111         _Mem_Free(buffer, filename, fileline);
2112 }
2113
2114 void _PRVM_FreeAll(const char *filename, int fileline)
2115 {
2116         prog->progs = NULL;
2117         prog->fielddefs = NULL;
2118         prog->functions = NULL;
2119         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2120 }
2121
2122 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2123 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2124 {
2125         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2126         return 0;
2127 }
2128
2129 /*
2130 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2131 {
2132         PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2133         return 0;
2134 }
2135
2136 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2137 {
2138         int n;
2139         n = e - prog->edicts;
2140         if ((unsigned int)n >= prog->limit_edicts)
2141                 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2142         return n;
2143 }
2144
2145 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2146 //{
2147 //      return e - prog->edicts;
2148 //}
2149
2150 //#define       PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2151 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2152 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2153 {
2154         int n;
2155         n = e - prog->edicts;
2156         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2157                 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2158         return n;// EXPERIMENTAL
2159         //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2160 }
2161 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2162 {
2163         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2164                 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2165         return prog->edicts + n; // EXPERIMENTAL
2166         //return prog->edicts + ((n) / (progs->entityfields * 4));
2167 }
2168 */
2169
2170
2171 sizebuf_t vm_tempstringsbuf;
2172
2173 const char *PRVM_GetString(int num)
2174 {
2175         if (num >= 0)
2176         {
2177                 if (num < prog->stringssize)
2178                         return prog->strings + num;
2179                 else
2180 #if 1
2181                 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2182                 {
2183                         num -= prog->stringssize;
2184                         if (num < vm_tempstringsbuf.cursize)
2185                                 return (char *)vm_tempstringsbuf.data + num;
2186                         else
2187                         {
2188                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2189                                 return "";
2190                         }
2191                 }
2192                 else
2193 #endif
2194                 {
2195                         VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2196                         return "";
2197                 }
2198         }
2199         else
2200         {
2201                 num = -1 - num;
2202 #if 0
2203                 if (num >= (1<<30))
2204                 {
2205                         // special range reserved for tempstrings
2206                         num -= (1<<30);
2207                         if (num < vm_tempstringsbuf.cursize)
2208                                 return (char *)vm_tempstringsbuf.data + num;
2209                         else
2210                         {
2211                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2212                                 return "";
2213                         }
2214                 }
2215                 else
2216 #endif
2217                 if (num < prog->numknownstrings)
2218                 {
2219                         if (!prog->knownstrings[num])
2220                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2221                         return prog->knownstrings[num];
2222                 }
2223                 else
2224                 {
2225                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2226                         return "";
2227                 }
2228         }
2229 }
2230
2231 int PRVM_SetEngineString(const char *s)
2232 {
2233         int i;
2234         if (!s)
2235                 return 0;
2236         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2237                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2238         // if it's in the tempstrings area, use a reserved range
2239         // (otherwise we'd get millions of useless string offsets cluttering the database)
2240         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2241 #if 1
2242                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2243 #else
2244                 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2245 #endif
2246         // see if it's a known string address
2247         for (i = 0;i < prog->numknownstrings;i++)
2248                 if (prog->knownstrings[i] == s)
2249                         return -1 - i;
2250         // new unknown engine string
2251         if (developer.integer >= 200)
2252                 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2253         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2254                 if (!prog->knownstrings[i])
2255                         break;
2256         if (i >= prog->numknownstrings)
2257         {
2258                 if (i >= prog->maxknownstrings)
2259                 {
2260                         const char **oldstrings = prog->knownstrings;
2261                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2262                         prog->maxknownstrings += 128;
2263                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2264                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2265                         if (prog->numknownstrings)
2266                         {
2267                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2268                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2269                         }
2270                 }
2271                 prog->numknownstrings++;
2272         }
2273         prog->firstfreeknownstring = i + 1;
2274         prog->knownstrings[i] = s;
2275         return -1 - i;
2276 }
2277
2278 // temp string handling
2279
2280 // all tempstrings go into this buffer consecutively, and it is reset
2281 // whenever PRVM_ExecuteProgram returns to the engine
2282 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2283 //  restores it on return, so multiple recursive calls can share the same
2284 //  buffer)
2285 // the buffer size is automatically grown as needed
2286
2287 int PRVM_SetTempString(const char *s)
2288 {
2289         int size;
2290         char *t;
2291         if (!s)
2292                 return 0;
2293         size = (int)strlen(s) + 1;
2294         if (developer.integer >= 300)
2295                 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2296         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2297         {
2298                 sizebuf_t old = vm_tempstringsbuf;
2299                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2300                         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);
2301                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2302                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2303                         vm_tempstringsbuf.maxsize *= 2;
2304                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2305                 {
2306                         if (developer.integer >= 100)
2307                                 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2308                         vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2309                         if (old.cursize)
2310                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2311                         if (old.data)
2312                                 Mem_Free(old.data);
2313                 }
2314         }
2315         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2316         memcpy(t, s, size);
2317         vm_tempstringsbuf.cursize += size;
2318         return PRVM_SetEngineString(t);
2319 }
2320
2321 int PRVM_AllocString(size_t bufferlength, char **pointer)
2322 {
2323         int i;
2324         if (!bufferlength)
2325                 return 0;
2326         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2327                 if (!prog->knownstrings[i])
2328                         break;
2329         if (i >= prog->numknownstrings)
2330         {
2331                 if (i >= prog->maxknownstrings)
2332                 {
2333                         const char **oldstrings = prog->knownstrings;
2334                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2335                         prog->maxknownstrings += 128;
2336                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2337                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2338                         if (prog->numknownstrings)
2339                         {
2340                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2341                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2342                         }
2343                 }
2344                 prog->numknownstrings++;
2345         }
2346         prog->firstfreeknownstring = i + 1;
2347         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2348         prog->knownstrings_freeable[i] = true;
2349         if (pointer)
2350                 *pointer = (char *)(prog->knownstrings[i]);
2351         return -1 - i;
2352 }
2353
2354 void PRVM_FreeString(int num)
2355 {
2356         if (num == 0)
2357                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2358         else if (num >= 0 && num < prog->stringssize)
2359                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2360         else if (num < 0 && num >= -prog->numknownstrings)
2361         {
2362                 num = -1 - num;
2363                 if (!prog->knownstrings[num])
2364                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2365                 if (!prog->knownstrings[num])
2366                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2367                 PRVM_Free((char *)prog->knownstrings[num]);
2368                 prog->knownstrings[num] = NULL;
2369                 prog->knownstrings_freeable[num] = false;
2370                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2371         }
2372         else
2373                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2374 }
2375