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