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