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