]> git.xonotic.org Git - xonotic/darkplaces.git/blob - prvm_edict.c
Redesigned TaskQueue to have a queue and distributor model so that threads can keep...
[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 #include "csprogs.h"
25
26 prvm_prog_t prvm_prog_list[PRVM_PROG_MAX];
27
28 int             prvm_type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
29
30 prvm_eval_t prvm_badvalue; // used only for error returns
31
32 cvar_t prvm_language = {CVAR_CLIENT | CVAR_SERVER | CVAR_SAVE, "prvm_language", "", "when set, loads PROGSFILE.LANGUAGENAME.po and common.LANGUAGENAME.po for string translations; when set to dump, PROGSFILE.pot is written from the strings in the progs"};
33 // LadyHavoc: prints every opcode as it executes - warning: this is significant spew
34 cvar_t prvm_traceqc = {CVAR_CLIENT | CVAR_SERVER, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
35 // LadyHavoc: counts usage of each QuakeC statement
36 cvar_t prvm_statementprofiling = {CVAR_CLIENT | CVAR_SERVER, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
37 cvar_t prvm_timeprofiling = {CVAR_CLIENT | CVAR_SERVER, "prvm_timeprofiling", "0", "counts how long each function has been executed, these counts are displayed in prvm_profile output (if enabled)"};
38 cvar_t prvm_coverage = {CVAR_CLIENT | CVAR_SERVER, "prvm_coverage", "0", "report and count coverage events (1: per-function, 2: coverage() builtin, 4: per-statement)"};
39 cvar_t prvm_backtraceforwarnings = {CVAR_CLIENT | CVAR_SERVER, "prvm_backtraceforwarnings", "0", "print a backtrace for warnings too"};
40 cvar_t prvm_leaktest = {CVAR_CLIENT | CVAR_SERVER, "prvm_leaktest", "0", "try to detect memory leaks in strings or entities"};
41 cvar_t prvm_leaktest_follow_targetname = {CVAR_CLIENT | CVAR_SERVER, "prvm_leaktest_follow_targetname", "0", "if set, target/targetname links are considered when leak testing; this should normally not be required, as entities created during startup - e.g. info_notnull - are never considered leaky"};
42 cvar_t prvm_leaktest_ignore_classnames = {CVAR_CLIENT | CVAR_SERVER, "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)"};
43 cvar_t prvm_errordump = {CVAR_CLIENT | CVAR_SERVER, "prvm_errordump", "0", "write a savegame on crash to crash-server.dmp"};
44 cvar_t prvm_breakpointdump = {CVAR_CLIENT | CVAR_SERVER, "prvm_breakpointdump", "0", "write a savegame on breakpoint to breakpoint-server.dmp"};
45 cvar_t prvm_reuseedicts_startuptime = {CVAR_CLIENT | CVAR_SERVER, "prvm_reuseedicts_startuptime", "2", "allows immediate re-use of freed entity slots during start of new level (value in seconds)"};
46 cvar_t prvm_reuseedicts_neverinsameframe = {CVAR_CLIENT | CVAR_SERVER, "prvm_reuseedicts_neverinsameframe", "1", "never allows re-use of freed entity slots during same frame"};
47
48 static double prvm_reuseedicts_always_allow = 0;
49 qboolean prvm_runawaycheck = true;
50
51 //============================================================================
52 // mempool handling
53
54 /*
55 ===============
56 PRVM_MEM_Alloc
57 ===============
58 */
59 static void PRVM_MEM_Alloc(prvm_prog_t *prog)
60 {
61         int i;
62
63         // reserve space for the null entity aka world
64         // check bound of max_edicts
65         prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts);
66         prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts);
67
68         // edictprivate_size has to be min as big prvm_edict_private_t
69         prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
70
71         // alloc edicts
72         prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
73
74         // alloc edict private space
75         prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
76
77         // alloc edict fields
78         prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
79         prog->edictsfields = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, prog->entityfieldsarea * sizeof(prvm_vec_t));
80
81         // set edict pointers
82         for(i = 0; i < prog->max_edicts; i++)
83         {
84                 prog->edicts[i].priv.required = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
85                 prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
86         }
87 }
88
89 /*
90 ===============
91 PRVM_MEM_IncreaseEdicts
92 ===============
93 */
94 void PRVM_MEM_IncreaseEdicts(prvm_prog_t *prog)
95 {
96         int             i;
97
98         if(prog->max_edicts >= prog->limit_edicts)
99                 return;
100
101         prog->begin_increase_edicts(prog);
102
103         // increase edicts
104         prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
105
106         prog->entityfieldsarea = prog->entityfields * prog->max_edicts;
107         prog->edictsfields = (prvm_vec_t*)Mem_Realloc(prog->progs_mempool, (void *)prog->edictsfields, prog->entityfieldsarea * sizeof(prvm_vec_t));
108         prog->edictprivate = (void *)Mem_Realloc(prog->progs_mempool, (void *)prog->edictprivate, prog->max_edicts * prog->edictprivate_size);
109
110         //set e and v pointers
111         for(i = 0; i < prog->max_edicts; i++)
112         {
113                 prog->edicts[i].priv.required  = (prvm_edict_private_t *)((unsigned char  *)prog->edictprivate + i * prog->edictprivate_size);
114                 prog->edicts[i].fields.fp = prog->edictsfields + i * prog->entityfields;
115         }
116
117         prog->end_increase_edicts(prog);
118 }
119
120 //============================================================================
121 // normal prvm
122
123 int PRVM_ED_FindFieldOffset(prvm_prog_t *prog, const char *field)
124 {
125         ddef_t *d;
126         d = PRVM_ED_FindField(prog, field);
127         if (!d)
128                 return -1;
129         return d->ofs;
130 }
131
132 int PRVM_ED_FindGlobalOffset(prvm_prog_t *prog, const char *global)
133 {
134         ddef_t *d;
135         d = PRVM_ED_FindGlobal(prog, global);
136         if (!d)
137                 return -1;
138         return d->ofs;
139 }
140
141 func_t PRVM_ED_FindFunctionOffset(prvm_prog_t *prog, const char *function)
142 {
143         mfunction_t *f;
144         f = PRVM_ED_FindFunction(prog, function);
145         if (!f)
146                 return 0;
147         return (func_t)(f - prog->functions);
148 }
149
150 /*
151 =================
152 PRVM_ProgFromString
153 =================
154 */
155 prvm_prog_t *PRVM_ProgFromString(const char *str)
156 {
157         if (!strcmp(str, "server"))
158                 return SVVM_prog;
159         if (!strcmp(str, "client"))
160                 return CLVM_prog;
161 #ifdef CONFIG_MENU
162         if (!strcmp(str, "menu"))
163                 return MVM_prog;
164 #endif
165         return NULL;
166 }
167
168 /*
169 =================
170 PRVM_FriendlyProgFromString
171 =================
172 */
173 prvm_prog_t *PRVM_FriendlyProgFromString(const char *str)
174 {
175         prvm_prog_t *prog = PRVM_ProgFromString(str);
176         if (!prog)
177         {
178                 Con_Printf("%s: unknown program name\n", str);
179                 return NULL;
180         }
181         if (!prog->loaded)
182         {
183                 Con_Printf("%s: program is not loaded\n", str);
184                 return NULL;
185         }
186         return prog;
187 }
188
189 /*
190 =================
191 PRVM_ED_ClearEdict
192
193 Sets everything to NULL.
194
195 Nota bene: this also marks the entity as allocated if it has been previously
196 freed and sets the allocation origin.
197 =================
198 */
199 void PRVM_ED_ClearEdict(prvm_prog_t *prog, prvm_edict_t *e)
200 {
201         memset(e->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
202         e->priv.required->free = false;
203         e->priv.required->freetime = realtime;
204         if(e->priv.required->allocation_origin)
205                 Mem_Free((char *)e->priv.required->allocation_origin);
206         e->priv.required->allocation_origin = PRVM_AllocationOrigin(prog);
207
208         // AK: Let the init_edict function determine if something needs to be initialized
209         prog->init_edict(prog, e);
210 }
211
212 const char *PRVM_AllocationOrigin(prvm_prog_t *prog)
213 {
214         char *buf = NULL;
215         if(prog->leaktest_active)
216         if(prog->depth > 0) // actually in QC code and not just parsing the entities block of a map/savegame
217         {
218                 buf = (char *)PRVM_Alloc(256);
219                 PRVM_ShortStackTrace(prog, buf, 256);
220         }
221         return buf;
222 }
223
224 /*
225 =================
226 PRVM_ED_CanAlloc
227
228 Returns if this particular edict could get allocated by PRVM_ED_Alloc
229 =================
230 */
231 qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e)
232 {
233         if(!e->priv.required->free)
234                 return false;
235         if(prvm_reuseedicts_always_allow == realtime)
236                 return true;
237         if(realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer)
238                 return false; // never allow reuse in same frame (causes networking trouble)
239         if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value)
240                 return true;
241         if(realtime > e->priv.required->freetime + 1)
242                 return true;
243         return false; // entity slot still blocked because the entity was freed less than one second ago
244 }
245
246 /*
247 =================
248 PRVM_ED_Alloc
249
250 Either finds a free edict, or allocates a new one.
251 Try to avoid reusing an entity that was recently freed, because it
252 can cause the client to think the entity morphed into something else
253 instead of being removed and recreated, which can cause interpolated
254 angles and bad trails.
255 =================
256 */
257 prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog)
258 {
259         int i;
260         prvm_edict_t *e;
261
262         // the client qc dont need maxclients
263         // thus it doesnt need to use svs.maxclients
264         // AK:  changed i=svs.maxclients+1
265         // AK:  changed so the edict 0 wont spawn -> used as reserved/world entity
266         //              although the menu/client has no world
267         for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
268         {
269                 e = PRVM_EDICT_NUM(i);
270                 if(PRVM_ED_CanAlloc(prog, e))
271                 {
272                         PRVM_ED_ClearEdict (prog, e);
273                         return e;
274                 }
275         }
276
277         if (i == prog->limit_edicts)
278                 prog->error_cmd("%s: PRVM_ED_Alloc: no free edicts", prog->name);
279
280         prog->num_edicts++;
281         if (prog->num_edicts >= prog->max_edicts)
282                 PRVM_MEM_IncreaseEdicts(prog);
283
284         e = PRVM_EDICT_NUM(i);
285
286         PRVM_ED_ClearEdict(prog, e);
287         return e;
288 }
289
290 /*
291 =================
292 PRVM_ED_Free
293
294 Marks the edict as free
295 FIXME: walk all entities and NULL out references to this entity
296 =================
297 */
298 void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed)
299 {
300         // dont delete the null entity (world) or reserved edicts
301         if (ed - prog->edicts <= prog->reserved_edicts)
302                 return;
303
304         prog->free_edict(prog, ed);
305
306         ed->priv.required->free = true;
307         ed->priv.required->freetime = realtime;
308         if(ed->priv.required->allocation_origin)
309         {
310                 Mem_Free((char *)ed->priv.required->allocation_origin);
311                 ed->priv.required->allocation_origin = NULL;
312         }
313 }
314
315 //===========================================================================
316
317 /*
318 ============
319 PRVM_ED_GlobalAtOfs
320 ============
321 */
322 static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs)
323 {
324         ddef_t          *def;
325         int                     i;
326
327         for (i = 0;i < prog->numglobaldefs;i++)
328         {
329                 def = &prog->globaldefs[i];
330                 if (def->ofs == ofs)
331                         return def;
332         }
333         return NULL;
334 }
335
336 /*
337 ============
338 PRVM_ED_FieldAtOfs
339 ============
340 */
341 ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs)
342 {
343         ddef_t          *def;
344         int                     i;
345
346         for (i = 0;i < prog->numfielddefs;i++)
347         {
348                 def = &prog->fielddefs[i];
349                 if (def->ofs == ofs)
350                         return def;
351         }
352         return NULL;
353 }
354
355 /*
356 ============
357 PRVM_ED_FindField
358 ============
359 */
360 ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name)
361 {
362         ddef_t *def;
363         int i;
364
365         for (i = 0;i < prog->numfielddefs;i++)
366         {
367                 def = &prog->fielddefs[i];
368                 if (!strcmp(PRVM_GetString(prog, def->s_name), name))
369                         return def;
370         }
371         return NULL;
372 }
373
374 /*
375 ============
376 PRVM_ED_FindGlobal
377 ============
378 */
379 ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name)
380 {
381         ddef_t *def;
382         int i;
383
384         for (i = 0;i < prog->numglobaldefs;i++)
385         {
386                 def = &prog->globaldefs[i];
387                 if (!strcmp(PRVM_GetString(prog, def->s_name), name))
388                         return def;
389         }
390         return NULL;
391 }
392
393
394 /*
395 ============
396 PRVM_ED_FindFunction
397 ============
398 */
399 mfunction_t *PRVM_ED_FindFunction (prvm_prog_t *prog, const char *name)
400 {
401         mfunction_t             *func;
402         int                             i;
403
404         for (i = 0;i < prog->numfunctions;i++)
405         {
406                 func = &prog->functions[i];
407                 if (!strcmp(PRVM_GetString(prog, func->s_name), name))
408                         return func;
409         }
410         return NULL;
411 }
412
413
414 /*
415 ============
416 PRVM_ValueString
417
418 Returns a string describing *data in a type specific manner
419 =============
420 */
421 static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
422 {
423         ddef_t *def;
424         mfunction_t *f;
425         int n;
426
427         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
428
429         switch (type)
430         {
431         case ev_string:
432                 strlcpy (line, PRVM_GetString (prog, val->string), linelength);
433                 break;
434         case ev_entity:
435                 n = val->edict;
436                 if (n < 0 || n >= prog->max_edicts)
437                         dpsnprintf (line, linelength, "entity %i (invalid!)", n);
438                 else
439                         dpsnprintf (line, linelength, "entity %i", n);
440                 break;
441         case ev_function:
442                 if ((unsigned int)val->function < (unsigned int)prog->progs_numfunctions)
443                 {
444                         f = prog->functions + val->function;
445                         dpsnprintf (line, linelength, "%s()", PRVM_GetString(prog, f->s_name));
446                 }
447                 else
448                         dpsnprintf (line, linelength, "function%i() (invalid!)", val->function);
449                 break;
450         case ev_field:
451                 def = PRVM_ED_FieldAtOfs ( prog, val->_int );
452                 if (def != NULL)
453                         dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
454                 else
455                         dpsnprintf (line, linelength, "field%i (invalid!)", val->_int );
456                 break;
457         case ev_void:
458                 dpsnprintf (line, linelength, "void");
459                 break;
460         case ev_float:
461                 // LadyHavoc: changed from %5.1f to %10.4f
462                 dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
463                 break;
464         case ev_vector:
465                 // LadyHavoc: changed from %5.1f to %10.4f
466                 dpsnprintf (line, linelength, "'" VECTOR_LOSSLESS_FORMAT "'", val->vector[0], val->vector[1], val->vector[2]);
467                 break;
468         case ev_pointer:
469                 dpsnprintf (line, linelength, "pointer");
470                 break;
471         default:
472                 dpsnprintf (line, linelength, "bad type %i", (int) type);
473                 break;
474         }
475
476         return line;
477 }
478
479 /*
480 ============
481 PRVM_UglyValueString
482
483 Returns a string describing *data in a type specific manner
484 Easier to parse than PR_ValueString
485 =============
486 */
487 char *PRVM_UglyValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
488 {
489         int i;
490         const char *s;
491         ddef_t *def;
492         mfunction_t *f;
493
494         type = (etype_t)((int)type & ~DEF_SAVEGLOBAL);
495
496         switch (type)
497         {
498         case ev_string:
499                 // Parse the string a bit to turn special characters
500                 // (like newline, specifically) into escape codes,
501                 // this fixes saving games from various mods
502                 s = PRVM_GetString (prog, val->string);
503                 for (i = 0;i < (int)linelength - 2 && *s;)
504                 {
505                         if (*s == '\n')
506                         {
507                                 line[i++] = '\\';
508                                 line[i++] = 'n';
509                         }
510                         else if (*s == '\r')
511                         {
512                                 line[i++] = '\\';
513                                 line[i++] = 'r';
514                         }
515                         else if (*s == '\\')
516                         {
517                                 line[i++] = '\\';
518                                 line[i++] = '\\';
519                         }
520                         else if (*s == '"')
521                         {
522                                 line[i++] = '\\';
523                                 line[i++] = '"';
524                         }
525                         else
526                                 line[i++] = *s;
527                         s++;
528                 }
529                 line[i] = '\0';
530                 break;
531         case ev_entity:
532                 i = val->edict;
533                 dpsnprintf (line, linelength, "%i", i);
534                 break;
535         case ev_function:
536                 if ((unsigned int)val->function < (unsigned int)prog->progs_numfunctions)
537                 {
538                         f = prog->functions + val->function;
539                         strlcpy (line, PRVM_GetString (prog, f->s_name), linelength);
540                 }
541                 else
542                         dpsnprintf (line, linelength, "bad function %i (invalid!)", val->function);
543                 break;
544         case ev_field:
545                 def = PRVM_ED_FieldAtOfs ( prog, val->_int );
546                 if (def != NULL)
547                         dpsnprintf (line, linelength, ".%s", PRVM_GetString(prog, def->s_name));
548                 else
549                         dpsnprintf (line, linelength, "field%i (invalid!)", val->_int );
550                 break;
551         case ev_void:
552                 dpsnprintf (line, linelength, "void");
553                 break;
554         case ev_float:
555                 dpsnprintf (line, linelength, FLOAT_LOSSLESS_FORMAT, val->_float);
556                 break;
557         case ev_vector:
558                 dpsnprintf (line, linelength, VECTOR_LOSSLESS_FORMAT, val->vector[0], val->vector[1], val->vector[2]);
559                 break;
560         default:
561                 dpsnprintf (line, linelength, "bad type %i", type);
562                 break;
563         }
564
565         return line;
566 }
567
568 /*
569 ============
570 PRVM_GlobalString
571
572 Returns a string with a description and the contents of a global,
573 padded to 20 field width
574 ============
575 */
576 char *PRVM_GlobalString (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
577 {
578         char    *s;
579         //size_t        i;
580         ddef_t  *def;
581         prvm_eval_t     *val;
582         char valuebuf[MAX_INPUTLINE];
583
584         val = (prvm_eval_t *)&prog->globals.fp[ofs];
585         def = PRVM_ED_GlobalAtOfs(prog, ofs);
586         if (!def)
587                 dpsnprintf (line, linelength, "GLOBAL%i", ofs);
588         else
589         {
590                 s = PRVM_ValueString (prog, (etype_t)def->type, val, valuebuf, sizeof(valuebuf));
591                 dpsnprintf (line, linelength, "%s (=%s)", PRVM_GetString(prog, def->s_name), s);
592         }
593
594         //i = strlen(line);
595         //for ( ; i<20 ; i++)
596         //      strcat (line," ");
597         //strcat (line," ");
598
599         return line;
600 }
601
602 char *PRVM_GlobalStringNoContents (prvm_prog_t *prog, int ofs, char *line, size_t linelength)
603 {
604         //size_t        i;
605         ddef_t  *def;
606
607         def = PRVM_ED_GlobalAtOfs(prog, ofs);
608         if (!def)
609                 dpsnprintf (line, linelength, "GLOBAL%i", ofs);
610         else
611                 dpsnprintf (line, linelength, "%s", PRVM_GetString(prog, def->s_name));
612
613         //i = strlen(line);
614         //for ( ; i<20 ; i++)
615         //      strcat (line," ");
616         //strcat (line," ");
617
618         return line;
619 }
620
621
622 /*
623 =============
624 PRVM_ED_Print
625
626 For debugging
627 =============
628 */
629 // LadyHavoc: optimized this to print out much more quickly (tempstring)
630 // LadyHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print)
631 void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname)
632 {
633         size_t  l;
634         ddef_t  *d;
635         prvm_eval_t     *val;
636         int             i, j;
637         const char      *name;
638         int             type;
639         char    tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers
640         char    valuebuf[MAX_INPUTLINE];
641
642         if (ed->priv.required->free)
643         {
644                 Con_Printf("%s: FREE\n",prog->name);
645                 return;
646         }
647
648         tempstring[0] = 0;
649         dpsnprintf(tempstring, sizeof(tempstring), "\n%s EDICT %i:\n", prog->name, PRVM_NUM_FOR_EDICT(ed));
650         for (i = 1;i < prog->numfielddefs;i++)
651         {
652                 d = &prog->fielddefs[i];
653                 name = PRVM_GetString(prog, d->s_name);
654                 if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
655                         continue;       // skip _x, _y, _z vars
656
657                 // Check Field Name Wildcard
658                 if(wildcard_fieldname)
659                         if( !matchpattern(name, wildcard_fieldname, 1) )
660                                 // Didn't match; skip
661                                 continue;
662
663                 val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
664
665         // if the value is still all 0, skip the field
666                 type = d->type & ~DEF_SAVEGLOBAL;
667
668                 for (j=0 ; j<prvm_type_size[type] ; j++)
669                         if (val->ivector[j])
670                                 break;
671                 if (j == prvm_type_size[type])
672                         continue;
673
674                 if (strlen(name) > sizeof(tempstring2)-4)
675                 {
676                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
677                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
678                         tempstring2[sizeof(tempstring2)-1] = 0;
679                         name = tempstring2;
680                 }
681                 strlcat(tempstring, name, sizeof(tempstring));
682                 for (l = strlen(name);l < 14;l++)
683                         strlcat(tempstring, " ", sizeof(tempstring));
684                 strlcat(tempstring, " ", sizeof(tempstring));
685
686                 name = PRVM_ValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf));
687                 if (strlen(name) > sizeof(tempstring2)-4)
688                 {
689                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
690                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
691                         tempstring2[sizeof(tempstring2)-1] = 0;
692                         name = tempstring2;
693                 }
694                 strlcat(tempstring, name, sizeof(tempstring));
695                 strlcat(tempstring, "\n", sizeof(tempstring));
696                 if (strlen(tempstring) >= sizeof(tempstring)/2)
697                 {
698                         Con_Print(tempstring);
699                         tempstring[0] = 0;
700                 }
701         }
702         if (tempstring[0])
703                 Con_Print(tempstring);
704 }
705
706 /*
707 =============
708 PRVM_ED_Write
709
710 For savegames
711 =============
712 */
713 extern cvar_t developer_entityparsing;
714 void PRVM_ED_Write (prvm_prog_t *prog, qfile_t *f, prvm_edict_t *ed)
715 {
716         ddef_t  *d;
717         prvm_eval_t     *val;
718         int             i, j;
719         const char      *name;
720         int             type;
721         char vabuf[1024];
722         char valuebuf[MAX_INPUTLINE];
723
724         FS_Print(f, "{\n");
725
726         if (ed->priv.required->free)
727         {
728                 FS_Print(f, "}\n");
729                 return;
730         }
731
732         for (i = 1;i < prog->numfielddefs;i++)
733         {
734                 d = &prog->fielddefs[i];
735                 name = PRVM_GetString(prog, d->s_name);
736
737                 if(developer_entityparsing.integer)
738                         Con_Printf("PRVM_ED_Write: at entity %d field %s\n", PRVM_NUM_FOR_EDICT(ed), name);
739
740                 //if(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
741                 if(strlen(name) > 1 && name[strlen(name)-2] == '_')
742                         continue;       // skip _x, _y, _z vars, and ALSO other _? vars as some mods expect them to be never saved (TODO: a gameplayfix for using the "more precise" condition above?)
743
744                 val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
745
746         // if the value is still all 0, skip the field
747                 type = d->type & ~DEF_SAVEGLOBAL;
748                 for (j=0 ; j<prvm_type_size[type] ; j++)
749                         if (val->ivector[j])
750                                 break;
751                 if (j == prvm_type_size[type])
752                         continue;
753
754                 FS_Printf(f,"\"%s\" ",name);
755                 prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_Write, ent=%d, name=%s", i, name);
756                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)));
757                 prog->statestring = NULL;
758         }
759
760         FS_Print(f, "}\n");
761 }
762
763 void PRVM_ED_PrintNum (prvm_prog_t *prog, int ent, const char *wildcard_fieldname)
764 {
765         PRVM_ED_Print(prog, PRVM_EDICT_NUM(ent), wildcard_fieldname);
766 }
767
768 /*
769 =============
770 PRVM_ED_PrintEdicts_f
771
772 For debugging, prints all the entities in the current server
773 =============
774 */
775 void PRVM_ED_PrintEdicts_f(cmd_state_t *cmd)
776 {
777         prvm_prog_t *prog;
778         int             i;
779         const char *wildcard_fieldname;
780
781         if(Cmd_Argc(cmd) < 2 || Cmd_Argc(cmd) > 3)
782         {
783                 Con_Print("prvm_edicts <program name> <optional field name wildcard>\n");
784                 return;
785         }
786
787         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
788                 return;
789
790         if( Cmd_Argc(cmd) == 3)
791                 wildcard_fieldname = Cmd_Argv(cmd, 2);
792         else
793                 wildcard_fieldname = NULL;
794
795         Con_Printf("%s: %i entities\n", prog->name, prog->num_edicts);
796         for (i=0 ; i<prog->num_edicts ; i++)
797                 PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
798 }
799
800 /*
801 =============
802 PRVM_ED_PrintEdict_f
803
804 For debugging, prints a single edict
805 =============
806 */
807 static void PRVM_ED_PrintEdict_f(cmd_state_t *cmd)
808 {
809         prvm_prog_t *prog;
810         int             i;
811         const char      *wildcard_fieldname;
812
813         if(Cmd_Argc(cmd) < 3 || Cmd_Argc(cmd) > 4)
814         {
815                 Con_Print("prvm_edict <program name> <edict number> <optional field name wildcard>\n");
816                 return;
817         }
818
819         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
820                 return;
821
822         i = atoi (Cmd_Argv(cmd, 2));
823         if (i >= prog->num_edicts)
824         {
825                 Con_Print("Bad edict number\n");
826                 return;
827         }
828         if( Cmd_Argc(cmd) == 4)
829                 // Optional Wildcard Provided
830                 wildcard_fieldname = Cmd_Argv(cmd, 3);
831         else
832                 // Use All
833                 wildcard_fieldname = NULL;
834         PRVM_ED_PrintNum (prog, i, wildcard_fieldname);
835 }
836
837 /*
838 =============
839 PRVM_ED_Count
840
841 For debugging
842 =============
843 */
844 // 2 possibilities : 1. just displaying the active edict count
845 //                                       2. making a function pointer [x]
846 static void PRVM_ED_Count_f(cmd_state_t *cmd)
847 {
848         prvm_prog_t *prog;
849
850         if(Cmd_Argc(cmd) != 2)
851         {
852                 Con_Print("prvm_count <program name>\n");
853                 return;
854         }
855
856         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
857                 return;
858
859         prog->count_edicts(prog);
860 }
861
862 /*
863 ==============================================================================
864
865                                         ARCHIVING GLOBALS
866
867 FIXME: need to tag constants, doesn't really work
868 ==============================================================================
869 */
870
871 /*
872 =============
873 PRVM_ED_WriteGlobals
874 =============
875 */
876 void PRVM_ED_WriteGlobals (prvm_prog_t *prog, qfile_t *f)
877 {
878         ddef_t          *def;
879         int                     i;
880         const char              *name;
881         int                     type;
882         char vabuf[1024];
883         char valuebuf[MAX_INPUTLINE];
884
885         FS_Print(f,"{\n");
886         for (i = 0;i < prog->numglobaldefs;i++)
887         {
888                 def = &prog->globaldefs[i];
889                 type = def->type;
890                 if ( !(def->type & DEF_SAVEGLOBAL) )
891                         continue;
892                 type &= ~DEF_SAVEGLOBAL;
893
894                 if (type != ev_string && type != ev_float && type != ev_entity)
895                         continue;
896
897                 name = PRVM_GetString(prog, def->s_name);
898
899                 if(developer_entityparsing.integer)
900                         Con_Printf("PRVM_ED_WriteGlobals: at global %s\n", name);
901
902                 prog->statestring = va(vabuf, sizeof(vabuf), "PRVM_ED_WriteGlobals, name=%s", name);
903                 FS_Printf(f,"\"%s\" ", name);
904                 FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString(prog, (etype_t)type, (prvm_eval_t *)&prog->globals.fp[def->ofs], valuebuf, sizeof(valuebuf)));
905                 prog->statestring = NULL;
906         }
907         FS_Print(f,"}\n");
908 }
909
910 /*
911 =============
912 PRVM_ED_ParseGlobals
913 =============
914 */
915 void PRVM_ED_ParseGlobals (prvm_prog_t *prog, const char *data)
916 {
917         char keyname[MAX_INPUTLINE];
918         ddef_t *key;
919
920         while (1)
921         {
922                 // parse key
923                 if (!COM_ParseToken_Simple(&data, false, false, true))
924                         prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace");
925                 if (com_token[0] == '}')
926                         break;
927
928                 if (developer_entityparsing.integer)
929                         Con_Printf("Key: \"%s\"", com_token);
930
931                 strlcpy (keyname, com_token, sizeof(keyname));
932
933                 // parse value
934                 if (!COM_ParseToken_Simple(&data, false, true, true))
935                         prog->error_cmd("PRVM_ED_ParseGlobals: EOF without closing brace");
936
937                 if (developer_entityparsing.integer)
938                         Con_Printf(" \"%s\"\n", com_token);
939
940                 if (com_token[0] == '}')
941                         prog->error_cmd("PRVM_ED_ParseGlobals: closing brace without data");
942
943                 key = PRVM_ED_FindGlobal (prog, keyname);
944                 if (!key)
945                 {
946                         Con_DPrintf("'%s' is not a global on %s\n", keyname, prog->name);
947                         continue;
948                 }
949
950                 if (!PRVM_ED_ParseEpair(prog, NULL, key, com_token, true))
951                         prog->error_cmd("PRVM_ED_ParseGlobals: parse error");
952         }
953 }
954
955 //============================================================================
956
957
958 /*
959 =============
960 PRVM_ED_ParseEval
961
962 Can parse either fields or globals
963 returns false if error
964 =============
965 */
966 qboolean PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, ddef_t *key, const char *s, qboolean parsebackslash)
967 {
968         int i, l;
969         char *new_p;
970         ddef_t *def;
971         prvm_eval_t *val;
972         mfunction_t *func;
973
974         if (ent)
975                 val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
976         else
977                 val = (prvm_eval_t *)(prog->globals.fp + key->ofs);
978         switch (key->type & ~DEF_SAVEGLOBAL)
979         {
980         case ev_string:
981                 l = (int)strlen(s) + 1;
982                 val->string = PRVM_AllocString(prog, l, &new_p);
983                 for (i = 0;i < l;i++)
984                 {
985                         if (s[i] == '\\' && s[i+1] && parsebackslash)
986                         {
987                                 i++;
988                                 if (s[i] == 'n')
989                                         *new_p++ = '\n';
990                                 else if (s[i] == 'r')
991                                         *new_p++ = '\r';
992                                 else
993                                         *new_p++ = s[i];
994                         }
995                         else
996                                 *new_p++ = s[i];
997                 }
998                 break;
999
1000         case ev_float:
1001                 while (*s && ISWHITESPACE(*s))
1002                         s++;
1003                 val->_float = atof(s);
1004                 break;
1005
1006         case ev_vector:
1007                 for (i = 0;i < 3;i++)
1008                 {
1009                         while (*s && ISWHITESPACE(*s))
1010                                 s++;
1011                         if (!*s)
1012                                 break;
1013                         val->vector[i] = atof(s);
1014                         while (!ISWHITESPACE(*s))
1015                                 s++;
1016                         if (!*s)
1017                                 break;
1018                 }
1019                 break;
1020
1021         case ev_entity:
1022                 while (*s && ISWHITESPACE(*s))
1023                         s++;
1024                 i = atoi(s);
1025                 if (i >= prog->limit_edicts)
1026                         Con_Printf("PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (unsigned int)i, prog->limit_edicts, prog->name);
1027                 while (i >= prog->max_edicts)
1028                         PRVM_MEM_IncreaseEdicts(prog);
1029                 // if IncreaseEdicts was called the base pointer needs to be updated
1030                 if (ent)
1031                         val = (prvm_eval_t *)(ent->fields.fp + key->ofs);
1032                 val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i));
1033                 break;
1034
1035         case ev_field:
1036                 if (*s != '.')
1037                 {
1038                         Con_DPrintf("PRVM_ED_ParseEpair: Bogus field name %s in %s\n", s, prog->name);
1039                         return false;
1040                 }
1041                 def = PRVM_ED_FindField(prog, s + 1);
1042                 if (!def)
1043                 {
1044                         Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, prog->name);
1045                         return false;
1046                 }
1047                 val->_int = def->ofs;
1048                 break;
1049
1050         case ev_function:
1051                 func = PRVM_ED_FindFunction(prog, s);
1052                 if (!func)
1053                 {
1054                         Con_Printf("PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, prog->name);
1055                         return false;
1056                 }
1057                 val->function = func - prog->functions;
1058                 break;
1059
1060         default:
1061                 Con_Printf("PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(prog, key->s_name), prog->name);
1062                 return false;
1063         }
1064         return true;
1065 }
1066
1067 /*
1068 =============
1069 PRVM_GameCommand_f
1070
1071 Console command to send a string to QC function GameCommand of the
1072 indicated progs
1073
1074 Usage:
1075   sv_cmd adminmsg 3 "do not teamkill"
1076   cl_cmd someclientcommand
1077   menu_cmd somemenucommand
1078
1079 All progs can support this extension; sg calls it in server QC, cg in client
1080 QC, mg in menu QC.
1081 =============
1082 */
1083 static void PRVM_GameCommand(cmd_state_t *cmd, const char *whichprogs, const char *whichcmd)
1084 {
1085         prvm_prog_t *prog;
1086         if(Cmd_Argc(cmd) < 1)
1087         {
1088                 Con_Printf("%s text...\n", whichcmd);
1089                 return;
1090         }
1091
1092         if (!(prog = PRVM_FriendlyProgFromString(whichprogs)))
1093                 return;
1094
1095         if(!PRVM_allfunction(GameCommand))
1096         {
1097                 Con_Printf("%s program do not support GameCommand!\n", whichprogs);
1098         }
1099         else
1100         {
1101                 int restorevm_tempstringsbuf_cursize;
1102                 const char *s;
1103
1104                 s = Cmd_Args(cmd);
1105
1106                 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
1107                 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, s ? s : "");
1108                 prog->ExecuteProgram(prog, PRVM_allfunction(GameCommand), "QC function GameCommand is missing");
1109                 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1110         }
1111 }
1112 static void PRVM_GameCommand_Server_f(cmd_state_t *cmd)
1113 {
1114         PRVM_GameCommand(cmd, "server", "sv_cmd");
1115 }
1116 static void PRVM_GameCommand_Client_f(cmd_state_t *cmd)
1117 {
1118         PRVM_GameCommand(cmd, "client", "cl_cmd");
1119 }
1120 static void PRVM_GameCommand_Menu_f(cmd_state_t *cmd)
1121 {
1122         PRVM_GameCommand(cmd, "menu", "menu_cmd");
1123 }
1124
1125 /*
1126 =============
1127 PRVM_ED_EdictGet_f
1128
1129 Console command to load a field of a specified edict
1130 =============
1131 */
1132 static void PRVM_ED_EdictGet_f(cmd_state_t *cmd)
1133 {
1134         prvm_prog_t *prog;
1135         prvm_edict_t *ed;
1136         ddef_t *key;
1137         const char *s;
1138         prvm_eval_t *v;
1139         char valuebuf[MAX_INPUTLINE];
1140
1141         if(Cmd_Argc(cmd) != 4 && Cmd_Argc(cmd) != 5)
1142         {
1143                 Con_Print("prvm_edictget <program name> <edict number> <field> [<cvar>]\n");
1144                 return;
1145         }
1146
1147         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
1148                 return;
1149
1150         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(cmd, 2)));
1151
1152         if((key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, 3))) == 0)
1153         {
1154                 Con_Printf("Key %s not found !\n", Cmd_Argv(cmd, 3));
1155                 goto fail;
1156         }
1157
1158         v = (prvm_eval_t *)(ed->fields.fp + key->ofs);
1159         s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
1160         if(Cmd_Argc(cmd) == 5)
1161         {
1162                 cvar_t *cvar = Cvar_FindVar(cmd->cvars, Cmd_Argv(cmd, 4), cmd->cvars_flagsmask);
1163                 if (cvar && cvar->flags & CVAR_READONLY)
1164                 {
1165                         Con_Printf("prvm_edictget: %s is read-only\n", cvar->name);
1166                         goto fail;
1167                 }
1168                 Cvar_Get(cmd->cvars, Cmd_Argv(cmd, 4), s, cmd->cvars_flagsmask, NULL);
1169         }
1170         else
1171                 Con_Printf("%s\n", s);
1172
1173 fail:
1174         ;
1175 }
1176
1177 static void PRVM_ED_GlobalGet_f(cmd_state_t *cmd)
1178 {
1179         prvm_prog_t *prog;
1180         ddef_t *key;
1181         const char *s;
1182         prvm_eval_t *v;
1183         char valuebuf[MAX_INPUTLINE];
1184
1185         if(Cmd_Argc(cmd) != 3 && Cmd_Argc(cmd) != 4)
1186         {
1187                 Con_Print("prvm_globalget <program name> <global> [<cvar>]\n");
1188                 return;
1189         }
1190
1191         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
1192                 return;
1193
1194         key = PRVM_ED_FindGlobal(prog, Cmd_Argv(cmd, 2));
1195         if(!key)
1196         {
1197                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(cmd, 2), Cmd_Argv(cmd, 1) );
1198                 goto fail;
1199         }
1200
1201         v = (prvm_eval_t *) &prog->globals.fp[key->ofs];
1202         s = PRVM_UglyValueString(prog, (etype_t)key->type, v, valuebuf, sizeof(valuebuf));
1203         if(Cmd_Argc(cmd) == 4)
1204         {
1205                 cvar_t *cvar = Cvar_FindVar(cmd->cvars, Cmd_Argv(cmd, 3), cmd->cvars_flagsmask);
1206                 if (cvar && cvar->flags & CVAR_READONLY)
1207                 {
1208                         Con_Printf("prvm_globalget: %s is read-only\n", cvar->name);
1209                         goto fail;
1210                 }
1211                 Cvar_Get(cmd->cvars, Cmd_Argv(cmd, 3), s, cmd->cvars_flagsmask, NULL);
1212         }
1213         else
1214                 Con_Printf("%s\n", s);
1215
1216 fail:
1217         ;
1218 }
1219
1220 /*
1221 =============
1222 PRVM_ED_EdictSet_f
1223
1224 Console command to set a field of a specified edict
1225 =============
1226 */
1227 static void PRVM_ED_EdictSet_f(cmd_state_t *cmd)
1228 {
1229         prvm_prog_t *prog;
1230         prvm_edict_t *ed;
1231         ddef_t *key;
1232
1233         if(Cmd_Argc(cmd) != 5)
1234         {
1235                 Con_Print("prvm_edictset <program name> <edict number> <field> <value>\n");
1236                 return;
1237         }
1238
1239         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
1240                 return;
1241
1242         ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(cmd, 2)));
1243
1244         if((key = PRVM_ED_FindField(prog, Cmd_Argv(cmd, 3))) == 0)
1245                 Con_Printf("Key %s not found !\n", Cmd_Argv(cmd, 3));
1246         else
1247                 PRVM_ED_ParseEpair(prog, ed, key, Cmd_Argv(cmd, 4), true);
1248 }
1249
1250 /*
1251 ====================
1252 PRVM_ED_ParseEdict
1253
1254 Parses an edict out of the given string, returning the new position
1255 ed should be a properly initialized empty edict.
1256 Used for initial level load and for savegames.
1257 ====================
1258 */
1259 const char *PRVM_ED_ParseEdict (prvm_prog_t *prog, const char *data, prvm_edict_t *ent)
1260 {
1261         ddef_t *key;
1262         qboolean anglehack;
1263         qboolean init;
1264         char keyname[256];
1265         size_t n;
1266
1267         init = false;
1268
1269 // go through all the dictionary pairs
1270         while (1)
1271         {
1272         // parse key
1273                 if (!COM_ParseToken_Simple(&data, false, false, true))
1274                         prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace");
1275                 if (developer_entityparsing.integer)
1276                         Con_Printf("Key: \"%s\"", com_token);
1277                 if (com_token[0] == '}')
1278                         break;
1279
1280                 // anglehack is to allow QuakeEd to write single scalar angles
1281                 // and allow them to be turned into vectors. (FIXME...)
1282                 if (!strcmp(com_token, "angle"))
1283                 {
1284                         strlcpy (com_token, "angles", sizeof(com_token));
1285                         anglehack = true;
1286                 }
1287                 else
1288                         anglehack = false;
1289
1290                 // FIXME: change light to _light to get rid of this hack
1291                 if (!strcmp(com_token, "light"))
1292                         strlcpy (com_token, "light_lev", sizeof(com_token));    // hack for single light def
1293
1294                 strlcpy (keyname, com_token, sizeof(keyname));
1295
1296                 // another hack to fix keynames with trailing spaces
1297                 n = strlen(keyname);
1298                 while (n && keyname[n-1] == ' ')
1299                 {
1300                         keyname[n-1] = 0;
1301                         n--;
1302                 }
1303
1304         // parse value
1305                 if (!COM_ParseToken_Simple(&data, false, false, true))
1306                         prog->error_cmd("PRVM_ED_ParseEdict: EOF without closing brace");
1307                 if (developer_entityparsing.integer)
1308                         Con_Printf(" \"%s\"\n", com_token);
1309
1310                 if (com_token[0] == '}')
1311                         prog->error_cmd("PRVM_ED_ParseEdict: closing brace without data");
1312
1313                 init = true;
1314
1315                 // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp)
1316                 if (!keyname[0])
1317                         continue;
1318
1319 // keynames with a leading underscore are used for utility comments,
1320 // and are immediately discarded by quake
1321                 if (keyname[0] == '_')
1322                         continue;
1323
1324                 key = PRVM_ED_FindField (prog, keyname);
1325                 if (!key)
1326                 {
1327                         Con_DPrintf("%s: '%s' is not a field\n", prog->name, keyname);
1328                         continue;
1329                 }
1330
1331                 if (anglehack)
1332                 {
1333                         char    temp[32];
1334                         strlcpy (temp, com_token, sizeof(temp));
1335                         dpsnprintf (com_token, sizeof(com_token), "0 %s 0", temp);
1336                 }
1337
1338                 if (!PRVM_ED_ParseEpair(prog, ent, key, com_token, strcmp(keyname, "wad") != 0))
1339                         prog->error_cmd("PRVM_ED_ParseEdict: parse error");
1340         }
1341
1342         if (!init) {
1343                 ent->priv.required->free = true;
1344                 ent->priv.required->freetime = realtime;
1345         }
1346
1347         return data;
1348 }
1349
1350
1351 /*
1352 ================
1353 PRVM_ED_LoadFromFile
1354
1355 The entities are directly placed in the array, rather than allocated with
1356 PRVM_ED_Alloc, because otherwise an error loading the map would have entity
1357 number references out of order.
1358
1359 Creates a server's entity / program execution context by
1360 parsing textual entity definitions out of an ent file.
1361
1362 Used for both fresh maps and savegame loads.  A fresh map would also need
1363 to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves.
1364 ================
1365 */
1366 void PRVM_ED_LoadFromFile (prvm_prog_t *prog, const char *data)
1367 {
1368         prvm_edict_t *ent;
1369         int parsed, inhibited, spawned, died;
1370         const char *funcname;
1371         mfunction_t *func;
1372         char vabuf[1024];
1373
1374         parsed = 0;
1375         inhibited = 0;
1376         spawned = 0;
1377         died = 0;
1378
1379         prvm_reuseedicts_always_allow = realtime;
1380
1381 // parse ents
1382         while (1)
1383         {
1384 // parse the opening brace
1385                 if (!COM_ParseToken_Simple(&data, false, false, true))
1386                         break;
1387                 if (com_token[0] != '{')
1388                         prog->error_cmd("PRVM_ED_LoadFromFile: %s: found %s when expecting {", prog->name, com_token);
1389
1390                 // CHANGED: this is not conform to PR_LoadFromFile
1391                 if(prog->loadintoworld)
1392                 {
1393                         prog->loadintoworld = false;
1394                         ent = PRVM_EDICT_NUM(0);
1395                 }
1396                 else
1397                         ent = PRVM_ED_Alloc(prog);
1398
1399                 // clear it
1400                 if (ent != prog->edicts)        // hack
1401                         memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t));
1402
1403                 data = PRVM_ED_ParseEdict (prog, data, ent);
1404                 parsed++;
1405
1406                 // remove the entity ?
1407                 if(!prog->load_edict(prog, ent))
1408                 {
1409                         PRVM_ED_Free(prog, ent);
1410                         inhibited++;
1411                         continue;
1412                 }
1413
1414                 if (PRVM_serverfunction(SV_OnEntityPreSpawnFunction))
1415                 {
1416                         // self = ent
1417                         PRVM_serverglobalfloat(time) = sv.time;
1418                         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1419                         prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPreSpawnFunction), "QC function SV_OnEntityPreSpawnFunction is missing");
1420                 }
1421
1422                 if(ent->priv.required->free)
1423                 {
1424                         inhibited++;
1425                         continue;
1426                 }
1427
1428 //
1429 // immediately call spawn function, but only if there is a self global and a classname
1430 //
1431                 if(!ent->priv.required->free)
1432                 {
1433                         if (!PRVM_alledictstring(ent, classname))
1434                         {
1435                                 Con_Print("No classname for:\n");
1436                                 PRVM_ED_Print(prog, ent, NULL);
1437                                 PRVM_ED_Free (prog, ent);
1438                                 continue;
1439                         }
1440
1441                         // look for the spawn function
1442                         funcname = PRVM_GetString(prog, PRVM_alledictstring(ent, classname));
1443                         func = PRVM_ED_FindFunction (prog, va(vabuf, sizeof(vabuf), "spawnfunc_%s", funcname));
1444                         if(!func)
1445                                 if(!PRVM_allglobalfloat(require_spawnfunc_prefix))
1446                                         func = PRVM_ED_FindFunction (prog, funcname);
1447
1448                         if (!func)
1449                         {
1450                                 // check for OnEntityNoSpawnFunction
1451                                 if (PRVM_serverfunction(SV_OnEntityNoSpawnFunction))
1452                                 {
1453                                         // self = ent
1454                                         PRVM_serverglobalfloat(time) = sv.time;
1455                                         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1456                                         prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityNoSpawnFunction), "QC function SV_OnEntityNoSpawnFunction is missing");
1457                                 }
1458                                 else
1459                                 {
1460                                         if (developer.integer > 0) // don't confuse non-developers with errors
1461                                         {
1462                                                 Con_Print("No spawn function for:\n");
1463                                                 PRVM_ED_Print(prog, ent, NULL);
1464                                         }
1465                                         PRVM_ED_Free (prog, ent);
1466                                         continue; // not included in "inhibited" count
1467                                 }
1468                         }
1469                         else
1470                         {
1471                                 // self = ent
1472                                 PRVM_serverglobalfloat(time) = sv.time;
1473                                 PRVM_allglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1474                                 prog->ExecuteProgram(prog, func - prog->functions, "");
1475                         }
1476                 }
1477
1478                 if(!ent->priv.required->free)
1479                 if (PRVM_serverfunction(SV_OnEntityPostSpawnFunction))
1480                 {
1481                         // self = ent
1482                         PRVM_serverglobalfloat(time) = sv.time;
1483                         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1484                         prog->ExecuteProgram(prog, PRVM_serverfunction(SV_OnEntityPostSpawnFunction), "QC function SV_OnEntityPostSpawnFunction is missing");
1485                 }
1486
1487                 spawned++;
1488                 if (ent->priv.required->free)
1489                         died++;
1490         }
1491
1492         Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", prog->name, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
1493
1494         prvm_reuseedicts_always_allow = 0;
1495 }
1496
1497 static void PRVM_FindOffsets(prvm_prog_t *prog)
1498 {
1499         // field and global searches use -1 for NULL
1500         memset(&prog->fieldoffsets, -1, sizeof(prog->fieldoffsets));
1501         memset(&prog->globaloffsets, -1, sizeof(prog->globaloffsets));
1502         // function searches use 0 for NULL
1503         memset(&prog->funcoffsets, 0, sizeof(prog->funcoffsets));
1504 #define PRVM_DECLARE_serverglobalfloat(x)
1505 #define PRVM_DECLARE_serverglobalvector(x)
1506 #define PRVM_DECLARE_serverglobalstring(x)
1507 #define PRVM_DECLARE_serverglobaledict(x)
1508 #define PRVM_DECLARE_serverglobalfunction(x)
1509 #define PRVM_DECLARE_clientglobalfloat(x)
1510 #define PRVM_DECLARE_clientglobalvector(x)
1511 #define PRVM_DECLARE_clientglobalstring(x)
1512 #define PRVM_DECLARE_clientglobaledict(x)
1513 #define PRVM_DECLARE_clientglobalfunction(x)
1514 #define PRVM_DECLARE_menuglobalfloat(x)
1515 #define PRVM_DECLARE_menuglobalvector(x)
1516 #define PRVM_DECLARE_menuglobalstring(x)
1517 #define PRVM_DECLARE_menuglobaledict(x)
1518 #define PRVM_DECLARE_menuglobalfunction(x)
1519 #define PRVM_DECLARE_serverfieldfloat(x)
1520 #define PRVM_DECLARE_serverfieldvector(x)
1521 #define PRVM_DECLARE_serverfieldstring(x)
1522 #define PRVM_DECLARE_serverfieldedict(x)
1523 #define PRVM_DECLARE_serverfieldfunction(x)
1524 #define PRVM_DECLARE_clientfieldfloat(x)
1525 #define PRVM_DECLARE_clientfieldvector(x)
1526 #define PRVM_DECLARE_clientfieldstring(x)
1527 #define PRVM_DECLARE_clientfieldedict(x)
1528 #define PRVM_DECLARE_clientfieldfunction(x)
1529 #define PRVM_DECLARE_menufieldfloat(x)
1530 #define PRVM_DECLARE_menufieldvector(x)
1531 #define PRVM_DECLARE_menufieldstring(x)
1532 #define PRVM_DECLARE_menufieldedict(x)
1533 #define PRVM_DECLARE_menufieldfunction(x)
1534 #define PRVM_DECLARE_serverfunction(x)
1535 #define PRVM_DECLARE_clientfunction(x)
1536 #define PRVM_DECLARE_menufunction(x)
1537 #define PRVM_DECLARE_field(x) prog->fieldoffsets.x = PRVM_ED_FindFieldOffset(prog, #x);
1538 #define PRVM_DECLARE_global(x) prog->globaloffsets.x = PRVM_ED_FindGlobalOffset(prog, #x);
1539 #define PRVM_DECLARE_function(x) prog->funcoffsets.x = PRVM_ED_FindFunctionOffset(prog, #x);
1540 #include "prvm_offsets.h"
1541 #undef PRVM_DECLARE_serverglobalfloat
1542 #undef PRVM_DECLARE_serverglobalvector
1543 #undef PRVM_DECLARE_serverglobalstring
1544 #undef PRVM_DECLARE_serverglobaledict
1545 #undef PRVM_DECLARE_serverglobalfunction
1546 #undef PRVM_DECLARE_clientglobalfloat
1547 #undef PRVM_DECLARE_clientglobalvector
1548 #undef PRVM_DECLARE_clientglobalstring
1549 #undef PRVM_DECLARE_clientglobaledict
1550 #undef PRVM_DECLARE_clientglobalfunction
1551 #undef PRVM_DECLARE_menuglobalfloat
1552 #undef PRVM_DECLARE_menuglobalvector
1553 #undef PRVM_DECLARE_menuglobalstring
1554 #undef PRVM_DECLARE_menuglobaledict
1555 #undef PRVM_DECLARE_menuglobalfunction
1556 #undef PRVM_DECLARE_serverfieldfloat
1557 #undef PRVM_DECLARE_serverfieldvector
1558 #undef PRVM_DECLARE_serverfieldstring
1559 #undef PRVM_DECLARE_serverfieldedict
1560 #undef PRVM_DECLARE_serverfieldfunction
1561 #undef PRVM_DECLARE_clientfieldfloat
1562 #undef PRVM_DECLARE_clientfieldvector
1563 #undef PRVM_DECLARE_clientfieldstring
1564 #undef PRVM_DECLARE_clientfieldedict
1565 #undef PRVM_DECLARE_clientfieldfunction
1566 #undef PRVM_DECLARE_menufieldfloat
1567 #undef PRVM_DECLARE_menufieldvector
1568 #undef PRVM_DECLARE_menufieldstring
1569 #undef PRVM_DECLARE_menufieldedict
1570 #undef PRVM_DECLARE_menufieldfunction
1571 #undef PRVM_DECLARE_serverfunction
1572 #undef PRVM_DECLARE_clientfunction
1573 #undef PRVM_DECLARE_menufunction
1574 #undef PRVM_DECLARE_field
1575 #undef PRVM_DECLARE_global
1576 #undef PRVM_DECLARE_function
1577 }
1578
1579 // not used
1580 /*
1581 typedef struct dpfield_s
1582 {
1583         int type;
1584         char *string;
1585 }
1586 dpfield_t;
1587
1588 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1589
1590 dpfield_t dpfields[] =
1591 {
1592 };
1593 */
1594
1595 /*
1596 ===============
1597 PRVM_ResetProg
1598 ===============
1599 */
1600
1601 #define PO_HASHSIZE 16384
1602 typedef struct po_string_s
1603 {
1604         char *key, *value;
1605         struct po_string_s *nextonhashchain;
1606 }
1607 po_string_t;
1608 typedef struct po_s
1609 {
1610         po_string_t *hashtable[PO_HASHSIZE];
1611 }
1612 po_t;
1613 static void PRVM_PO_UnparseString(char *out, const char *in, size_t outsize)
1614 {
1615         for(;;)
1616         {
1617                 switch(*in)
1618                 {
1619                         case 0:
1620                                 *out++ = 0;
1621                                 return;
1622                         case '\a': if(outsize >= 2) { *out++ = '\\'; *out++ = 'a'; outsize -= 2; } break;
1623                         case '\b': if(outsize >= 2) { *out++ = '\\'; *out++ = 'b'; outsize -= 2; } break;
1624                         case '\t': if(outsize >= 2) { *out++ = '\\'; *out++ = 't'; outsize -= 2; } break;
1625                         case '\r': if(outsize >= 2) { *out++ = '\\'; *out++ = 'r'; outsize -= 2; } break;
1626                         case '\n': if(outsize >= 2) { *out++ = '\\'; *out++ = 'n'; outsize -= 2; } break;
1627                         case '\\': if(outsize >= 2) { *out++ = '\\'; *out++ = '\\'; outsize -= 2; } break;
1628                         case '"': if(outsize >= 2) { *out++ = '\\'; *out++ = '"'; outsize -= 2; } break;
1629                         default:
1630                                 if(*in >= 0 && *in <= 0x1F)
1631                                 {
1632                                         if(outsize >= 4)
1633                                         {
1634                                                 *out++ = '\\';
1635                                                 *out++ = '0' + ((*in & 0700) >> 6);
1636                                                 *out++ = '0' + ((*in & 0070) >> 3);
1637                                                 *out++ = '0' +  (*in & 0007)      ;
1638                                                 outsize -= 4;
1639                                         }
1640                                 }
1641                                 else
1642                                 {
1643                                         if(outsize >= 1)
1644                                         {
1645                                                 *out++ = *in;
1646                                                 outsize -= 1;
1647                                         }
1648                                 }
1649                                 break;
1650                 }
1651                 ++in;
1652         }
1653 }
1654 static void PRVM_PO_ParseString(char *out, const char *in, size_t outsize)
1655 {
1656         for(;;)
1657         {
1658                 switch(*in)
1659                 {
1660                         case 0:
1661                                 *out++ = 0;
1662                                 return;
1663                         case '\\':
1664                                 ++in;
1665                                 switch(*in)
1666                                 {
1667                                         case 'a': if(outsize > 0) { *out++ = '\a'; --outsize; } break;
1668                                         case 'b': if(outsize > 0) { *out++ = '\b'; --outsize; } break;
1669                                         case 't': if(outsize > 0) { *out++ = '\t'; --outsize; } break;
1670                                         case 'r': if(outsize > 0) { *out++ = '\r'; --outsize; } break;
1671                                         case 'n': if(outsize > 0) { *out++ = '\n'; --outsize; } break;
1672                                         case '\\': if(outsize > 0) { *out++ = '\\'; --outsize; } break;
1673                                         case '"': if(outsize > 0) { *out++ = '"'; --outsize; } break;
1674                                         case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
1675                                                 if(outsize > 0) 
1676                                                         *out = *in - '0';
1677                                                 ++in;
1678                                                 if(*in >= '0' && *in <= '7')
1679                                                 {
1680                                                         if(outsize > 0)
1681                                                                 *out = (*out << 3) | (*in - '0');
1682                                                         ++in;
1683                                                 }
1684                                                 if(*in >= '0' && *in <= '7')
1685                                                 {
1686                                                         if(outsize > 0)
1687                                                                 *out = (*out << 3) | (*in - '0');
1688                                                         ++in;
1689                                                 }
1690                                                 --in;
1691                                                 if(outsize > 0)
1692                                                 {
1693                                                         ++out;
1694                                                         --outsize;
1695                                                 }
1696                                                 break;
1697                                         default:
1698                                                 if(outsize > 0) { *out++ = *in; --outsize; }
1699                                                 break;
1700                                 }
1701                                 break;
1702                         default:
1703                                 if(outsize > 0)
1704                                 {
1705                                         *out++ = *in;
1706                                         --outsize;
1707                                 }
1708                                 break;
1709                 }
1710                 ++in;
1711         }
1712 }
1713 static po_t *PRVM_PO_Load(const char *filename, const char *filename2, mempool_t *pool)
1714 {
1715         po_t *po = NULL;
1716         const char *p, *q;
1717         int mode;
1718         char inbuf[MAX_INPUTLINE];
1719         char decodedbuf[MAX_INPUTLINE];
1720         size_t decodedpos;
1721         int hashindex;
1722         po_string_t thisstr;
1723         int i;
1724
1725         for (i = 0; i < 2; ++i)
1726         {
1727                 const char *buf = (const char *)
1728                         FS_LoadFile((i > 0 ? filename : filename2), pool, true, NULL);
1729                 // first read filename2, then read filename
1730                 // so that progs.dat.de.po wins over common.de.po
1731                 // and within file, last item wins
1732
1733                 if(!buf)
1734                         continue;
1735
1736                 if (!po)
1737                 {
1738                         po = (po_t *)Mem_Alloc(pool, sizeof(*po));
1739                         memset(po, 0, sizeof(*po));
1740                 }
1741
1742                 memset(&thisstr, 0, sizeof(thisstr)); // hush compiler warning
1743
1744                 p = buf;
1745                 while(*p)
1746                 {
1747                         if(*p == '#')
1748                         {
1749                                 // skip to newline
1750                                 p = strchr(p, '\n');
1751                                 if(!p)
1752                                         break;
1753                                 ++p;
1754                                 continue;
1755                         }
1756                         if(*p == '\r' || *p == '\n')
1757                         {
1758                                 ++p;
1759                                 continue;
1760                         }
1761                         if(!strncmp(p, "msgid \"", 7))
1762                         {
1763                                 mode = 0;
1764                                 p += 6;
1765                         }
1766                         else if(!strncmp(p, "msgstr \"", 8))
1767                         {
1768                                 mode = 1;
1769                                 p += 7;
1770                         }
1771                         else
1772                         {
1773                                 p = strchr(p, '\n');
1774                                 if(!p)
1775                                         break;
1776                                 ++p;
1777                                 continue;
1778                         }
1779                         decodedpos = 0;
1780                         while(*p == '"')
1781                         {
1782                                 ++p;
1783                                 q = strchr(p, '\n');
1784                                 if(!q)
1785                                         break;
1786                                 if(*(q-1) == '\r')
1787                                         --q;
1788                                 if(*(q-1) != '"')
1789                                         break;
1790                                 if((size_t)(q - p) >= (size_t) sizeof(inbuf))
1791                                         break;
1792                                 strlcpy(inbuf, p, q - p); // not - 1, because this adds a NUL
1793                                 PRVM_PO_ParseString(decodedbuf + decodedpos, inbuf, sizeof(decodedbuf) - decodedpos);
1794                                 decodedpos += strlen(decodedbuf + decodedpos);
1795                                 if(*q == '\r')
1796                                         ++q;
1797                                 if(*q == '\n')
1798                                         ++q;
1799                                 p = q;
1800                         }
1801                         if(mode == 0)
1802                         {
1803                                 if(thisstr.key)
1804                                         Mem_Free(thisstr.key);
1805                                 thisstr.key = (char *)Mem_Alloc(pool, decodedpos + 1);
1806                                 memcpy(thisstr.key, decodedbuf, decodedpos + 1);
1807                         }
1808                         else if(decodedpos > 0 && thisstr.key) // skip empty translation results
1809                         {
1810                                 thisstr.value = (char *)Mem_Alloc(pool, decodedpos + 1);
1811                                 memcpy(thisstr.value, decodedbuf, decodedpos + 1);
1812                                 hashindex = CRC_Block((const unsigned char *) thisstr.key, strlen(thisstr.key)) % PO_HASHSIZE;
1813                                 thisstr.nextonhashchain = po->hashtable[hashindex];
1814                                 po->hashtable[hashindex] = (po_string_t *)Mem_Alloc(pool, sizeof(thisstr));
1815                                 memcpy(po->hashtable[hashindex], &thisstr, sizeof(thisstr));
1816                                 memset(&thisstr, 0, sizeof(thisstr));
1817                         }
1818                 }
1819                 
1820                 Mem_Free((char *) buf);
1821         }
1822
1823         return po;
1824 }
1825 static const char *PRVM_PO_Lookup(po_t *po, const char *str)
1826 {
1827         int hashindex = CRC_Block((const unsigned char *) str, strlen(str)) % PO_HASHSIZE;
1828         po_string_t *p = po->hashtable[hashindex];
1829         while(p)
1830         {
1831                 if(!strcmp(str, p->key))
1832                         return p->value;
1833                 p = p->nextonhashchain;
1834         }
1835         return NULL;
1836 }
1837 static void PRVM_PO_Destroy(po_t *po)
1838 {
1839         int i;
1840         for(i = 0; i < PO_HASHSIZE; ++i)
1841         {
1842                 po_string_t *p = po->hashtable[i];
1843                 while(p)
1844                 {
1845                         po_string_t *q = p;
1846                         p = p->nextonhashchain;
1847                         Mem_Free(q->key);
1848                         Mem_Free(q->value);
1849                         Mem_Free(q);
1850                 }
1851         }
1852         Mem_Free(po);
1853 }
1854
1855 void PRVM_LeakTest(prvm_prog_t *prog);
1856 void PRVM_Prog_Reset(prvm_prog_t *prog)
1857 {
1858         if (prog->loaded)
1859         {
1860                 PRVM_LeakTest(prog);
1861                 prog->reset_cmd(prog);
1862                 Mem_FreePool(&prog->progs_mempool);
1863                 if(prog->po)
1864                         PRVM_PO_Destroy((po_t *) prog->po);
1865         }
1866         memset(prog,0,sizeof(prvm_prog_t));
1867         prog->break_statement = -1;
1868         prog->watch_global_type = ev_void;
1869         prog->watch_field_type = ev_void;
1870 }
1871
1872 /*
1873 ===============
1874 PRVM_LoadLNO
1875 ===============
1876 */
1877 static void PRVM_LoadLNO( prvm_prog_t *prog, const char *progname ) {
1878         fs_offset_t filesize;
1879         unsigned char *lno;
1880         unsigned int *header;
1881         char filename[512];
1882
1883         FS_StripExtension( progname, filename, sizeof( filename ) );
1884         strlcat( filename, ".lno", sizeof( filename ) );
1885
1886         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1887         if( !lno ) {
1888                 return;
1889         }
1890
1891 /*
1892 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1893 <Spike>    SafeWrite (h, &version, sizeof(int));
1894 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1895 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1896 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1897 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1898 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1899 */
1900         if ((unsigned int)filesize < (6 + prog->progs_numstatements) * sizeof(int))
1901         {
1902                 Mem_Free(lno);
1903                 return;
1904         }
1905
1906         header = (unsigned int *) lno;
1907         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1908                 LittleLong( header[ 1 ] ) == 1 &&
1909                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs_numglobaldefs &&
1910                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs_numglobals &&
1911                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs_numfielddefs &&
1912                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs_numstatements )
1913         {
1914                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
1915                 memcpy( prog->statement_linenums, header + 6, prog->progs_numstatements * sizeof( int ) );
1916
1917                 /* gmqcc suports columnums */
1918                 if ((unsigned int)filesize > ((6 + 2 * prog->progs_numstatements) * sizeof( int )))
1919                 {
1920                         prog->statement_columnnums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof( int ) );
1921                         memcpy( prog->statement_columnnums, header + 6 + prog->progs_numstatements, prog->progs_numstatements * sizeof( int ) );
1922                 }
1923         }
1924         Mem_Free( lno );
1925 }
1926
1927 /*
1928 ===============
1929 PRVM_LoadProgs
1930 ===============
1931 */
1932 static void PRVM_UpdateBreakpoints(prvm_prog_t *prog);
1933 void PRVM_Prog_Load(prvm_prog_t *prog, const char * filename, unsigned char * data, fs_offset_t size, int numrequiredfunc, const char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, prvm_required_field_t *required_global)
1934 {
1935         int i;
1936         dprograms_t *dprograms;
1937         dstatement_t *instatements;
1938         ddef_t *infielddefs;
1939         ddef_t *inglobaldefs;
1940         int *inglobals;
1941         dfunction_t *infunctions;
1942         char *instrings;
1943         fs_offset_t filesize;
1944         int requiredglobalspace;
1945         opcode_t op;
1946         int a;
1947         int b;
1948         int c;
1949         union
1950         {
1951                 unsigned int i;
1952                 float f;
1953         }
1954         u;
1955         unsigned int d;
1956         char vabuf[1024];
1957         char vabuf2[1024];
1958         cvar_t *cvar;
1959
1960         if (prog->loaded)
1961                 prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name );
1962
1963         Host_LockSession(); // all progs can use the session cvar
1964         Crypto_LoadKeys(); // all progs might use the keys at init time
1965
1966         if (data)
1967         {
1968                 dprograms = (dprograms_t *) data;
1969                 filesize = size;
1970         }
1971         else
1972                 dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1973         if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1974                 prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name);
1975         // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file
1976
1977         prog->profiletime = Sys_DirtyTime();
1978         prog->starttime = realtime;
1979
1980         Con_DPrintf("%s programs occupy %iK.\n", prog->name, (int)(filesize/1024));
1981
1982         requiredglobalspace = 0;
1983         for (i = 0;i < numrequiredglobals;i++)
1984                 requiredglobalspace += required_global[i].type == ev_vector ? 3 : 1;
1985
1986         prog->filecrc = CRC_Block((unsigned char *)dprograms, filesize);
1987
1988 // byte swap the header
1989         prog->progs_version = LittleLong(dprograms->version);
1990         prog->progs_crc = LittleLong(dprograms->crc);
1991         if (prog->progs_version != PROG_VERSION)
1992                 prog->error_cmd("%s: %s has wrong version number (%i should be %i)", prog->name, filename, prog->progs_version, PROG_VERSION);
1993         instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements));
1994         prog->progs_numstatements = LittleLong(dprograms->numstatements);
1995         inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs));
1996         prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs);
1997         infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs));
1998         prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs);
1999         infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions));
2000         prog->progs_numfunctions = LittleLong(dprograms->numfunctions);
2001         instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings));
2002         prog->progs_numstrings = LittleLong(dprograms->numstrings);
2003         inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
2004         prog->progs_numglobals = LittleLong(dprograms->numglobals);
2005         prog->progs_entityfields = LittleLong(dprograms->entityfields);
2006
2007         prog->numstatements = prog->progs_numstatements;
2008         prog->numglobaldefs = prog->progs_numglobaldefs;
2009         prog->numfielddefs = prog->progs_numfielddefs;
2010         prog->numfunctions = prog->progs_numfunctions;
2011         prog->numstrings = prog->progs_numstrings;
2012         prog->numglobals = prog->progs_numglobals;
2013         prog->entityfields = prog->progs_entityfields;
2014
2015         if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize)
2016                 prog->error_cmd("%s: %s strings go past end of file", prog->name, filename);
2017         prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings);
2018         memcpy(prog->strings, instrings, prog->progs_numstrings);
2019         prog->stringssize = prog->progs_numstrings;
2020
2021         prog->numknownstrings = 0;
2022         prog->maxknownstrings = 0;
2023         prog->knownstrings = NULL;
2024         prog->knownstrings_freeable = NULL;
2025
2026         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
2027
2028         // we need to expand the globaldefs and fielddefs to include engine defs
2029         prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t));
2030         prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t));
2031                 // + 2 is because of an otherwise occurring overrun in RETURN instruction
2032                 // when trying to return the last or second-last global
2033                 // (RETURN always returns a vector, there is no RETURN_F instruction)
2034         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t));
2035         // we need to convert the statements to our memory format
2036         prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
2037         // allocate space for profiling statement usage
2038         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
2039         prog->explicit_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
2040         // functions need to be converted to the memory format
2041         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions);
2042
2043         for (i = 0;i < prog->progs_numfunctions;i++)
2044         {
2045                 prog->functions[i].first_statement = LittleLong(infunctions[i].first_statement);
2046                 prog->functions[i].parm_start = LittleLong(infunctions[i].parm_start);
2047                 prog->functions[i].s_name = LittleLong(infunctions[i].s_name);
2048                 prog->functions[i].s_file = LittleLong(infunctions[i].s_file);
2049                 prog->functions[i].numparms = LittleLong(infunctions[i].numparms);
2050                 prog->functions[i].locals = LittleLong(infunctions[i].locals);
2051                 memcpy(prog->functions[i].parm_size, infunctions[i].parm_size, sizeof(infunctions[i].parm_size));
2052                 if(prog->functions[i].first_statement >= prog->numstatements)
2053                         prog->error_cmd("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, prog->name);
2054                 // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size
2055         }
2056
2057         // copy the globaldefs to the new globaldefs list
2058         for (i=0 ; i<prog->numglobaldefs ; i++)
2059         {
2060                 prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type);
2061                 prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs);
2062                 prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name);
2063                 // TODO bounds check ofs, s_name
2064         }
2065
2066         // append the required globals
2067         for (i = 0;i < numrequiredglobals;i++)
2068         {
2069                 prog->globaldefs[prog->numglobaldefs].type = required_global[i].type;
2070                 prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals;
2071                 prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(prog, required_global[i].name);
2072                 if (prog->globaldefs[prog->numglobaldefs].type == ev_vector)
2073                         prog->numglobals += 3;
2074                 else
2075                         prog->numglobals++;
2076                 prog->numglobaldefs++;
2077         }
2078
2079         // copy the progs fields to the new fields list
2080         for (i = 0;i < prog->numfielddefs;i++)
2081         {
2082                 prog->fielddefs[i].type = LittleShort(infielddefs[i].type);
2083                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
2084                         prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name);
2085                 prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs);
2086                 prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name);
2087                 // TODO bounds check ofs, s_name
2088         }
2089
2090         // append the required fields
2091         for (i = 0;i < numrequiredfields;i++)
2092         {
2093                 prog->fielddefs[prog->numfielddefs].type = required_field[i].type;
2094                 prog->fielddefs[prog->numfielddefs].ofs = prog->entityfields;
2095                 prog->fielddefs[prog->numfielddefs].s_name = PRVM_SetEngineString(prog, required_field[i].name);
2096                 if (prog->fielddefs[prog->numfielddefs].type == ev_vector)
2097                         prog->entityfields += 3;
2098                 else
2099                         prog->entityfields++;
2100                 prog->numfielddefs++;
2101         }
2102
2103         // LadyHavoc: TODO: reorder globals to match engine struct
2104         // LadyHavoc: TODO: reorder fields to match engine struct
2105 #define remapglobal(index) (index)
2106 #define remapfield(index) (index)
2107
2108         // copy globals
2109         // FIXME: LadyHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type
2110         for (i = 0;i < prog->progs_numglobals;i++)
2111         {
2112                 u.i = LittleLong(inglobals[i]);
2113                 // most globals are 0, we only need to deal with the ones that are not
2114                 if (u.i)
2115                 {
2116                         d = u.i & 0xFF800000;
2117                         if ((d == 0xFF800000) || (d == 0))
2118                         {
2119                                 // Looks like an integer (expand to int64)
2120                                 prog->globals.ip[remapglobal(i)] = u.i;
2121                         }
2122                         else
2123                         {
2124                                 // Looks like a float (expand to double)
2125                                 prog->globals.fp[remapglobal(i)] = u.f;
2126                         }
2127                 }
2128         }
2129
2130         // LadyHavoc: TODO: support 32bit progs statement formats
2131         // copy, remap globals in statements, bounds check
2132         for (i = 0;i < prog->progs_numstatements;i++)
2133         {
2134                 op = (opcode_t)LittleShort(instatements[i].op);
2135                 a = (unsigned short)LittleShort(instatements[i].a);
2136                 b = (unsigned short)LittleShort(instatements[i].b);
2137                 c = (unsigned short)LittleShort(instatements[i].c);
2138                 switch (op)
2139                 {
2140                 case OP_IF:
2141                 case OP_IFNOT:
2142                         b = (short)b;
2143                         if (a >= prog->progs_numglobals || b + i < 0 || b + i >= prog->progs_numstatements)
2144                                 prog->error_cmd("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, prog->name);
2145                         prog->statements[i].op = op;
2146                         prog->statements[i].operand[0] = remapglobal(a);
2147                         prog->statements[i].operand[1] = -1;
2148                         prog->statements[i].operand[2] = -1;
2149                         prog->statements[i].jumpabsolute = i + b;
2150                         break;
2151                 case OP_GOTO:
2152                         a = (short)a;
2153                         if (a + i < 0 || a + i >= prog->progs_numstatements)
2154                                 prog->error_cmd("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, prog->name);
2155                         prog->statements[i].op = op;
2156                         prog->statements[i].operand[0] = -1;
2157                         prog->statements[i].operand[1] = -1;
2158                         prog->statements[i].operand[2] = -1;
2159                         prog->statements[i].jumpabsolute = i + a;
2160                         break;
2161                 default:
2162                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, prog->name);
2163                         break;
2164                 // global global global
2165                 case OP_ADD_F:
2166                 case OP_ADD_V:
2167                 case OP_SUB_F:
2168                 case OP_SUB_V:
2169                 case OP_MUL_F:
2170                 case OP_MUL_V:
2171                 case OP_MUL_FV:
2172                 case OP_MUL_VF:
2173                 case OP_DIV_F:
2174                 case OP_BITAND:
2175                 case OP_BITOR:
2176                 case OP_GE:
2177                 case OP_LE:
2178                 case OP_GT:
2179                 case OP_LT:
2180                 case OP_AND:
2181                 case OP_OR:
2182                 case OP_EQ_F:
2183                 case OP_EQ_V:
2184                 case OP_EQ_S:
2185                 case OP_EQ_E:
2186                 case OP_EQ_FNC:
2187                 case OP_NE_F:
2188                 case OP_NE_V:
2189                 case OP_NE_S:
2190                 case OP_NE_E:
2191                 case OP_NE_FNC:
2192                 case OP_ADDRESS:
2193                 case OP_LOAD_F:
2194                 case OP_LOAD_FLD:
2195                 case OP_LOAD_ENT:
2196                 case OP_LOAD_S:
2197                 case OP_LOAD_FNC:
2198                 case OP_LOAD_V:
2199                         if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals)
2200                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
2201                         prog->statements[i].op = op;
2202                         prog->statements[i].operand[0] = remapglobal(a);
2203                         prog->statements[i].operand[1] = remapglobal(b);
2204                         prog->statements[i].operand[2] = remapglobal(c);
2205                         prog->statements[i].jumpabsolute = -1;
2206                         break;
2207                 // global none global
2208                 case OP_NOT_F:
2209                 case OP_NOT_V:
2210                 case OP_NOT_S:
2211                 case OP_NOT_FNC:
2212                 case OP_NOT_ENT:
2213                         if (a >= prog->progs_numglobals || c >= prog->progs_numglobals)
2214                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2215                         prog->statements[i].op = op;
2216                         prog->statements[i].operand[0] = remapglobal(a);
2217                         prog->statements[i].operand[1] = -1;
2218                         prog->statements[i].operand[2] = remapglobal(c);
2219                         prog->statements[i].jumpabsolute = -1;
2220                         break;
2221                 // 2 globals
2222                 case OP_STOREP_F:
2223                 case OP_STOREP_ENT:
2224                 case OP_STOREP_FLD:
2225                 case OP_STOREP_S:
2226                 case OP_STOREP_FNC:
2227                 case OP_STORE_F:
2228                 case OP_STORE_ENT:
2229                 case OP_STORE_FLD:
2230                 case OP_STORE_S:
2231                 case OP_STORE_FNC:
2232                 case OP_STATE:
2233                 case OP_STOREP_V:
2234                 case OP_STORE_V:
2235                         if (a >= prog->progs_numglobals || b >= prog->progs_numglobals)
2236                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2237                         prog->statements[i].op = op;
2238                         prog->statements[i].operand[0] = remapglobal(a);
2239                         prog->statements[i].operand[1] = remapglobal(b);
2240                         prog->statements[i].operand[2] = -1;
2241                         prog->statements[i].jumpabsolute = -1;
2242                         break;
2243                 // 1 global
2244                 case OP_CALL0:
2245                         if ( a < prog->progs_numglobals)
2246                                 if ( prog->globals.ip[remapglobal(a)] >= 0 )
2247                                         if ( prog->globals.ip[remapglobal(a)] < prog->progs_numfunctions )
2248                                                 if ( prog->functions[prog->globals.ip[remapglobal(a)]].first_statement == -642 )
2249                                                         ++prog->numexplicitcoveragestatements;
2250                 case OP_CALL1:
2251                 case OP_CALL2:
2252                 case OP_CALL3:
2253                 case OP_CALL4:
2254                 case OP_CALL5:
2255                 case OP_CALL6:
2256                 case OP_CALL7:
2257                 case OP_CALL8:
2258                 case OP_DONE:
2259                 case OP_RETURN:
2260                         if ( a >= prog->progs_numglobals)
2261                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2262                         prog->statements[i].op = op;
2263                         prog->statements[i].operand[0] = remapglobal(a);
2264                         prog->statements[i].operand[1] = -1;
2265                         prog->statements[i].operand[2] = -1;
2266                         prog->statements[i].jumpabsolute = -1;
2267                         break;
2268                 }
2269         }
2270         if(prog->numstatements < 1)
2271         {
2272                 prog->error_cmd("PRVM_LoadProgs: empty program in %s", prog->name);
2273         }
2274         else switch(prog->statements[prog->numstatements - 1].op)
2275         {
2276                 case OP_RETURN:
2277                 case OP_GOTO:
2278                 case OP_DONE:
2279                         break;
2280                 default:
2281                         prog->error_cmd("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", prog->name);
2282                         break;
2283         }
2284
2285         // we're done with the file now
2286         if(!data)
2287                 Mem_Free(dprograms);
2288         dprograms = NULL;
2289
2290         // check required functions
2291         for(i=0 ; i < numrequiredfunc ; i++)
2292                 if(PRVM_ED_FindFunction(prog, required_func[i]) == 0)
2293                         prog->error_cmd("%s: %s not found in %s",prog->name, required_func[i], filename);
2294
2295         PRVM_LoadLNO(prog, filename);
2296
2297         PRVM_Init_Exec(prog);
2298
2299         if(*prvm_language.string)
2300         // in CSQC we really shouldn't be able to change how stuff works... sorry for now
2301         // later idea: include a list of authorized .po file checksums with the csprogs
2302         {
2303                 qboolean deftrans = prog == CLVM_prog;
2304                 const char *realfilename = (prog != CLVM_prog ? filename : csqc_progname.string);
2305                 if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method!
2306                 {
2307                         for (i=0 ; i<prog->numglobaldefs ; i++)
2308                         {
2309                                 const char *name;
2310                                 name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2311                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2312                                 if(name && !strncmp(name, "dotranslate_", 12))
2313                                 {
2314                                         deftrans = false;
2315                                         break;
2316                                 }
2317                         }
2318                 }
2319                 if(!strcmp(prvm_language.string, "dump"))
2320                 {
2321                         qfile_t *f = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.pot", realfilename), "w", false);
2322                         Con_Printf("Dumping to %s.pot\n", realfilename);
2323                         if(f)
2324                         {
2325                                 for (i=0 ; i<prog->numglobaldefs ; i++)
2326                                 {
2327                                         const char *name;
2328                                         name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2329                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2330                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2331                                         {
2332                                                 prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2333                                                 const char *value = PRVM_GetString(prog, val->string);
2334                                                 if(*value)
2335                                                 {
2336                                                         char buf[MAX_INPUTLINE];
2337                                                         PRVM_PO_UnparseString(buf, value, sizeof(buf));
2338                                                         FS_Printf(f, "msgid \"%s\"\nmsgstr \"\"\n\n", buf);
2339                                                 }
2340                                         }
2341                                 }
2342                                 FS_Close(f);
2343                         }
2344                 }
2345                 else
2346                 {
2347                         po_t *po = PRVM_PO_Load(
2348                                         va(vabuf, sizeof(vabuf), "%s.%s.po", realfilename, prvm_language.string),
2349                                         va(vabuf2, sizeof(vabuf2), "common.%s.po", prvm_language.string),
2350                                         prog->progs_mempool);
2351                         if(po)
2352                         {
2353                                 for (i=0 ; i<prog->numglobaldefs ; i++)
2354                                 {
2355                                         const char *name;
2356                                         name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2357                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2358                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2359                                         {
2360                                                 prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2361                                                 const char *value = PRVM_GetString(prog, val->string);
2362                                                 if(*value)
2363                                                 {
2364                                                         value = PRVM_PO_Lookup(po, value);
2365                                                         if(value)
2366                                                                 val->string = PRVM_SetEngineString(prog, value);
2367                                                 }
2368                                         }
2369                                 }
2370                         }
2371                 }
2372         }
2373
2374         for (cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
2375                 cvar->globaldefindex[prog - prvm_prog_list] = -1;
2376
2377         for (i=0 ; i<prog->numglobaldefs ; i++)
2378         {
2379                 const char *name;
2380                 name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2381                 //Con_Printf("found var %s\n", name);
2382                 if(name
2383                         && !strncmp(name, "autocvar_", 9)
2384                         && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
2385                 )
2386                 {
2387                         prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2388                         cvar = Cvar_FindVar(prog->console_cmd->cvars, name + 9, prog->console_cmd->cvars_flagsmask);
2389                         //Con_Printf("PRVM_LoadProgs: autocvar global %s in %s, processing...\n", name, prog->name);
2390                         if(!cvar)
2391                         {
2392                                 const char *value;
2393                                 char buf[64];
2394                                 Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, prog->name);
2395                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2396                                 {
2397                                         case ev_float:
2398                                                 if((float)((int)(val->_float)) == val->_float)
2399                                                         dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float));
2400                                                 else
2401                                                         dpsnprintf(buf, sizeof(buf), "%.9g", val->_float);
2402                                                 value = buf;
2403                                                 break;
2404                                         case ev_vector:
2405                                                 dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf;
2406                                                 break;
2407                                         case ev_string:
2408                                                 value = PRVM_GetString(prog, val->string);
2409                                                 break;
2410                                         default:
2411                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
2412                                                 goto fail;
2413                                 }
2414                                 cvar = Cvar_Get(prog->console_cmd->cvars, name + 9, value, prog->console_cmd->cvars_flagsmask, NULL);
2415                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2416                                 {
2417                                         val->string = PRVM_SetEngineString(prog, cvar->string);
2418                                         cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
2419                                 }
2420                                 if(!cvar)
2421                                         prog->error_cmd("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, prog->name);
2422                                 cvar->globaldefindex[prog - prvm_prog_list] = i;
2423                         }
2424                         else if((cvar->flags & CVAR_PRIVATE) == 0)
2425                         {
2426                                 // MUST BE SYNCED WITH cvar.c Cvar_Set
2427                                 int j;
2428                                 const char *s;
2429                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2430                                 {
2431                                         case ev_float:
2432                                                 val->_float = cvar->value;
2433                                                 break;
2434                                         case ev_vector:
2435                                                 s = cvar->string;
2436                                                 VectorClear(val->vector);
2437                                                 for (j = 0;j < 3;j++)
2438                                                 {
2439                                                         while (*s && ISWHITESPACE(*s))
2440                                                                 s++;
2441                                                         if (!*s)
2442                                                                 break;
2443                                                         val->vector[j] = atof(s);
2444                                                         while (!ISWHITESPACE(*s))
2445                                                                 s++;
2446                                                         if (!*s)
2447                                                                 break;
2448                                                 }
2449                                                 break;
2450                                         case ev_string:
2451                                                 val->string = PRVM_SetEngineString(prog, cvar->string);
2452                                                 cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
2453                                                 break;
2454                                         default:
2455                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
2456                                                 goto fail;
2457                                 }
2458                                 cvar->globaldefindex[prog - prvm_prog_list] = i;
2459                         }
2460                         else
2461                                 Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, prog->name);
2462                 }
2463 fail:
2464                 ;
2465         }
2466
2467         prog->loaded = TRUE;
2468
2469         PRVM_UpdateBreakpoints(prog);
2470
2471         // set flags & ddef_ts in prog
2472
2473         prog->flag = 0;
2474
2475         PRVM_FindOffsets(prog);
2476
2477         prog->init_cmd(prog);
2478
2479         // init mempools
2480         PRVM_MEM_Alloc(prog);
2481
2482         // Inittime is at least the time when this function finished. However,
2483         // later events may bump it.
2484         prog->inittime = realtime;
2485 }
2486
2487
2488 static void PRVM_Fields_f(cmd_state_t *cmd)
2489 {
2490         prvm_prog_t *prog;
2491         int i, j, ednum, used, usedamount;
2492         int *counts;
2493         char tempstring[MAX_INPUTLINE], tempstring2[260];
2494         const char *name;
2495         prvm_edict_t *ed;
2496         ddef_t *d;
2497         prvm_eval_t *val;
2498
2499         // TODO
2500         /*
2501         if (!sv.active)
2502         {
2503                 Con_Print("no progs loaded\n");
2504                 return;
2505         }
2506         */
2507
2508         if(Cmd_Argc(cmd) != 2)
2509         {
2510                 Con_Print("prvm_fields <program name>\n");
2511                 return;
2512         }
2513
2514         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2515                 return;
2516
2517         counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int));
2518         for (ednum = 0;ednum < prog->max_edicts;ednum++)
2519         {
2520                 ed = PRVM_EDICT_NUM(ednum);
2521                 if (ed->priv.required->free)
2522                         continue;
2523                 for (i = 1;i < prog->numfielddefs;i++)
2524                 {
2525                         d = &prog->fielddefs[i];
2526                         name = PRVM_GetString(prog, d->s_name);
2527                         if (name[strlen(name)-2] == '_')
2528                                 continue;       // skip _x, _y, _z vars
2529                         val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
2530                         // if the value is still all 0, skip the field
2531                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
2532                         {
2533                                 if (val->ivector[j])
2534                                 {
2535                                         counts[i]++;
2536                                         break;
2537                                 }
2538                         }
2539                 }
2540         }
2541         used = 0;
2542         usedamount = 0;
2543         tempstring[0] = 0;
2544         for (i = 0;i < prog->numfielddefs;i++)
2545         {
2546                 d = &prog->fielddefs[i];
2547                 name = PRVM_GetString(prog, d->s_name);
2548                 if (name[strlen(name)-2] == '_')
2549                         continue;       // skip _x, _y, _z vars
2550                 switch(d->type & ~DEF_SAVEGLOBAL)
2551                 {
2552                 case ev_string:
2553                         strlcat(tempstring, "string   ", sizeof(tempstring));
2554                         break;
2555                 case ev_entity:
2556                         strlcat(tempstring, "entity   ", sizeof(tempstring));
2557                         break;
2558                 case ev_function:
2559                         strlcat(tempstring, "function ", sizeof(tempstring));
2560                         break;
2561                 case ev_field:
2562                         strlcat(tempstring, "field    ", sizeof(tempstring));
2563                         break;
2564                 case ev_void:
2565                         strlcat(tempstring, "void     ", sizeof(tempstring));
2566                         break;
2567                 case ev_float:
2568                         strlcat(tempstring, "float    ", sizeof(tempstring));
2569                         break;
2570                 case ev_vector:
2571                         strlcat(tempstring, "vector   ", sizeof(tempstring));
2572                         break;
2573                 case ev_pointer:
2574                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
2575                         break;
2576                 default:
2577                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
2578                         strlcat(tempstring, tempstring2, sizeof(tempstring));
2579                         break;
2580                 }
2581                 if (strlen(name) > sizeof(tempstring2)-4)
2582                 {
2583                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
2584                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
2585                         tempstring2[sizeof(tempstring2)-1] = 0;
2586                         name = tempstring2;
2587                 }
2588                 strlcat(tempstring, name, sizeof(tempstring));
2589                 for (j = (int)strlen(name);j < 25;j++)
2590                         strlcat(tempstring, " ", sizeof(tempstring));
2591                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
2592                 strlcat(tempstring, tempstring2, sizeof(tempstring));
2593                 strlcat(tempstring, "\n", sizeof(tempstring));
2594                 if (strlen(tempstring) >= sizeof(tempstring)/2)
2595                 {
2596                         Con_Print(tempstring);
2597                         tempstring[0] = 0;
2598                 }
2599                 if (counts[i])
2600                 {
2601                         used++;
2602                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
2603                 }
2604         }
2605         Mem_Free(counts);
2606         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", prog->name, prog->entityfields, used, prog->entityfields * 4, usedamount * 4, prog->max_edicts, prog->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts);
2607 }
2608
2609 static void PRVM_Globals_f(cmd_state_t *cmd)
2610 {
2611         prvm_prog_t *prog;
2612         int i;
2613         const char *wildcard;
2614         int numculled;
2615                 numculled = 0;
2616         // TODO
2617         /*if (!sv.active)
2618         {
2619                 Con_Print("no progs loaded\n");
2620                 return;
2621         }*/
2622         if(Cmd_Argc (cmd) < 2 || Cmd_Argc(cmd) > 3)
2623         {
2624                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
2625                 return;
2626         }
2627
2628         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2629                 return;
2630
2631         if( Cmd_Argc(cmd) == 3)
2632                 wildcard = Cmd_Argv(cmd, 2);
2633         else
2634                 wildcard = NULL;
2635
2636         Con_Printf("%s :", prog->name);
2637
2638         for (i = 0;i < prog->numglobaldefs;i++)
2639         {
2640                 if(wildcard)
2641                         if( !matchpattern( PRVM_GetString(prog, prog->globaldefs[i].s_name), wildcard, 1) )
2642                         {
2643                                 numculled++;
2644                                 continue;
2645                         }
2646                 Con_Printf("%s\n", PRVM_GetString(prog, prog->globaldefs[i].s_name));
2647         }
2648         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->numglobals, numculled, prog->numglobals * 4);
2649 }
2650
2651 /*
2652 ===============
2653 PRVM_Global
2654 ===============
2655 */
2656 static void PRVM_Global_f(cmd_state_t *cmd)
2657 {
2658         prvm_prog_t *prog;
2659         ddef_t *global;
2660         char valuebuf[MAX_INPUTLINE];
2661         if( Cmd_Argc(cmd) != 3 ) {
2662                 Con_Printf( "prvm_global <program name> <global name>\n" );
2663                 return;
2664         }
2665
2666         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2667                 return;
2668
2669         global = PRVM_ED_FindGlobal( prog, Cmd_Argv(cmd, 2) );
2670         if( !global )
2671                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(cmd, 2), Cmd_Argv(cmd, 1) );
2672         else
2673                 Con_Printf( "%s: %s\n", Cmd_Argv(cmd, 2), PRVM_ValueString( prog, (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs), valuebuf, sizeof(valuebuf) ) );
2674 }
2675
2676 /*
2677 ===============
2678 PRVM_GlobalSet
2679 ===============
2680 */
2681 static void PRVM_GlobalSet_f(cmd_state_t *cmd)
2682 {
2683         prvm_prog_t *prog;
2684         ddef_t *global;
2685         if( Cmd_Argc(cmd) != 4 ) {
2686                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2687                 return;
2688         }
2689
2690         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2691                 return;
2692
2693         global = PRVM_ED_FindGlobal( prog, Cmd_Argv(cmd, 2) );
2694         if( !global )
2695                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(cmd, 2), Cmd_Argv(cmd, 1) );
2696         else
2697                 PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(cmd, 3), true );
2698 }
2699
2700 /*
2701 ======================
2702 Break- and Watchpoints
2703 ======================
2704 */
2705 typedef struct
2706 {
2707         char break_statement[256];
2708         char watch_global[256];
2709         int watch_edict;
2710         char watch_field[256];
2711 }
2712 debug_data_t;
2713 static debug_data_t debug_data[PRVM_PROG_MAX];
2714
2715 void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text)
2716 {
2717         char vabuf[1024];
2718         Con_Printf("PRVM_Breakpoint: %s\n", text);
2719         PRVM_PrintState(prog, stack_index);
2720         if (prvm_breakpointdump.integer)
2721                 Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name));
2722 }
2723
2724 void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n)
2725 {
2726         size_t sz = sizeof(prvm_vec_t) * ((type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2727         if (memcmp(o, n, sz))
2728         {
2729                 char buf[1024];
2730                 char valuebuf_o[128];
2731                 char valuebuf_n[128];
2732                 PRVM_UglyValueString(prog, type, o, valuebuf_o, sizeof(valuebuf_o));
2733                 PRVM_UglyValueString(prog, type, n, valuebuf_n, sizeof(valuebuf_n));
2734                 dpsnprintf(buf, sizeof(buf), "%s: %s -> %s", text, valuebuf_o, valuebuf_n);
2735                 PRVM_Breakpoint(prog, stack_index, buf);
2736                 memcpy(o, n, sz);
2737         }
2738 }
2739
2740 static void PRVM_UpdateBreakpoints(prvm_prog_t *prog)
2741 {
2742         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2743         if (!prog->loaded)
2744                 return;
2745         if (debug->break_statement[0])
2746         {
2747                 if (debug->break_statement[0] >= '0' && debug->break_statement[0] <= '9')
2748                 {
2749                         prog->break_statement = atoi(debug->break_statement);
2750                         prog->break_stack_index = 0;
2751                 }
2752                 else
2753                 {
2754                         mfunction_t *func;
2755                         func = PRVM_ED_FindFunction (prog, debug->break_statement);
2756                         if (!func)
2757                         {
2758                                 Con_Printf("%s progs: no function or statement named %s to break on!\n", prog->name, debug->break_statement);
2759                                 prog->break_statement = -1;
2760                         }
2761                         else
2762                         {
2763                                 prog->break_statement = func->first_statement;
2764                                 prog->break_stack_index = 1;
2765                         }
2766                 }
2767                 if (prog->break_statement >= -1)
2768                         Con_Printf("%s progs: breakpoint is at statement %d\n", prog->name, prog->break_statement);
2769         }
2770         else
2771                 prog->break_statement = -1;
2772
2773         if (debug->watch_global[0])
2774         {
2775                 ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global );
2776                 if( !global )
2777                 {
2778                         Con_Printf( "%s progs: no global named '%s' to watch!\n", prog->name, debug->watch_global );
2779                         prog->watch_global_type = ev_void;
2780                 }
2781                 else
2782                 {
2783                         size_t sz = sizeof(prvm_vec_t) * ((global->type  & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2784                         prog->watch_global = global->ofs;
2785                         prog->watch_global_type = (etype_t)global->type;
2786                         memcpy(&prog->watch_global_value, PRVM_GLOBALFIELDVALUE(prog->watch_global), sz);
2787                 }
2788                 if (prog->watch_global_type != ev_void)
2789                         Con_Printf("%s progs: global watchpoint is at global index %d\n", prog->name, prog->watch_global);
2790         }
2791         else
2792                 prog->watch_global_type = ev_void;
2793
2794         if (debug->watch_field[0])
2795         {
2796                 ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field );
2797                 if( !field )
2798                 {
2799                         Con_Printf( "%s progs: no field named '%s' to watch!\n", prog->name, debug->watch_field );
2800                         prog->watch_field_type = ev_void;
2801                 }
2802                 else
2803                 {
2804                         size_t sz = sizeof(prvm_vec_t) * ((field->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2805                         prog->watch_edict = debug->watch_edict;
2806                         prog->watch_field = field->ofs;
2807                         prog->watch_field_type = (etype_t)field->type;
2808                         if (prog->watch_edict < prog->num_edicts)
2809                                 memcpy(&prog->watch_edictfield_value, PRVM_EDICTFIELDVALUE(PRVM_EDICT_NUM(prog->watch_edict), prog->watch_field), sz);
2810                         else
2811                                 memset(&prog->watch_edictfield_value, 0, sz);
2812                 }
2813                 if (prog->watch_edict != ev_void)
2814                         Con_Printf("%s progs: edict field watchpoint is at edict %d field index %d\n", prog->name, prog->watch_edict, prog->watch_field);
2815         }
2816         else
2817                 prog->watch_field_type = ev_void;
2818 }
2819
2820 static void PRVM_Breakpoint_f(cmd_state_t *cmd)
2821 {
2822         prvm_prog_t *prog;
2823
2824         if( Cmd_Argc(cmd) == 2 ) {
2825                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2826                         return;
2827                 {
2828                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2829                         debug->break_statement[0] = 0;
2830                 }
2831                 PRVM_UpdateBreakpoints(prog);
2832                 return;
2833         }
2834         if( Cmd_Argc(cmd) != 3 ) {
2835                 Con_Printf( "prvm_breakpoint <program name> <function name | statement>\n" );
2836                 return;
2837         }
2838
2839         if (!(prog = PRVM_ProgFromString(Cmd_Argv(cmd, 1))))
2840                 return;
2841
2842         {
2843                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2844                 strlcpy(debug->break_statement, Cmd_Argv(cmd, 2), sizeof(debug->break_statement));
2845         }
2846         PRVM_UpdateBreakpoints(prog);
2847 }
2848
2849 static void PRVM_GlobalWatchpoint_f(cmd_state_t *cmd)
2850 {
2851         prvm_prog_t *prog;
2852
2853         if( Cmd_Argc(cmd) == 2 ) {
2854                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2855                         return;
2856                 {
2857                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2858                         debug->watch_global[0] = 0;
2859                 }
2860                 PRVM_UpdateBreakpoints(prog);
2861                 return;
2862         }
2863         if( Cmd_Argc(cmd) != 3 ) {
2864                 Con_Printf( "prvm_globalwatchpoint <program name> <global name>\n" );
2865                 return;
2866         }
2867
2868         if (!(prog = PRVM_ProgFromString(Cmd_Argv(cmd, 1))))
2869                 return;
2870
2871         {
2872                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2873                 strlcpy(debug->watch_global, Cmd_Argv(cmd, 2), sizeof(debug->watch_global));
2874         }
2875         PRVM_UpdateBreakpoints(prog);
2876 }
2877
2878 static void PRVM_EdictWatchpoint_f(cmd_state_t *cmd)
2879 {
2880         prvm_prog_t *prog;
2881
2882         if( Cmd_Argc(cmd) == 2 ) {
2883                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(cmd, 1))))
2884                         return;
2885                 {
2886                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2887                         debug->watch_field[0] = 0;
2888                 }
2889                 PRVM_UpdateBreakpoints(prog);
2890                 return;
2891         }
2892         if( Cmd_Argc(cmd) != 4 ) {
2893                 Con_Printf( "prvm_edictwatchpoint <program name> <edict number> <field name>\n" );
2894                 return;
2895         }
2896
2897         if (!(prog = PRVM_ProgFromString(Cmd_Argv(cmd, 1))))
2898                 return;
2899
2900         {
2901                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2902                 debug->watch_edict = atoi(Cmd_Argv(cmd, 2));
2903                 strlcpy(debug->watch_field, Cmd_Argv(cmd, 3), sizeof(debug->watch_field));
2904         }
2905         PRVM_UpdateBreakpoints(prog);
2906 }
2907
2908 /*
2909 ===============
2910 PRVM_Init
2911 ===============
2912 */
2913 void PRVM_Init (void)
2914 {
2915         Cmd_AddCommand(&cmd_client, "prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2916         Cmd_AddCommand(&cmd_client, "prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2917         Cmd_AddCommand(&cmd_client, "prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2918         Cmd_AddCommand(&cmd_client, "prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2919         Cmd_AddCommand(&cmd_client, "prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls");
2920         Cmd_AddCommand(&cmd_client, "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)");
2921         Cmd_AddCommand(&cmd_client, "prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
2922         Cmd_AddCommand(&cmd_client, "prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2923         Cmd_AddCommand(&cmd_client, "prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2924         Cmd_AddCommand(&cmd_client, "prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2925         Cmd_AddCommand(&cmd_client, "prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
2926         Cmd_AddCommand(&cmd_client, "prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console");
2927         Cmd_AddCommand(&cmd_client, "prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console");
2928         Cmd_AddCommand(&cmd_client, "prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2929         Cmd_AddCommand(&cmd_client, "cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2930         Cmd_AddCommand(&cmd_client, "menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2931         Cmd_AddCommand(&cmd_client, "sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2932         Cmd_AddCommand(&cmd_client, "prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint");
2933         Cmd_AddCommand(&cmd_client, "prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
2934         Cmd_AddCommand(&cmd_client, "prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
2935
2936         Cmd_AddCommand(&cmd_server, "prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2937         Cmd_AddCommand(&cmd_server, "prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2938         Cmd_AddCommand(&cmd_server, "prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2939         Cmd_AddCommand(&cmd_server, "prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2940         Cmd_AddCommand(&cmd_server, "prvm_childprofile", PRVM_ChildProfile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu), sorted by time taken in function with child calls");
2941         Cmd_AddCommand(&cmd_server, "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)");
2942         Cmd_AddCommand(&cmd_server, "prvm_fields", PRVM_Fields_f, "prints usage statistics on properties (how many entities have non-zero values) in the selected VM (server, client, menu)");
2943         Cmd_AddCommand(&cmd_server, "prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2944         Cmd_AddCommand(&cmd_server, "prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2945         Cmd_AddCommand(&cmd_server, "prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2946         Cmd_AddCommand(&cmd_server, "prvm_edictset", PRVM_ED_EdictSet_f, "changes value of a specified property of a specified entity in the selected VM (server, client, menu)");
2947         Cmd_AddCommand(&cmd_server, "prvm_edictget", PRVM_ED_EdictGet_f, "retrieves the value of a specified property of a specified entity in the selected VM (server, client menu) into a cvar or to the console");
2948         Cmd_AddCommand(&cmd_server, "prvm_globalget", PRVM_ED_GlobalGet_f, "retrieves the value of a specified global variable in the selected VM (server, client menu) into a cvar or to the console");
2949         Cmd_AddCommand(&cmd_server, "prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2950         Cmd_AddCommand(&cmd_server, "cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2951         Cmd_AddCommand(&cmd_server, "menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2952         Cmd_AddCommand(&cmd_server, "sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2953         Cmd_AddCommand(&cmd_server, "prvm_breakpoint", PRVM_Breakpoint_f, "marks a statement or function as breakpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear breakpoint");
2954         Cmd_AddCommand(&cmd_server, "prvm_globalwatchpoint", PRVM_GlobalWatchpoint_f, "marks a global as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
2955         Cmd_AddCommand(&cmd_server, "prvm_edictwatchpoint", PRVM_EdictWatchpoint_f, "marks an entity field as watchpoint (when this is executed, a stack trace is printed); to actually halt and investigate state, combine this with a gdb breakpoint on PRVM_Breakpoint, or with prvm_breakpointdump; run with just progs name to clear watchpoint");
2956
2957         Cvar_RegisterVariable (&prvm_language);
2958         Cvar_RegisterVariable (&prvm_traceqc);
2959         Cvar_RegisterVariable (&prvm_statementprofiling);
2960         Cvar_RegisterVariable (&prvm_timeprofiling);
2961         Cvar_RegisterVariable (&prvm_coverage);
2962         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2963         Cvar_RegisterVariable (&prvm_leaktest);
2964         Cvar_RegisterVariable (&prvm_leaktest_follow_targetname);
2965         Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2966         Cvar_RegisterVariable (&prvm_errordump);
2967         Cvar_RegisterVariable (&prvm_breakpointdump);
2968         Cvar_RegisterVariable (&prvm_reuseedicts_startuptime);
2969         Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe);
2970
2971         // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
2972         prvm_runawaycheck = !COM_CheckParm("-norunaway");
2973
2974         //VM_Cmd_Init();
2975 }
2976
2977 /*
2978 ===============
2979 PRVM_InitProg
2980 ===============
2981 */
2982 void PRVM_Prog_Init(prvm_prog_t *prog, cmd_state_t *cmd)
2983 {
2984         PRVM_Prog_Reset(prog);
2985         prog->leaktest_active = prvm_leaktest.integer != 0;
2986         prog->console_cmd = cmd;
2987 }
2988
2989 // LadyHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2990 unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
2991 {
2992         prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline);
2993         return 0;
2994 }
2995
2996 #define PRVM_KNOWNSTRINGBASE 0x40000000
2997
2998 const char *PRVM_GetString(prvm_prog_t *prog, int num)
2999 {
3000         if (num < 0)
3001         {
3002                 // invalid
3003                 VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num);
3004                 return "";
3005         }
3006         else if (num < prog->stringssize)
3007         {
3008                 // constant string from progs.dat
3009                 return prog->strings + num;
3010         }
3011         else if (num <= prog->stringssize + prog->tempstringsbuf.maxsize)
3012         {
3013                 // tempstring returned by engine to QC (becomes invalid after returning to engine)
3014                 num -= prog->stringssize;
3015                 if (num < prog->tempstringsbuf.cursize)
3016                         return (char *)prog->tempstringsbuf.data + num;
3017                 else
3018                 {
3019                         VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize);
3020                         return "";
3021                 }
3022         }
3023         else if (num & PRVM_KNOWNSTRINGBASE)
3024         {
3025                 // allocated string
3026                 num = num - PRVM_KNOWNSTRINGBASE;
3027                 if (num >= 0 && num < prog->numknownstrings)
3028                 {
3029                         if (!prog->knownstrings[num])
3030                         {
3031                                 VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
3032                                 return "";
3033                         }
3034                         return prog->knownstrings[num];
3035                 }
3036                 else
3037                 {
3038                         VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
3039                         return "";
3040                 }
3041         }
3042         else
3043         {
3044                 // invalid string offset
3045                 VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
3046                 return "";
3047         }
3048 }
3049
3050 const char *PRVM_ChangeEngineString(prvm_prog_t *prog, int i, const char *s)
3051 {
3052         const char *old;
3053         i = i - PRVM_KNOWNSTRINGBASE;
3054         if(i < 0 || i >= prog->numknownstrings)
3055                 prog->error_cmd("PRVM_ChangeEngineString: s is not an engine string");
3056         old = prog->knownstrings[i];
3057         prog->knownstrings[i] = s;
3058         return old;
3059 }
3060
3061 int PRVM_SetEngineString(prvm_prog_t *prog, const char *s)
3062 {
3063         int i;
3064         if (!s)
3065                 return 0;
3066         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
3067                 prog->error_cmd("PRVM_SetEngineString: s in prog->strings area");
3068         // if it's in the tempstrings area, use a reserved range
3069         // (otherwise we'd get millions of useless string offsets cluttering the database)
3070         if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize)
3071                 return prog->stringssize + (s - (char *)prog->tempstringsbuf.data);
3072         // see if it's a known string address
3073         for (i = 0;i < prog->numknownstrings;i++)
3074                 if (prog->knownstrings[i] == s)
3075                         return PRVM_KNOWNSTRINGBASE + i;
3076         // new unknown engine string
3077         if (developer_insane.integer)
3078                 Con_DPrintf("new engine string %p = \"%s\"\n", s, s);
3079         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
3080                 if (!prog->knownstrings[i])
3081                         break;
3082         if (i >= prog->numknownstrings)
3083         {
3084                 if (i >= prog->maxknownstrings)
3085                 {
3086                         const char **oldstrings = prog->knownstrings;
3087                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
3088                         const char **oldstrings_origin = prog->knownstrings_origin;
3089                         prog->maxknownstrings += 128;
3090                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3091                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
3092                         if(prog->leaktest_active)
3093                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3094                         if (prog->numknownstrings)
3095                         {
3096                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
3097                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
3098                                 if(prog->leaktest_active)
3099                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
3100                         }
3101                 }
3102                 prog->numknownstrings++;
3103         }
3104         prog->firstfreeknownstring = i + 1;
3105         prog->knownstrings[i] = s;
3106         prog->knownstrings_freeable[i] = false;
3107         if(prog->leaktest_active)
3108                 prog->knownstrings_origin[i] = NULL;
3109         return PRVM_KNOWNSTRINGBASE + i;
3110 }
3111
3112 // temp string handling
3113
3114 // all tempstrings go into this buffer consecutively, and it is reset
3115 // whenever PRVM_ExecuteProgram returns to the engine
3116 // (technically each PRVM_ExecuteProgram call saves the cursize value and
3117 //  restores it on return, so multiple recursive calls can share the same
3118 //  buffer)
3119 // the buffer size is automatically grown as needed
3120
3121 int PRVM_SetTempString(prvm_prog_t *prog, const char *s)
3122 {
3123         int size;
3124         char *t;
3125         if (!s)
3126                 return 0;
3127         size = (int)strlen(s) + 1;
3128         if (developer_insane.integer)
3129                 Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", prog->tempstringsbuf.cursize, size);
3130         if (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
3131         {
3132                 sizebuf_t old = prog->tempstringsbuf;
3133                 if (prog->tempstringsbuf.cursize + size >= 1<<28)
3134                         prog->error_cmd("PRVM_SetTempString: ran out of tempstring memory!  (refusing to grow tempstring buffer over 256MB, cursize %i, size %i)\n", prog->tempstringsbuf.cursize, size);
3135                 prog->tempstringsbuf.maxsize = max(prog->tempstringsbuf.maxsize, 65536);
3136                 while (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
3137                         prog->tempstringsbuf.maxsize *= 2;
3138                 if (prog->tempstringsbuf.maxsize != old.maxsize || prog->tempstringsbuf.data == NULL)
3139                 {
3140                         Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, prog->tempstringsbuf.maxsize/1024);
3141                         prog->tempstringsbuf.data = (unsigned char *) Mem_Alloc(prog->progs_mempool, prog->tempstringsbuf.maxsize);
3142                         if (old.data)
3143                         {
3144                                 if (old.cursize)
3145                                         memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
3146                                 Mem_Free(old.data);
3147                         }
3148                 }
3149         }
3150         t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize;
3151         memcpy(t, s, size);
3152         prog->tempstringsbuf.cursize += size;
3153         return PRVM_SetEngineString(prog, t);
3154 }
3155
3156 int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer)
3157 {
3158         int i;
3159         if (!bufferlength)
3160         {
3161                 if (pointer)
3162                         *pointer = NULL;
3163                 return 0;
3164         }
3165         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
3166                 if (!prog->knownstrings[i])
3167                         break;
3168         if (i >= prog->numknownstrings)
3169         {
3170                 if (i >= prog->maxknownstrings)
3171                 {
3172                         const char **oldstrings = prog->knownstrings;
3173                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
3174                         const char **oldstrings_origin = prog->knownstrings_origin;
3175                         prog->maxknownstrings += 128;
3176                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3177                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
3178                         if(prog->leaktest_active)
3179                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3180                         if (prog->numknownstrings)
3181                         {
3182                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
3183                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
3184                                 if(prog->leaktest_active)
3185                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
3186                         }
3187                         if (oldstrings)
3188                                 Mem_Free((char **)oldstrings);
3189                         if (oldstrings_freeable)
3190                                 Mem_Free((unsigned char *)oldstrings_freeable);
3191                         if (oldstrings_origin)
3192                                 Mem_Free((char **)oldstrings_origin);
3193                 }
3194                 prog->numknownstrings++;
3195         }
3196         prog->firstfreeknownstring = i + 1;
3197         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
3198         prog->knownstrings_freeable[i] = true;
3199         if(prog->leaktest_active)
3200                 prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog);
3201         if (pointer)
3202                 *pointer = (char *)(prog->knownstrings[i]);
3203         return PRVM_KNOWNSTRINGBASE + i;
3204 }
3205
3206 void PRVM_FreeString(prvm_prog_t *prog, int num)
3207 {
3208         if (num == 0)
3209                 prog->error_cmd("PRVM_FreeString: attempt to free a NULL string");
3210         else if (num >= 0 && num < prog->stringssize)
3211                 prog->error_cmd("PRVM_FreeString: attempt to free a constant string");
3212         else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings)
3213         {
3214                 num = num - PRVM_KNOWNSTRINGBASE;
3215                 if (!prog->knownstrings[num])
3216                         prog->error_cmd("PRVM_FreeString: attempt to free a non-existent or already freed string");
3217                 if (!prog->knownstrings_freeable[num])
3218                         prog->error_cmd("PRVM_FreeString: attempt to free a string owned by the engine");
3219                 PRVM_Free((char *)prog->knownstrings[num]);
3220                 if(prog->leaktest_active)
3221                         if(prog->knownstrings_origin[num])
3222                                 PRVM_Free((char *)prog->knownstrings_origin[num]);
3223                 prog->knownstrings[num] = NULL;
3224                 prog->knownstrings_freeable[num] = false;
3225                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
3226         }
3227         else
3228                 prog->error_cmd("PRVM_FreeString: invalid string offset %i", num);
3229 }
3230
3231 static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string)
3232 {
3233         int i, j;
3234
3235         for (i = 0;i < prog->numglobaldefs;i++)
3236         {
3237                 ddef_t *d = &prog->globaldefs[i];
3238                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3239                         continue;
3240                 if(string == PRVM_GLOBALFIELDSTRING(d->ofs))
3241                         return true;
3242         }
3243
3244         for(j = 0; j < prog->num_edicts; ++j)
3245         {
3246                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3247                 if (ed->priv.required->free)
3248                         continue;
3249                 for (i=0; i<prog->numfielddefs; ++i)
3250                 {
3251                         ddef_t *d = &prog->fielddefs[i];
3252                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3253                                 continue;
3254                         if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs))
3255                                 return true;
3256                 }
3257         }
3258
3259         return false;
3260 }
3261
3262 static qboolean PRVM_IsEdictRelevant(prvm_prog_t *prog, prvm_edict_t *edict)
3263 {
3264         char vabuf[1024];
3265         char vabuf2[1024];
3266         if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
3267                 return true; // world or clients
3268         if (edict->priv.required->freetime <= prog->inittime)
3269                 return true; // created during startup
3270         if (prog == SVVM_prog)
3271         {
3272                 if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger?
3273                         return true;
3274                 if(PRVM_serveredictfloat(edict, modelindex)) // visible ent?
3275                         return true;
3276                 if(PRVM_serveredictfloat(edict, effects)) // particle effect?
3277                         return true;
3278                 if(PRVM_serveredictfunction(edict, think)) // has a think function?
3279                         if(PRVM_serveredictfloat(edict, nextthink) > 0) // that actually will eventually run?
3280                                 return true;
3281                 if(PRVM_serveredictfloat(edict, takedamage))
3282                         return true;
3283                 if(*prvm_leaktest_ignore_classnames.string)
3284                 {
3285                         if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_serveredictstring(edict, classname)))))
3286                                 return true;
3287                 }
3288         }
3289         else if (prog == CLVM_prog)
3290         {
3291                 // TODO someone add more stuff here
3292                 if(PRVM_clientedictfloat(edict, entnum)) // csqc networked
3293                         return true;
3294                 if(PRVM_clientedictfloat(edict, modelindex)) // visible ent?
3295                         return true;
3296                 if(PRVM_clientedictfloat(edict, effects)) // particle effect?
3297                         return true;
3298                 if(PRVM_clientedictfunction(edict, think)) // has a think function?
3299                         if(PRVM_clientedictfloat(edict, nextthink) > 0) // that actually will eventually run?
3300                                 return true;
3301                 if(*prvm_leaktest_ignore_classnames.string)
3302                 {
3303                         if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_clientedictstring(edict, classname)))))
3304                                 return true;
3305                 }
3306         }
3307         else
3308         {
3309                 // menu prog does not have classnames
3310         }
3311         return false;
3312 }
3313
3314 static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, int mark)
3315 {
3316         int i, j;
3317         int edictnum = PRVM_NUM_FOR_EDICT(edict);
3318         const char *targetname = NULL;
3319
3320         if (prog == SVVM_prog && prvm_leaktest_follow_targetname.integer)
3321                 targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname));
3322
3323         if(targetname)
3324                 if(!*targetname) // ""
3325                         targetname = NULL;
3326
3327         for(j = 0; j < prog->num_edicts; ++j)
3328         {
3329                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3330                 if (ed->priv.required->mark < mark)
3331                         continue;
3332                 if(ed == edict)
3333                         continue;
3334                 if(targetname)
3335                 {
3336                         const char *target = PRVM_GetString(prog, PRVM_serveredictstring(ed, target));
3337                         if(target)
3338                                 if(!strcmp(target, targetname))
3339                                         return true;
3340                 }
3341                 for (i=0; i<prog->numfielddefs; ++i)
3342                 {
3343                         ddef_t *d = &prog->fielddefs[i];
3344                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3345                                 continue;
3346                         if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs))
3347                                 return true;
3348                 }
3349         }
3350
3351         return false;
3352 }
3353
3354 static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog)
3355 {
3356         int i, j;
3357         qboolean found_new;
3358         int stage;
3359
3360         // Stage 1: world, all entities that are relevant, and all entities that are referenced by globals.
3361         stage = 1;
3362         for(j = 0; j < prog->num_edicts; ++j)
3363         {
3364                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3365                 if(ed->priv.required->free)
3366                         continue;
3367                 ed->priv.required->mark = PRVM_IsEdictRelevant(prog, ed) ? stage : 0;
3368         }
3369         for (i = 0;i < prog->numglobaldefs;i++)
3370         {
3371                 ddef_t *d = &prog->globaldefs[i];
3372                 prvm_edict_t *ed;
3373                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3374                         continue;
3375                 j = PRVM_GLOBALFIELDEDICT(d->ofs);
3376                 if (i < 0 || j >= prog->max_edicts) {
3377                         Con_Printf("Invalid entity reference from global %s.\n", PRVM_GetString(prog, d->s_name));
3378                         continue;
3379                 }
3380                 ed = PRVM_EDICT_NUM(j);;
3381                 ed->priv.required->mark = stage;
3382         }
3383
3384         // Future stages: all entities that are referenced by an entity of the previous stage.
3385         do
3386         {
3387                 found_new = false;
3388                 for(j = 0; j < prog->num_edicts; ++j)
3389                 {
3390                         prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3391                         if(ed->priv.required->free)
3392                                 continue;
3393                         if(ed->priv.required->mark)
3394                                 continue;
3395                         if(PRVM_IsEdictReferenced(prog, ed, stage))
3396                         {
3397                                 ed->priv.required->mark = stage + 1;
3398                                 found_new = true;
3399                         }
3400                 }
3401                 ++stage;
3402         }
3403         while(found_new);
3404         Con_DPrintf("leak check used %d stages to find all references\n", stage);
3405 }
3406
3407 void PRVM_LeakTest(prvm_prog_t *prog)
3408 {
3409         int i, j;
3410         qboolean leaked = false;
3411
3412         if(!prog->leaktest_active)
3413                 return;
3414
3415         // 1. Strings
3416         for (i = 0; i < prog->numknownstrings; ++i)
3417         {
3418                 if(prog->knownstrings[i])
3419                 if(prog->knownstrings_freeable[i])
3420                 if(prog->knownstrings_origin[i])
3421                 if(!PRVM_IsStringReferenced(prog, PRVM_KNOWNSTRINGBASE + i))
3422                 {
3423                         Con_Printf("Unreferenced string found!\n  Value: %s\n  Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
3424                         leaked = true;
3425                 }
3426         }
3427
3428         // 2. Edicts
3429         PRVM_MarkReferencedEdicts(prog);
3430         for(j = 0; j < prog->num_edicts; ++j)
3431         {
3432                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3433                 if(ed->priv.required->free)
3434                         continue;
3435                 if(!ed->priv.required->mark)
3436                 if(ed->priv.required->allocation_origin)
3437                 {
3438                         Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
3439                         PRVM_ED_Print(prog, ed, NULL);
3440                         Con_Print("\n");
3441                         leaked = true;
3442                 }
3443
3444                 ed->priv.required->mark = 0; // clear marks again when done
3445         }
3446
3447         for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
3448         {
3449                 prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
3450                 if(stringbuffer)
3451                 if(stringbuffer->origin)
3452                 {
3453                         Con_Printf("Open string buffer handle found!\n  Allocated at: %s\n", stringbuffer->origin);
3454                         leaked = true;
3455                 }
3456         }
3457
3458         for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
3459         {
3460                 if(prog->openfiles[i])
3461                 if(prog->openfiles_origin[i])
3462                 {
3463                         Con_Printf("Open file handle found!\n  Allocated at: %s\n", prog->openfiles_origin[i]);
3464                         leaked = true;
3465                 }
3466         }
3467
3468         for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
3469         {
3470                 if(prog->opensearches[i])
3471                 if(prog->opensearches_origin[i])
3472                 {
3473                         Con_Printf("Open search handle found!\n  Allocated at: %s\n", prog->opensearches_origin[i]);
3474                         leaked = true;
3475                 }
3476         }
3477
3478         if(!leaked)
3479                 Con_Printf("Congratulations. No leaks found.\n");
3480 }