Initialize globalindex for autocvars with -1 to prevent prog corruption.
[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(256);
219                 PRVM_ShortStackTrace(prog, buf, 256);
220         }
221         return buf;
222 }
223
224 /*
225 =================
226 PRVM_ED_CanAlloc
227
228 Returns if this particular edict could get allocated by PRVM_ED_Alloc
229 =================
230 */
231 qboolean PRVM_ED_CanAlloc(prvm_prog_t *prog, prvm_edict_t *e)
232 {
233         if(!e->priv.required->free)
234                 return false;
235         if(prvm_reuseedicts_always_allow == realtime)
236                 return true;
237         if(realtime <= e->priv.required->freetime + 0.1 && prvm_reuseedicts_neverinsameframe.integer)
238                 return false; // never allow reuse in same frame (causes networking trouble)
239         if(e->priv.required->freetime < prog->starttime + prvm_reuseedicts_startuptime.value)
240                 return true;
241         if(realtime > e->priv.required->freetime + 1)
242                 return true;
243         return false; // entity slot still blocked because the entity was freed less than one second ago
244 }
245
246 /*
247 =================
248 PRVM_ED_Alloc
249
250 Either finds a free edict, or allocates a new one.
251 Try to avoid reusing an entity that was recently freed, because it
252 can cause the client to think the entity morphed into something else
253 instead of being removed and recreated, which can cause interpolated
254 angles and bad trails.
255 =================
256 */
257 prvm_edict_t *PRVM_ED_Alloc(prvm_prog_t *prog)
258 {
259         int i;
260         prvm_edict_t *e;
261
262         // the client qc dont need maxclients
263         // thus it doesnt need to use svs.maxclients
264         // AK:  changed i=svs.maxclients+1
265         // AK:  changed so the edict 0 wont spawn -> used as reserved/world entity
266         //              although the menu/client has no world
267         for (i = prog->reserved_edicts + 1;i < prog->num_edicts;i++)
268         {
269                 e = PRVM_EDICT_NUM(i);
270                 if(PRVM_ED_CanAlloc(prog, e))
271                 {
272                         PRVM_ED_ClearEdict (prog, e);
273                         return e;
274                 }
275         }
276
277         if (i == prog->limit_edicts)
278                 prog->error_cmd("%s: PRVM_ED_Alloc: no free edicts", prog->name);
279
280         prog->num_edicts++;
281         if (prog->num_edicts >= prog->max_edicts)
282                 PRVM_MEM_IncreaseEdicts(prog);
283
284         e = PRVM_EDICT_NUM(i);
285
286         PRVM_ED_ClearEdict(prog, e);
287         return e;
288 }
289
290 /*
291 =================
292 PRVM_ED_Free
293
294 Marks the edict as free
295 FIXME: walk all entities and NULL out references to this entity
296 =================
297 */
298 void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed)
299 {
300         // dont delete the null entity (world) or reserved edicts
301         if (ed - prog->edicts <= prog->reserved_edicts)
302                 return;
303
304         prog->free_edict(prog, ed);
305
306         ed->priv.required->free = true;
307         ed->priv.required->freetime = realtime;
308         if(ed->priv.required->allocation_origin)
309         {
310                 Mem_Free((char *)ed->priv.required->allocation_origin);
311                 ed->priv.required->allocation_origin = NULL;
312         }
313 }
314
315 //===========================================================================
316
317 /*
318 ============
319 PRVM_ED_GlobalAtOfs
320 ============
321 */
322 static ddef_t *PRVM_ED_GlobalAtOfs (prvm_prog_t *prog, int ofs)
323 {
324         ddef_t          *def;
325         int                     i;
326
327         for (i = 0;i < prog->numglobaldefs;i++)
328         {
329                 def = &prog->globaldefs[i];
330                 if (def->ofs == ofs)
331                         return def;
332         }
333         return NULL;
334 }
335
336 /*
337 ============
338 PRVM_ED_FieldAtOfs
339 ============
340 */
341 ddef_t *PRVM_ED_FieldAtOfs (prvm_prog_t *prog, int ofs)
342 {
343         ddef_t          *def;
344         int                     i;
345
346         for (i = 0;i < prog->numfielddefs;i++)
347         {
348                 def = &prog->fielddefs[i];
349                 if (def->ofs == ofs)
350                         return def;
351         }
352         return NULL;
353 }
354
355 /*
356 ============
357 PRVM_ED_FindField
358 ============
359 */
360 ddef_t *PRVM_ED_FindField (prvm_prog_t *prog, const char *name)
361 {
362         ddef_t *def;
363         int i;
364
365         for (i = 0;i < prog->numfielddefs;i++)
366         {
367                 def = &prog->fielddefs[i];
368                 if (!strcmp(PRVM_GetString(prog, def->s_name), name))
369                         return def;
370         }
371         return NULL;
372 }
373
374 /*
375 ============
376 PRVM_ED_FindGlobal
377 ============
378 */
379 ddef_t *PRVM_ED_FindGlobal (prvm_prog_t *prog, const char *name)
380 {
381         ddef_t *def;
382         int i;
383
384         for (i = 0;i < prog->numglobaldefs;i++)
385         {
386                 def = &prog->globaldefs[i];
387                 if (!strcmp(PRVM_GetString(prog, def->s_name), name))
388                         return def;
389         }
390         return NULL;
391 }
392
393
394 /*
395 ============
396 PRVM_ED_FindFunction
397 ============
398 */
399 mfunction_t *PRVM_ED_FindFunction (prvm_prog_t *prog, const char *name)
400 {
401         mfunction_t             *func;
402         int                             i;
403
404         for (i = 0;i < prog->numfunctions;i++)
405         {
406                 func = &prog->functions[i];
407                 if (!strcmp(PRVM_GetString(prog, func->s_name), name))
408                         return func;
409         }
410         return NULL;
411 }
412
413
414 /*
415 ============
416 PRVM_ValueString
417
418 Returns a string describing *data in a type specific manner
419 =============
420 */
421 static char *PRVM_ValueString (prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
422 {
423         ddef_t *def;
424         mfunction_t *f;
425         int n;
426
427         type = (etype_t)((int) type & ~DEF_SAVEGLOBAL);
428
429         switch (type)
430         {
431         case ev_string:
432                 strlcpy (line, PRVM_GetString (prog, val->string), linelength);
433                 break;
434         case ev_entity:
435                 n = val->edict;
436                 if (n < 0 || n >= prog->max_edicts)
437                         dpsnprintf (line, linelength, "entity %i (invalid!)", n);
438                 else
439                         dpsnprintf (line, linelength, "entity %i", n);
440                 break;
441         case ev_function:
442                 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         cvar_t *cvar;
1942
1943         if (prog->loaded)
1944                 prog->error_cmd("PRVM_LoadProgs: there is already a %s program loaded!", prog->name );
1945
1946         Host_LockSession(); // all progs can use the session cvar
1947         Crypto_LoadKeys(); // all progs might use the keys at init time
1948
1949         if (data)
1950         {
1951                 dprograms = (dprograms_t *) data;
1952                 filesize = size;
1953         }
1954         else
1955                 dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1956         if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1957                 prog->error_cmd("PRVM_LoadProgs: couldn't load %s for %s", filename, prog->name);
1958         // TODO bounds check header fields (e.g. numstatements), they must never go behind end of file
1959
1960         prog->profiletime = Sys_DirtyTime();
1961         prog->starttime = realtime;
1962
1963         Con_DPrintf("%s programs occupy %iK.\n", prog->name, (int)(filesize/1024));
1964
1965         requiredglobalspace = 0;
1966         for (i = 0;i < numrequiredglobals;i++)
1967                 requiredglobalspace += required_global[i].type == ev_vector ? 3 : 1;
1968
1969         prog->filecrc = CRC_Block((unsigned char *)dprograms, filesize);
1970
1971 // byte swap the header
1972         prog->progs_version = LittleLong(dprograms->version);
1973         prog->progs_crc = LittleLong(dprograms->crc);
1974         if (prog->progs_version != PROG_VERSION)
1975                 prog->error_cmd("%s: %s has wrong version number (%i should be %i)", prog->name, filename, prog->progs_version, PROG_VERSION);
1976         instatements = (dstatement_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_statements));
1977         prog->progs_numstatements = LittleLong(dprograms->numstatements);
1978         inglobaldefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globaldefs));
1979         prog->progs_numglobaldefs = LittleLong(dprograms->numglobaldefs);
1980         infielddefs = (ddef_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_fielddefs));
1981         prog->progs_numfielddefs = LittleLong(dprograms->numfielddefs);
1982         infunctions = (dfunction_t *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_functions));
1983         prog->progs_numfunctions = LittleLong(dprograms->numfunctions);
1984         instrings = (char *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_strings));
1985         prog->progs_numstrings = LittleLong(dprograms->numstrings);
1986         inglobals = (int *)((unsigned char *)dprograms + LittleLong(dprograms->ofs_globals));
1987         prog->progs_numglobals = LittleLong(dprograms->numglobals);
1988         prog->progs_entityfields = LittleLong(dprograms->entityfields);
1989
1990         prog->numstatements = prog->progs_numstatements;
1991         prog->numglobaldefs = prog->progs_numglobaldefs;
1992         prog->numfielddefs = prog->progs_numfielddefs;
1993         prog->numfunctions = prog->progs_numfunctions;
1994         prog->numstrings = prog->progs_numstrings;
1995         prog->numglobals = prog->progs_numglobals;
1996         prog->entityfields = prog->progs_entityfields;
1997
1998         if (LittleLong(dprograms->ofs_strings) + prog->progs_numstrings > (int)filesize)
1999                 prog->error_cmd("%s: %s strings go past end of file", prog->name, filename);
2000         prog->strings = (char *)Mem_Alloc(prog->progs_mempool, prog->progs_numstrings);
2001         memcpy(prog->strings, instrings, prog->progs_numstrings);
2002         prog->stringssize = prog->progs_numstrings;
2003
2004         prog->numknownstrings = 0;
2005         prog->maxknownstrings = 0;
2006         prog->knownstrings = NULL;
2007         prog->knownstrings_freeable = NULL;
2008
2009         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
2010
2011         // we need to expand the globaldefs and fielddefs to include engine defs
2012         prog->globaldefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobaldefs + numrequiredglobals) * sizeof(ddef_t));
2013         prog->globals.fp = (prvm_vec_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numglobals + requiredglobalspace + 2) * sizeof(prvm_vec_t));
2014                 // + 2 is because of an otherwise occurring overrun in RETURN instruction
2015                 // when trying to return the last or second-last global
2016                 // (RETURN always returns a vector, there is no RETURN_F instruction)
2017         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs_numfielddefs + numrequiredfields) * sizeof(ddef_t));
2018         // we need to convert the statements to our memory format
2019         prog->statements = (mstatement_t *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(mstatement_t));
2020         // allocate space for profiling statement usage
2021         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
2022         prog->explicit_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs_numstatements * sizeof(*prog->statement_profile));
2023         // functions need to be converted to the memory format
2024         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs_numfunctions);
2025
2026         for (i = 0;i < prog->progs_numfunctions;i++)
2027         {
2028                 prog->functions[i].first_statement = LittleLong(infunctions[i].first_statement);
2029                 prog->functions[i].parm_start = LittleLong(infunctions[i].parm_start);
2030                 prog->functions[i].s_name = LittleLong(infunctions[i].s_name);
2031                 prog->functions[i].s_file = LittleLong(infunctions[i].s_file);
2032                 prog->functions[i].numparms = LittleLong(infunctions[i].numparms);
2033                 prog->functions[i].locals = LittleLong(infunctions[i].locals);
2034                 memcpy(prog->functions[i].parm_size, infunctions[i].parm_size, sizeof(infunctions[i].parm_size));
2035                 if(prog->functions[i].first_statement >= prog->numstatements)
2036                         prog->error_cmd("PRVM_LoadProgs: out of bounds function statement (function %d) in %s", i, prog->name);
2037                 // TODO bounds check parm_start, s_name, s_file, numparms, locals, parm_size
2038         }
2039
2040         // copy the globaldefs to the new globaldefs list
2041         for (i=0 ; i<prog->numglobaldefs ; i++)
2042         {
2043                 prog->globaldefs[i].type = LittleShort(inglobaldefs[i].type);
2044                 prog->globaldefs[i].ofs = LittleShort(inglobaldefs[i].ofs);
2045                 prog->globaldefs[i].s_name = LittleLong(inglobaldefs[i].s_name);
2046                 // TODO bounds check ofs, s_name
2047         }
2048
2049         // append the required globals
2050         for (i = 0;i < numrequiredglobals;i++)
2051         {
2052                 prog->globaldefs[prog->numglobaldefs].type = required_global[i].type;
2053                 prog->globaldefs[prog->numglobaldefs].ofs = prog->numglobals;
2054                 prog->globaldefs[prog->numglobaldefs].s_name = PRVM_SetEngineString(prog, required_global[i].name);
2055                 if (prog->globaldefs[prog->numglobaldefs].type == ev_vector)
2056                         prog->numglobals += 3;
2057                 else
2058                         prog->numglobals++;
2059                 prog->numglobaldefs++;
2060         }
2061
2062         // copy the progs fields to the new fields list
2063         for (i = 0;i < prog->numfielddefs;i++)
2064         {
2065                 prog->fielddefs[i].type = LittleShort(infielddefs[i].type);
2066                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
2067                         prog->error_cmd("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", prog->name);
2068                 prog->fielddefs[i].ofs = LittleShort(infielddefs[i].ofs);
2069                 prog->fielddefs[i].s_name = LittleLong(infielddefs[i].s_name);
2070                 // TODO bounds check ofs, s_name
2071         }
2072
2073         // append the required fields
2074         for (i = 0;i < numrequiredfields;i++)
2075         {
2076                 prog->fielddefs[prog->numfielddefs].type = required_field[i].type;
2077                 prog->fielddefs[prog->numfielddefs].ofs = prog->entityfields;
2078                 prog->fielddefs[prog->numfielddefs].s_name = PRVM_SetEngineString(prog, required_field[i].name);
2079                 if (prog->fielddefs[prog->numfielddefs].type == ev_vector)
2080                         prog->entityfields += 3;
2081                 else
2082                         prog->entityfields++;
2083                 prog->numfielddefs++;
2084         }
2085
2086         // LordHavoc: TODO: reorder globals to match engine struct
2087         // LordHavoc: TODO: reorder fields to match engine struct
2088 #define remapglobal(index) (index)
2089 #define remapfield(index) (index)
2090
2091         // copy globals
2092         // FIXME: LordHavoc: this uses a crude way to identify integer constants, rather than checking for matching globaldefs and checking their type
2093         for (i = 0;i < prog->progs_numglobals;i++)
2094         {
2095                 u.i = LittleLong(inglobals[i]);
2096                 // most globals are 0, we only need to deal with the ones that are not
2097                 if (u.i)
2098                 {
2099                         d = u.i & 0xFF800000;
2100                         if ((d == 0xFF800000) || (d == 0))
2101                         {
2102                                 // Looks like an integer (expand to int64)
2103                                 prog->globals.ip[remapglobal(i)] = u.i;
2104                         }
2105                         else
2106                         {
2107                                 // Looks like a float (expand to double)
2108                                 prog->globals.fp[remapglobal(i)] = u.f;
2109                         }
2110                 }
2111         }
2112
2113         // LordHavoc: TODO: support 32bit progs statement formats
2114         // copy, remap globals in statements, bounds check
2115         for (i = 0;i < prog->progs_numstatements;i++)
2116         {
2117                 op = (opcode_t)LittleShort(instatements[i].op);
2118                 a = (unsigned short)LittleShort(instatements[i].a);
2119                 b = (unsigned short)LittleShort(instatements[i].b);
2120                 c = (unsigned short)LittleShort(instatements[i].c);
2121                 switch (op)
2122                 {
2123                 case OP_IF:
2124                 case OP_IFNOT:
2125                         b = (short)b;
2126                         if (a >= prog->progs_numglobals || b + i < 0 || b + i >= prog->progs_numstatements)
2127                                 prog->error_cmd("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, prog->name);
2128                         prog->statements[i].op = op;
2129                         prog->statements[i].operand[0] = remapglobal(a);
2130                         prog->statements[i].operand[1] = -1;
2131                         prog->statements[i].operand[2] = -1;
2132                         prog->statements[i].jumpabsolute = i + b;
2133                         break;
2134                 case OP_GOTO:
2135                         a = (short)a;
2136                         if (a + i < 0 || a + i >= prog->progs_numstatements)
2137                                 prog->error_cmd("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, prog->name);
2138                         prog->statements[i].op = op;
2139                         prog->statements[i].operand[0] = -1;
2140                         prog->statements[i].operand[1] = -1;
2141                         prog->statements[i].operand[2] = -1;
2142                         prog->statements[i].jumpabsolute = i + a;
2143                         break;
2144                 default:
2145                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", (int)op, i, prog->name);
2146                         break;
2147                 // global global global
2148                 case OP_ADD_F:
2149                 case OP_ADD_V:
2150                 case OP_SUB_F:
2151                 case OP_SUB_V:
2152                 case OP_MUL_F:
2153                 case OP_MUL_V:
2154                 case OP_MUL_FV:
2155                 case OP_MUL_VF:
2156                 case OP_DIV_F:
2157                 case OP_BITAND:
2158                 case OP_BITOR:
2159                 case OP_GE:
2160                 case OP_LE:
2161                 case OP_GT:
2162                 case OP_LT:
2163                 case OP_AND:
2164                 case OP_OR:
2165                 case OP_EQ_F:
2166                 case OP_EQ_V:
2167                 case OP_EQ_S:
2168                 case OP_EQ_E:
2169                 case OP_EQ_FNC:
2170                 case OP_NE_F:
2171                 case OP_NE_V:
2172                 case OP_NE_S:
2173                 case OP_NE_E:
2174                 case OP_NE_FNC:
2175                 case OP_ADDRESS:
2176                 case OP_LOAD_F:
2177                 case OP_LOAD_FLD:
2178                 case OP_LOAD_ENT:
2179                 case OP_LOAD_S:
2180                 case OP_LOAD_FNC:
2181                 case OP_LOAD_V:
2182                         if (a >= prog->progs_numglobals || b >= prog->progs_numglobals || c >= prog->progs_numglobals)
2183                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
2184                         prog->statements[i].op = op;
2185                         prog->statements[i].operand[0] = remapglobal(a);
2186                         prog->statements[i].operand[1] = remapglobal(b);
2187                         prog->statements[i].operand[2] = remapglobal(c);
2188                         prog->statements[i].jumpabsolute = -1;
2189                         break;
2190                 // global none global
2191                 case OP_NOT_F:
2192                 case OP_NOT_V:
2193                 case OP_NOT_S:
2194                 case OP_NOT_FNC:
2195                 case OP_NOT_ENT:
2196                         if (a >= prog->progs_numglobals || c >= prog->progs_numglobals)
2197                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2198                         prog->statements[i].op = op;
2199                         prog->statements[i].operand[0] = remapglobal(a);
2200                         prog->statements[i].operand[1] = -1;
2201                         prog->statements[i].operand[2] = remapglobal(c);
2202                         prog->statements[i].jumpabsolute = -1;
2203                         break;
2204                 // 2 globals
2205                 case OP_STOREP_F:
2206                 case OP_STOREP_ENT:
2207                 case OP_STOREP_FLD:
2208                 case OP_STOREP_S:
2209                 case OP_STOREP_FNC:
2210                 case OP_STORE_F:
2211                 case OP_STORE_ENT:
2212                 case OP_STORE_FLD:
2213                 case OP_STORE_S:
2214                 case OP_STORE_FNC:
2215                 case OP_STATE:
2216                 case OP_STOREP_V:
2217                 case OP_STORE_V:
2218                         if (a >= prog->progs_numglobals || b >= prog->progs_numglobals)
2219                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2220                         prog->statements[i].op = op;
2221                         prog->statements[i].operand[0] = remapglobal(a);
2222                         prog->statements[i].operand[1] = remapglobal(b);
2223                         prog->statements[i].operand[2] = -1;
2224                         prog->statements[i].jumpabsolute = -1;
2225                         break;
2226                 // 1 global
2227                 case OP_CALL0:
2228                         if ( a < prog->progs_numglobals)
2229                                 if ( prog->globals.ip[remapglobal(a)] >= 0 )
2230                                         if ( prog->globals.ip[remapglobal(a)] < prog->progs_numfunctions )
2231                                                 if ( prog->functions[prog->globals.ip[remapglobal(a)]].first_statement == -642 )
2232                                                         ++prog->numexplicitcoveragestatements;
2233                 case OP_CALL1:
2234                 case OP_CALL2:
2235                 case OP_CALL3:
2236                 case OP_CALL4:
2237                 case OP_CALL5:
2238                 case OP_CALL6:
2239                 case OP_CALL7:
2240                 case OP_CALL8:
2241                 case OP_DONE:
2242                 case OP_RETURN:
2243                         if ( a >= prog->progs_numglobals)
2244                                 prog->error_cmd("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, prog->name);
2245                         prog->statements[i].op = op;
2246                         prog->statements[i].operand[0] = remapglobal(a);
2247                         prog->statements[i].operand[1] = -1;
2248                         prog->statements[i].operand[2] = -1;
2249                         prog->statements[i].jumpabsolute = -1;
2250                         break;
2251                 }
2252         }
2253         if(prog->numstatements < 1)
2254         {
2255                 prog->error_cmd("PRVM_LoadProgs: empty program in %s", prog->name);
2256         }
2257         else switch(prog->statements[prog->numstatements - 1].op)
2258         {
2259                 case OP_RETURN:
2260                 case OP_GOTO:
2261                 case OP_DONE:
2262                         break;
2263                 default:
2264                         prog->error_cmd("PRVM_LoadProgs: program may fall off the edge (does not end with RETURN, GOTO or DONE) in %s", prog->name);
2265                         break;
2266         }
2267
2268         // we're done with the file now
2269         if(!data)
2270                 Mem_Free(dprograms);
2271         dprograms = NULL;
2272
2273         // check required functions
2274         for(i=0 ; i < numrequiredfunc ; i++)
2275                 if(PRVM_ED_FindFunction(prog, required_func[i]) == 0)
2276                         prog->error_cmd("%s: %s not found in %s",prog->name, required_func[i], filename);
2277
2278         PRVM_LoadLNO(prog, filename);
2279
2280         PRVM_Init_Exec(prog);
2281
2282         if(*prvm_language.string)
2283         // in CSQC we really shouldn't be able to change how stuff works... sorry for now
2284         // later idea: include a list of authorized .po file checksums with the csprogs
2285         {
2286                 qboolean deftrans = prog == CLVM_prog;
2287                 const char *realfilename = (prog != CLVM_prog ? filename : csqc_progname.string);
2288                 if(deftrans) // once we have dotranslate_ strings, ALWAYS use the opt-in method!
2289                 {
2290                         for (i=0 ; i<prog->numglobaldefs ; i++)
2291                         {
2292                                 const char *name;
2293                                 name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2294                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2295                                 if(name && !strncmp(name, "dotranslate_", 12))
2296                                 {
2297                                         deftrans = false;
2298                                         break;
2299                                 }
2300                         }
2301                 }
2302                 if(!strcmp(prvm_language.string, "dump"))
2303                 {
2304                         qfile_t *f = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.pot", realfilename), "w", false);
2305                         Con_Printf("Dumping to %s.pot\n", realfilename);
2306                         if(f)
2307                         {
2308                                 for (i=0 ; i<prog->numglobaldefs ; i++)
2309                                 {
2310                                         const char *name;
2311                                         name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2312                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2313                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2314                                         {
2315                                                 prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2316                                                 const char *value = PRVM_GetString(prog, val->string);
2317                                                 if(*value)
2318                                                 {
2319                                                         char buf[MAX_INPUTLINE];
2320                                                         PRVM_PO_UnparseString(buf, value, sizeof(buf));
2321                                                         FS_Printf(f, "msgid \"%s\"\nmsgstr \"\"\n\n", buf);
2322                                                 }
2323                                         }
2324                                 }
2325                                 FS_Close(f);
2326                         }
2327                 }
2328                 else
2329                 {
2330                         po_t *po = PRVM_PO_Load(
2331                                         va(vabuf, sizeof(vabuf), "%s.%s.po", realfilename, prvm_language.string),
2332                                         va(vabuf2, sizeof(vabuf2), "common.%s.po", prvm_language.string),
2333                                         prog->progs_mempool);
2334                         if(po)
2335                         {
2336                                 for (i=0 ; i<prog->numglobaldefs ; i++)
2337                                 {
2338                                         const char *name;
2339                                         name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2340                                         if(deftrans ? (!name || strncmp(name, "notranslate_", 12)) : (name && !strncmp(name, "dotranslate_", 12)))
2341                                         if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2342                                         {
2343                                                 prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2344                                                 const char *value = PRVM_GetString(prog, val->string);
2345                                                 if(*value)
2346                                                 {
2347                                                         value = PRVM_PO_Lookup(po, value);
2348                                                         if(value)
2349                                                                 val->string = PRVM_SetEngineString(prog, value);
2350                                                 }
2351                                         }
2352                                 }
2353                         }
2354                 }
2355         }
2356
2357         for (cvar = cvar_vars; cvar; cvar = cvar->next)
2358                 cvar->globaldefindex[prog - prvm_prog_list] = -1;
2359
2360         for (i=0 ; i<prog->numglobaldefs ; i++)
2361         {
2362                 const char *name;
2363                 name = PRVM_GetString(prog, prog->globaldefs[i].s_name);
2364                 //Con_Printf("found var %s\n", name);
2365                 if(name
2366                         && !strncmp(name, "autocvar_", 9)
2367                         && !(strlen(name) > 1 && name[strlen(name)-2] == '_' && (name[strlen(name)-1] == 'x' || name[strlen(name)-1] == 'y' || name[strlen(name)-1] == 'z'))
2368                 )
2369                 {
2370                         prvm_eval_t *val = PRVM_GLOBALFIELDVALUE(prog->globaldefs[i].ofs);
2371                         cvar = Cvar_FindVar(name + 9);
2372                         //Con_Printf("PRVM_LoadProgs: autocvar global %s in %s, processing...\n", name, prog->name);
2373                         if(!cvar)
2374                         {
2375                                 const char *value;
2376                                 char buf[64];
2377                                 Con_DPrintf("PRVM_LoadProgs: no cvar for autocvar global %s in %s, creating...\n", name, prog->name);
2378                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2379                                 {
2380                                         case ev_float:
2381                                                 if((float)((int)(val->_float)) == val->_float)
2382                                                         dpsnprintf(buf, sizeof(buf), "%i", (int)(val->_float));
2383                                                 else
2384                                                         dpsnprintf(buf, sizeof(buf), "%.9g", val->_float);
2385                                                 value = buf;
2386                                                 break;
2387                                         case ev_vector:
2388                                                 dpsnprintf(buf, sizeof(buf), "%.9g %.9g %.9g", val->vector[0], val->vector[1], val->vector[2]); value = buf;
2389                                                 break;
2390                                         case ev_string:
2391                                                 value = PRVM_GetString(prog, val->string);
2392                                                 break;
2393                                         default:
2394                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
2395                                                 goto fail;
2396                                 }
2397                                 cvar = Cvar_Get(name + 9, value, 0, NULL);
2398                                 if((prog->globaldefs[i].type & ~DEF_SAVEGLOBAL) == ev_string)
2399                                 {
2400                                         val->string = PRVM_SetEngineString(prog, cvar->string);
2401                                         cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
2402                                 }
2403                                 if(!cvar)
2404                                         prog->error_cmd("PRVM_LoadProgs: could not create cvar for autocvar global %s in %s", name, prog->name);
2405                                 cvar->globaldefindex_progid[prog - prvm_prog_list] = prog->id;
2406                                 cvar->globaldefindex[prog - prvm_prog_list] = i;
2407                         }
2408                         else if((cvar->flags & CVAR_PRIVATE) == 0)
2409                         {
2410                                 // MUST BE SYNCED WITH cvar.c Cvar_Set
2411                                 int j;
2412                                 const char *s;
2413                                 switch(prog->globaldefs[i].type & ~DEF_SAVEGLOBAL)
2414                                 {
2415                                         case ev_float:
2416                                                 val->_float = cvar->value;
2417                                                 break;
2418                                         case ev_vector:
2419                                                 s = cvar->string;
2420                                                 VectorClear(val->vector);
2421                                                 for (j = 0;j < 3;j++)
2422                                                 {
2423                                                         while (*s && ISWHITESPACE(*s))
2424                                                                 s++;
2425                                                         if (!*s)
2426                                                                 break;
2427                                                         val->vector[j] = atof(s);
2428                                                         while (!ISWHITESPACE(*s))
2429                                                                 s++;
2430                                                         if (!*s)
2431                                                                 break;
2432                                                 }
2433                                                 break;
2434                                         case ev_string:
2435                                                 val->string = PRVM_SetEngineString(prog, cvar->string);
2436                                                 cvar->globaldefindex_stringno[prog - prvm_prog_list] = val->string;
2437                                                 break;
2438                                         default:
2439                                                 Con_Printf("PRVM_LoadProgs: invalid type of autocvar global %s in %s\n", name, prog->name);
2440                                                 goto fail;
2441                                 }
2442                                 cvar->globaldefindex_progid[prog - prvm_prog_list] = prog->id;
2443                                 cvar->globaldefindex[prog - prvm_prog_list] = i;
2444                         }
2445                         else
2446                                 Con_Printf("PRVM_LoadProgs: private cvar for autocvar global %s in %s\n", name, prog->name);
2447                 }
2448 fail:
2449                 ;
2450         }
2451
2452         prog->loaded = TRUE;
2453
2454         PRVM_UpdateBreakpoints(prog);
2455
2456         // set flags & ddef_ts in prog
2457
2458         prog->flag = 0;
2459
2460         PRVM_FindOffsets(prog);
2461
2462         prog->init_cmd(prog);
2463
2464         // init mempools
2465         PRVM_MEM_Alloc(prog);
2466
2467         // Inittime is at least the time when this function finished. However,
2468         // later events may bump it.
2469         prog->inittime = realtime;
2470 }
2471
2472
2473 static void PRVM_Fields_f (void)
2474 {
2475         prvm_prog_t *prog;
2476         int i, j, ednum, used, usedamount;
2477         int *counts;
2478         char tempstring[MAX_INPUTLINE], tempstring2[260];
2479         const char *name;
2480         prvm_edict_t *ed;
2481         ddef_t *d;
2482         prvm_eval_t *val;
2483
2484         // TODO
2485         /*
2486         if (!sv.active)
2487         {
2488                 Con_Print("no progs loaded\n");
2489                 return;
2490         }
2491         */
2492
2493         if(Cmd_Argc() != 2)
2494         {
2495                 Con_Print("prvm_fields <program name>\n");
2496                 return;
2497         }
2498
2499         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2500                 return;
2501
2502         counts = (int *)Mem_Alloc(tempmempool, prog->numfielddefs * sizeof(int));
2503         for (ednum = 0;ednum < prog->max_edicts;ednum++)
2504         {
2505                 ed = PRVM_EDICT_NUM(ednum);
2506                 if (ed->priv.required->free)
2507                         continue;
2508                 for (i = 1;i < prog->numfielddefs;i++)
2509                 {
2510                         d = &prog->fielddefs[i];
2511                         name = PRVM_GetString(prog, d->s_name);
2512                         if (name[strlen(name)-2] == '_')
2513                                 continue;       // skip _x, _y, _z vars
2514                         val = (prvm_eval_t *)(ed->fields.fp + d->ofs);
2515                         // if the value is still all 0, skip the field
2516                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
2517                         {
2518                                 if (val->ivector[j])
2519                                 {
2520                                         counts[i]++;
2521                                         break;
2522                                 }
2523                         }
2524                 }
2525         }
2526         used = 0;
2527         usedamount = 0;
2528         tempstring[0] = 0;
2529         for (i = 0;i < prog->numfielddefs;i++)
2530         {
2531                 d = &prog->fielddefs[i];
2532                 name = PRVM_GetString(prog, d->s_name);
2533                 if (name[strlen(name)-2] == '_')
2534                         continue;       // skip _x, _y, _z vars
2535                 switch(d->type & ~DEF_SAVEGLOBAL)
2536                 {
2537                 case ev_string:
2538                         strlcat(tempstring, "string   ", sizeof(tempstring));
2539                         break;
2540                 case ev_entity:
2541                         strlcat(tempstring, "entity   ", sizeof(tempstring));
2542                         break;
2543                 case ev_function:
2544                         strlcat(tempstring, "function ", sizeof(tempstring));
2545                         break;
2546                 case ev_field:
2547                         strlcat(tempstring, "field    ", sizeof(tempstring));
2548                         break;
2549                 case ev_void:
2550                         strlcat(tempstring, "void     ", sizeof(tempstring));
2551                         break;
2552                 case ev_float:
2553                         strlcat(tempstring, "float    ", sizeof(tempstring));
2554                         break;
2555                 case ev_vector:
2556                         strlcat(tempstring, "vector   ", sizeof(tempstring));
2557                         break;
2558                 case ev_pointer:
2559                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
2560                         break;
2561                 default:
2562                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
2563                         strlcat(tempstring, tempstring2, sizeof(tempstring));
2564                         break;
2565                 }
2566                 if (strlen(name) > sizeof(tempstring2)-4)
2567                 {
2568                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
2569                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
2570                         tempstring2[sizeof(tempstring2)-1] = 0;
2571                         name = tempstring2;
2572                 }
2573                 strlcat(tempstring, name, sizeof(tempstring));
2574                 for (j = (int)strlen(name);j < 25;j++)
2575                         strlcat(tempstring, " ", sizeof(tempstring));
2576                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
2577                 strlcat(tempstring, tempstring2, sizeof(tempstring));
2578                 strlcat(tempstring, "\n", sizeof(tempstring));
2579                 if (strlen(tempstring) >= sizeof(tempstring)/2)
2580                 {
2581                         Con_Print(tempstring);
2582                         tempstring[0] = 0;
2583                 }
2584                 if (counts[i])
2585                 {
2586                         used++;
2587                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
2588                 }
2589         }
2590         Mem_Free(counts);
2591         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);
2592 }
2593
2594 static void PRVM_Globals_f (void)
2595 {
2596         prvm_prog_t *prog;
2597         int i;
2598         const char *wildcard;
2599         int numculled;
2600                 numculled = 0;
2601         // TODO
2602         /*if (!sv.active)
2603         {
2604                 Con_Print("no progs loaded\n");
2605                 return;
2606         }*/
2607         if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
2608         {
2609                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
2610                 return;
2611         }
2612
2613         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2614                 return;
2615
2616         if( Cmd_Argc() == 3)
2617                 wildcard = Cmd_Argv(2);
2618         else
2619                 wildcard = NULL;
2620
2621         Con_Printf("%s :", prog->name);
2622
2623         for (i = 0;i < prog->numglobaldefs;i++)
2624         {
2625                 if(wildcard)
2626                         if( !matchpattern( PRVM_GetString(prog, prog->globaldefs[i].s_name), wildcard, 1) )
2627                         {
2628                                 numculled++;
2629                                 continue;
2630                         }
2631                 Con_Printf("%s\n", PRVM_GetString(prog, prog->globaldefs[i].s_name));
2632         }
2633         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->numglobals, numculled, prog->numglobals * 4);
2634 }
2635
2636 /*
2637 ===============
2638 PRVM_Global
2639 ===============
2640 */
2641 static void PRVM_Global_f(void)
2642 {
2643         prvm_prog_t *prog;
2644         ddef_t *global;
2645         char valuebuf[MAX_INPUTLINE];
2646         if( Cmd_Argc() != 3 ) {
2647                 Con_Printf( "prvm_global <program name> <global name>\n" );
2648                 return;
2649         }
2650
2651         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2652                 return;
2653
2654         global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) );
2655         if( !global )
2656                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2657         else
2658                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( prog, (etype_t)global->type, PRVM_GLOBALFIELDVALUE(global->ofs), valuebuf, sizeof(valuebuf) ) );
2659 }
2660
2661 /*
2662 ===============
2663 PRVM_GlobalSet
2664 ===============
2665 */
2666 static void PRVM_GlobalSet_f(void)
2667 {
2668         prvm_prog_t *prog;
2669         ddef_t *global;
2670         if( Cmd_Argc() != 4 ) {
2671                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2672                 return;
2673         }
2674
2675         if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2676                 return;
2677
2678         global = PRVM_ED_FindGlobal( prog, Cmd_Argv(2) );
2679         if( !global )
2680                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2681         else
2682                 PRVM_ED_ParseEpair( prog, NULL, global, Cmd_Argv(3), true );
2683 }
2684
2685 /*
2686 ======================
2687 Break- and Watchpoints
2688 ======================
2689 */
2690 typedef struct
2691 {
2692         char break_statement[256];
2693         char watch_global[256];
2694         int watch_edict;
2695         char watch_field[256];
2696 }
2697 debug_data_t;
2698 static debug_data_t debug_data[PRVM_PROG_MAX];
2699
2700 void PRVM_Breakpoint(prvm_prog_t *prog, int stack_index, const char *text)
2701 {
2702         char vabuf[1024];
2703         Con_Printf("PRVM_Breakpoint: %s\n", text);
2704         PRVM_PrintState(prog, stack_index);
2705         if (prvm_breakpointdump.integer)
2706                 Host_Savegame_to(prog, va(vabuf, sizeof(vabuf), "breakpoint-%s.dmp", prog->name));
2707 }
2708
2709 void PRVM_Watchpoint(prvm_prog_t *prog, int stack_index, const char *text, etype_t type, prvm_eval_t *o, prvm_eval_t *n)
2710 {
2711         size_t sz = sizeof(prvm_vec_t) * ((type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2712         if (memcmp(o, n, sz))
2713         {
2714                 char buf[1024];
2715                 char valuebuf_o[128];
2716                 char valuebuf_n[128];
2717                 PRVM_UglyValueString(prog, type, o, valuebuf_o, sizeof(valuebuf_o));
2718                 PRVM_UglyValueString(prog, type, n, valuebuf_n, sizeof(valuebuf_n));
2719                 dpsnprintf(buf, sizeof(buf), "%s: %s -> %s", text, valuebuf_o, valuebuf_n);
2720                 PRVM_Breakpoint(prog, stack_index, buf);
2721                 memcpy(o, n, sz);
2722         }
2723 }
2724
2725 static void PRVM_UpdateBreakpoints(prvm_prog_t *prog)
2726 {
2727         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2728         if (!prog->loaded)
2729                 return;
2730         if (debug->break_statement[0])
2731         {
2732                 if (debug->break_statement[0] >= '0' && debug->break_statement[0] <= '9')
2733                 {
2734                         prog->break_statement = atoi(debug->break_statement);
2735                         prog->break_stack_index = 0;
2736                 }
2737                 else
2738                 {
2739                         mfunction_t *func;
2740                         func = PRVM_ED_FindFunction (prog, debug->break_statement);
2741                         if (!func)
2742                         {
2743                                 Con_Printf("%s progs: no function or statement named %s to break on!\n", prog->name, debug->break_statement);
2744                                 prog->break_statement = -1;
2745                         }
2746                         else
2747                         {
2748                                 prog->break_statement = func->first_statement;
2749                                 prog->break_stack_index = 1;
2750                         }
2751                 }
2752                 if (prog->break_statement >= -1)
2753                         Con_Printf("%s progs: breakpoint is at statement %d\n", prog->name, prog->break_statement);
2754         }
2755         else
2756                 prog->break_statement = -1;
2757
2758         if (debug->watch_global[0])
2759         {
2760                 ddef_t *global = PRVM_ED_FindGlobal( prog, debug->watch_global );
2761                 if( !global )
2762                 {
2763                         Con_Printf( "%s progs: no global named '%s' to watch!\n", prog->name, debug->watch_global );
2764                         prog->watch_global_type = ev_void;
2765                 }
2766                 else
2767                 {
2768                         size_t sz = sizeof(prvm_vec_t) * ((global->type  & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2769                         prog->watch_global = global->ofs;
2770                         prog->watch_global_type = (etype_t)global->type;
2771                         memcpy(&prog->watch_global_value, PRVM_GLOBALFIELDVALUE(prog->watch_global), sz);
2772                 }
2773                 if (prog->watch_global_type != ev_void)
2774                         Con_Printf("%s progs: global watchpoint is at global index %d\n", prog->name, prog->watch_global);
2775         }
2776         else
2777                 prog->watch_global_type = ev_void;
2778
2779         if (debug->watch_field[0])
2780         {
2781                 ddef_t *field = PRVM_ED_FindField( prog, debug->watch_field );
2782                 if( !field )
2783                 {
2784                         Con_Printf( "%s progs: no field named '%s' to watch!\n", prog->name, debug->watch_field );
2785                         prog->watch_field_type = ev_void;
2786                 }
2787                 else
2788                 {
2789                         size_t sz = sizeof(prvm_vec_t) * ((field->type & ~DEF_SAVEGLOBAL) == ev_vector ? 3 : 1);
2790                         prog->watch_edict = debug->watch_edict;
2791                         prog->watch_field = field->ofs;
2792                         prog->watch_field_type = (etype_t)field->type;
2793                         if (prog->watch_edict < prog->num_edicts)
2794                                 memcpy(&prog->watch_edictfield_value, PRVM_EDICTFIELDVALUE(PRVM_EDICT_NUM(prog->watch_edict), prog->watch_field), sz);
2795                         else
2796                                 memset(&prog->watch_edictfield_value, 0, sz);
2797                 }
2798                 if (prog->watch_edict != ev_void)
2799                         Con_Printf("%s progs: edict field watchpoint is at edict %d field index %d\n", prog->name, prog->watch_edict, prog->watch_field);
2800         }
2801         else
2802                 prog->watch_field_type = ev_void;
2803 }
2804
2805 static void PRVM_Breakpoint_f(void)
2806 {
2807         prvm_prog_t *prog;
2808
2809         if( Cmd_Argc() == 2 ) {
2810                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2811                         return;
2812                 {
2813                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2814                         debug->break_statement[0] = 0;
2815                 }
2816                 PRVM_UpdateBreakpoints(prog);
2817                 return;
2818         }
2819         if( Cmd_Argc() != 3 ) {
2820                 Con_Printf( "prvm_breakpoint <program name> <function name | statement>\n" );
2821                 return;
2822         }
2823
2824         if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
2825                 return;
2826
2827         {
2828                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2829                 strlcpy(debug->break_statement, Cmd_Argv(2), sizeof(debug->break_statement));
2830         }
2831         PRVM_UpdateBreakpoints(prog);
2832 }
2833
2834 static void PRVM_GlobalWatchpoint_f(void)
2835 {
2836         prvm_prog_t *prog;
2837
2838         if( Cmd_Argc() == 2 ) {
2839                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2840                         return;
2841                 {
2842                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2843                         debug->watch_global[0] = 0;
2844                 }
2845                 PRVM_UpdateBreakpoints(prog);
2846                 return;
2847         }
2848         if( Cmd_Argc() != 3 ) {
2849                 Con_Printf( "prvm_globalwatchpoint <program name> <global name>\n" );
2850                 return;
2851         }
2852
2853         if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
2854                 return;
2855
2856         {
2857                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2858                 strlcpy(debug->watch_global, Cmd_Argv(2), sizeof(debug->watch_global));
2859         }
2860         PRVM_UpdateBreakpoints(prog);
2861 }
2862
2863 static void PRVM_EdictWatchpoint_f(void)
2864 {
2865         prvm_prog_t *prog;
2866
2867         if( Cmd_Argc() == 2 ) {
2868                 if (!(prog = PRVM_FriendlyProgFromString(Cmd_Argv(1))))
2869                         return;
2870                 {
2871                         debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2872                         debug->watch_field[0] = 0;
2873                 }
2874                 PRVM_UpdateBreakpoints(prog);
2875                 return;
2876         }
2877         if( Cmd_Argc() != 4 ) {
2878                 Con_Printf( "prvm_edictwatchpoint <program name> <edict number> <field name>\n" );
2879                 return;
2880         }
2881
2882         if (!(prog = PRVM_ProgFromString(Cmd_Argv(1))))
2883                 return;
2884
2885         {
2886                 debug_data_t *debug = &debug_data[prog - prvm_prog_list];
2887                 debug->watch_edict = atoi(Cmd_Argv(2));
2888                 strlcpy(debug->watch_field, Cmd_Argv(3), sizeof(debug->watch_field));
2889         }
2890         PRVM_UpdateBreakpoints(prog);
2891 }
2892
2893 /*
2894 ===============
2895 PRVM_Init
2896 ===============
2897 */
2898 void PRVM_Init (void)
2899 {
2900         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2901         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2902         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2903         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2904         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");
2905         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)");
2906         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)");
2907         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2908         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2909         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2910         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)");
2911         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");
2912         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");
2913         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2914         Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2915         Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2916         Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2917
2918         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");
2919         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");
2920         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");
2921
2922         Cvar_RegisterVariable (&prvm_language);
2923         Cvar_RegisterVariable (&prvm_traceqc);
2924         Cvar_RegisterVariable (&prvm_statementprofiling);
2925         Cvar_RegisterVariable (&prvm_timeprofiling);
2926         Cvar_RegisterVariable (&prvm_coverage);
2927         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2928         Cvar_RegisterVariable (&prvm_leaktest);
2929         Cvar_RegisterVariable (&prvm_leaktest_follow_targetname);
2930         Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2931         Cvar_RegisterVariable (&prvm_errordump);
2932         Cvar_RegisterVariable (&prvm_breakpointdump);
2933         Cvar_RegisterVariable (&prvm_reuseedicts_startuptime);
2934         Cvar_RegisterVariable (&prvm_reuseedicts_neverinsameframe);
2935
2936         // COMMANDLINEOPTION: PRVM: -norunaway disables the runaway loop check (it might be impossible to exit DarkPlaces if used!)
2937         prvm_runawaycheck = !COM_CheckParm("-norunaway");
2938
2939         //VM_Cmd_Init();
2940 }
2941
2942 /*
2943 ===============
2944 PRVM_InitProg
2945 ===============
2946 */
2947 void PRVM_Prog_Init(prvm_prog_t *prog)
2948 {
2949         PRVM_Prog_Reset(prog);
2950         prog->leaktest_active = prvm_leaktest.integer != 0;
2951 }
2952
2953 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2954 unsigned int PRVM_EDICT_NUM_ERROR(prvm_prog_t *prog, unsigned int n, const char *filename, int fileline)
2955 {
2956         prog->error_cmd("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", prog->name, n, filename, fileline);
2957         return 0;
2958 }
2959
2960 #define PRVM_KNOWNSTRINGBASE 0x40000000
2961
2962 const char *PRVM_GetString(prvm_prog_t *prog, int num)
2963 {
2964         if (num < 0)
2965         {
2966                 // invalid
2967                 VM_Warning(prog, "PRVM_GetString: Invalid string offset (%i < 0)\n", num);
2968                 return "";
2969         }
2970         else if (num < prog->stringssize)
2971         {
2972                 // constant string from progs.dat
2973                 return prog->strings + num;
2974         }
2975         else if (num <= prog->stringssize + prog->tempstringsbuf.maxsize)
2976         {
2977                 // tempstring returned by engine to QC (becomes invalid after returning to engine)
2978                 num -= prog->stringssize;
2979                 if (num < prog->tempstringsbuf.cursize)
2980                         return (char *)prog->tempstringsbuf.data + num;
2981                 else
2982                 {
2983                         VM_Warning(prog, "PRVM_GetString: Invalid temp-string offset (%i >= %i prog->tempstringsbuf.cursize)\n", num, prog->tempstringsbuf.cursize);
2984                         return "";
2985                 }
2986         }
2987         else if (num & PRVM_KNOWNSTRINGBASE)
2988         {
2989                 // allocated string
2990                 num = num - PRVM_KNOWNSTRINGBASE;
2991                 if (num >= 0 && num < prog->numknownstrings)
2992                 {
2993                         if (!prog->knownstrings[num])
2994                         {
2995                                 VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2996                                 return "";
2997                         }
2998                         return prog->knownstrings[num];
2999                 }
3000                 else
3001                 {
3002                         VM_Warning(prog, "PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
3003                         return "";
3004                 }
3005         }
3006         else
3007         {
3008                 // invalid string offset
3009                 VM_Warning(prog, "PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
3010                 return "";
3011         }
3012 }
3013
3014 const char *PRVM_ChangeEngineString(prvm_prog_t *prog, int i, const char *s)
3015 {
3016         const char *old;
3017         i = i - PRVM_KNOWNSTRINGBASE;
3018         if(i < 0 || i >= prog->numknownstrings)
3019                 prog->error_cmd("PRVM_ChangeEngineString: s is not an engine string");
3020         old = prog->knownstrings[i];
3021         prog->knownstrings[i] = s;
3022         return old;
3023 }
3024
3025 int PRVM_SetEngineString(prvm_prog_t *prog, const char *s)
3026 {
3027         int i;
3028         if (!s)
3029                 return 0;
3030         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
3031                 prog->error_cmd("PRVM_SetEngineString: s in prog->strings area");
3032         // if it's in the tempstrings area, use a reserved range
3033         // (otherwise we'd get millions of useless string offsets cluttering the database)
3034         if (s >= (char *)prog->tempstringsbuf.data && s < (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.maxsize)
3035                 return prog->stringssize + (s - (char *)prog->tempstringsbuf.data);
3036         // see if it's a known string address
3037         for (i = 0;i < prog->numknownstrings;i++)
3038                 if (prog->knownstrings[i] == s)
3039                         return PRVM_KNOWNSTRINGBASE + i;
3040         // new unknown engine string
3041         if (developer_insane.integer)
3042                 Con_DPrintf("new engine string %p = \"%s\"\n", s, s);
3043         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
3044                 if (!prog->knownstrings[i])
3045                         break;
3046         if (i >= prog->numknownstrings)
3047         {
3048                 if (i >= prog->maxknownstrings)
3049                 {
3050                         const char **oldstrings = prog->knownstrings;
3051                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
3052                         const char **oldstrings_origin = prog->knownstrings_origin;
3053                         prog->maxknownstrings += 128;
3054                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3055                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
3056                         if(prog->leaktest_active)
3057                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3058                         if (prog->numknownstrings)
3059                         {
3060                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
3061                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
3062                                 if(prog->leaktest_active)
3063                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
3064                         }
3065                 }
3066                 prog->numknownstrings++;
3067         }
3068         prog->firstfreeknownstring = i + 1;
3069         prog->knownstrings[i] = s;
3070         prog->knownstrings_freeable[i] = false;
3071         if(prog->leaktest_active)
3072                 prog->knownstrings_origin[i] = NULL;
3073         return PRVM_KNOWNSTRINGBASE + i;
3074 }
3075
3076 // temp string handling
3077
3078 // all tempstrings go into this buffer consecutively, and it is reset
3079 // whenever PRVM_ExecuteProgram returns to the engine
3080 // (technically each PRVM_ExecuteProgram call saves the cursize value and
3081 //  restores it on return, so multiple recursive calls can share the same
3082 //  buffer)
3083 // the buffer size is automatically grown as needed
3084
3085 int PRVM_SetTempString(prvm_prog_t *prog, const char *s)
3086 {
3087         int size;
3088         char *t;
3089         if (!s)
3090                 return 0;
3091         size = (int)strlen(s) + 1;
3092         if (developer_insane.integer)
3093                 Con_DPrintf("PRVM_SetTempString: cursize %i, size %i\n", prog->tempstringsbuf.cursize, size);
3094         if (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
3095         {
3096                 sizebuf_t old = prog->tempstringsbuf;
3097                 if (prog->tempstringsbuf.cursize + size >= 1<<28)
3098                         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);
3099                 prog->tempstringsbuf.maxsize = max(prog->tempstringsbuf.maxsize, 65536);
3100                 while (prog->tempstringsbuf.maxsize < prog->tempstringsbuf.cursize + size)
3101                         prog->tempstringsbuf.maxsize *= 2;
3102                 if (prog->tempstringsbuf.maxsize != old.maxsize || prog->tempstringsbuf.data == NULL)
3103                 {
3104                         Con_DPrintf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, prog->tempstringsbuf.maxsize/1024);
3105                         prog->tempstringsbuf.data = (unsigned char *) Mem_Alloc(prog->progs_mempool, prog->tempstringsbuf.maxsize);
3106                         if (old.data)
3107                         {
3108                                 if (old.cursize)
3109                                         memcpy(prog->tempstringsbuf.data, old.data, old.cursize);
3110                                 Mem_Free(old.data);
3111                         }
3112                 }
3113         }
3114         t = (char *)prog->tempstringsbuf.data + prog->tempstringsbuf.cursize;
3115         memcpy(t, s, size);
3116         prog->tempstringsbuf.cursize += size;
3117         return PRVM_SetEngineString(prog, t);
3118 }
3119
3120 int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer)
3121 {
3122         int i;
3123         if (!bufferlength)
3124         {
3125                 if (pointer)
3126                         *pointer = NULL;
3127                 return 0;
3128         }
3129         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
3130                 if (!prog->knownstrings[i])
3131                         break;
3132         if (i >= prog->numknownstrings)
3133         {
3134                 if (i >= prog->maxknownstrings)
3135                 {
3136                         const char **oldstrings = prog->knownstrings;
3137                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
3138                         const char **oldstrings_origin = prog->knownstrings_origin;
3139                         prog->maxknownstrings += 128;
3140                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3141                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
3142                         if(prog->leaktest_active)
3143                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
3144                         if (prog->numknownstrings)
3145                         {
3146                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
3147                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
3148                                 if(prog->leaktest_active)
3149                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
3150                         }
3151                         if (oldstrings)
3152                                 Mem_Free((char **)oldstrings);
3153                         if (oldstrings_freeable)
3154                                 Mem_Free((unsigned char *)oldstrings_freeable);
3155                         if (oldstrings_origin)
3156                                 Mem_Free((char **)oldstrings_origin);
3157                 }
3158                 prog->numknownstrings++;
3159         }
3160         prog->firstfreeknownstring = i + 1;
3161         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
3162         prog->knownstrings_freeable[i] = true;
3163         if(prog->leaktest_active)
3164                 prog->knownstrings_origin[i] = PRVM_AllocationOrigin(prog);
3165         if (pointer)
3166                 *pointer = (char *)(prog->knownstrings[i]);
3167         return PRVM_KNOWNSTRINGBASE + i;
3168 }
3169
3170 void PRVM_FreeString(prvm_prog_t *prog, int num)
3171 {
3172         if (num == 0)
3173                 prog->error_cmd("PRVM_FreeString: attempt to free a NULL string");
3174         else if (num >= 0 && num < prog->stringssize)
3175                 prog->error_cmd("PRVM_FreeString: attempt to free a constant string");
3176         else if (num >= PRVM_KNOWNSTRINGBASE && num < PRVM_KNOWNSTRINGBASE + prog->numknownstrings)
3177         {
3178                 num = num - PRVM_KNOWNSTRINGBASE;
3179                 if (!prog->knownstrings[num])
3180                         prog->error_cmd("PRVM_FreeString: attempt to free a non-existent or already freed string");
3181                 if (!prog->knownstrings_freeable[num])
3182                         prog->error_cmd("PRVM_FreeString: attempt to free a string owned by the engine");
3183                 PRVM_Free((char *)prog->knownstrings[num]);
3184                 if(prog->leaktest_active)
3185                         if(prog->knownstrings_origin[num])
3186                                 PRVM_Free((char *)prog->knownstrings_origin[num]);
3187                 prog->knownstrings[num] = NULL;
3188                 prog->knownstrings_freeable[num] = false;
3189                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
3190         }
3191         else
3192                 prog->error_cmd("PRVM_FreeString: invalid string offset %i", num);
3193 }
3194
3195 static qboolean PRVM_IsStringReferenced(prvm_prog_t *prog, string_t string)
3196 {
3197         int i, j;
3198
3199         for (i = 0;i < prog->numglobaldefs;i++)
3200         {
3201                 ddef_t *d = &prog->globaldefs[i];
3202                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3203                         continue;
3204                 if(string == PRVM_GLOBALFIELDSTRING(d->ofs))
3205                         return true;
3206         }
3207
3208         for(j = 0; j < prog->num_edicts; ++j)
3209         {
3210                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3211                 if (ed->priv.required->free)
3212                         continue;
3213                 for (i=0; i<prog->numfielddefs; ++i)
3214                 {
3215                         ddef_t *d = &prog->fielddefs[i];
3216                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
3217                                 continue;
3218                         if(string == PRVM_EDICTFIELDSTRING(ed, d->ofs))
3219                                 return true;
3220                 }
3221         }
3222
3223         return false;
3224 }
3225
3226 static qboolean PRVM_IsEdictRelevant(prvm_prog_t *prog, prvm_edict_t *edict)
3227 {
3228         char vabuf[1024];
3229         char vabuf2[1024];
3230         if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
3231                 return true; // world or clients
3232         if (edict->priv.required->freetime <= prog->inittime)
3233                 return true; // created during startup
3234         if (prog == SVVM_prog)
3235         {
3236                 if(PRVM_serveredictfloat(edict, solid)) // can block other stuff, or is a trigger?
3237                         return true;
3238                 if(PRVM_serveredictfloat(edict, modelindex)) // visible ent?
3239                         return true;
3240                 if(PRVM_serveredictfloat(edict, effects)) // particle effect?
3241                         return true;
3242                 if(PRVM_serveredictfunction(edict, think)) // has a think function?
3243                         if(PRVM_serveredictfloat(edict, nextthink) > 0) // that actually will eventually run?
3244                                 return true;
3245                 if(PRVM_serveredictfloat(edict, takedamage))
3246                         return true;
3247                 if(*prvm_leaktest_ignore_classnames.string)
3248                 {
3249                         if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_serveredictstring(edict, classname)))))
3250                                 return true;
3251                 }
3252         }
3253         else if (prog == CLVM_prog)
3254         {
3255                 // TODO someone add more stuff here
3256                 if(PRVM_clientedictfloat(edict, entnum)) // csqc networked
3257                         return true;
3258                 if(PRVM_clientedictfloat(edict, modelindex)) // visible ent?
3259                         return true;
3260                 if(PRVM_clientedictfloat(edict, effects)) // particle effect?
3261                         return true;
3262                 if(PRVM_clientedictfunction(edict, think)) // has a think function?
3263                         if(PRVM_clientedictfloat(edict, nextthink) > 0) // that actually will eventually run?
3264                                 return true;
3265                 if(*prvm_leaktest_ignore_classnames.string)
3266                 {
3267                         if(strstr(va(vabuf, sizeof(vabuf), " %s ", prvm_leaktest_ignore_classnames.string), va(vabuf2, sizeof(vabuf2), " %s ", PRVM_GetString(prog, PRVM_clientedictstring(edict, classname)))))
3268                                 return true;
3269                 }
3270         }
3271         else
3272         {
3273                 // menu prog does not have classnames
3274         }
3275         return false;
3276 }
3277
3278 static qboolean PRVM_IsEdictReferenced(prvm_prog_t *prog, prvm_edict_t *edict, int mark)
3279 {
3280         int i, j;
3281         int edictnum = PRVM_NUM_FOR_EDICT(edict);
3282         const char *targetname = NULL;
3283
3284         if (prog == SVVM_prog && prvm_leaktest_follow_targetname.integer)
3285                 targetname = PRVM_GetString(prog, PRVM_serveredictstring(edict, targetname));
3286
3287         if(targetname)
3288                 if(!*targetname) // ""
3289                         targetname = NULL;
3290
3291         for(j = 0; j < prog->num_edicts; ++j)
3292         {
3293                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3294                 if (ed->priv.required->mark < mark)
3295                         continue;
3296                 if(ed == edict)
3297                         continue;
3298                 if(targetname)
3299                 {
3300                         const char *target = PRVM_GetString(prog, PRVM_serveredictstring(ed, target));
3301                         if(target)
3302                                 if(!strcmp(target, targetname))
3303                                         return true;
3304                 }
3305                 for (i=0; i<prog->numfielddefs; ++i)
3306                 {
3307                         ddef_t *d = &prog->fielddefs[i];
3308                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3309                                 continue;
3310                         if(edictnum == PRVM_EDICTFIELDEDICT(ed, d->ofs))
3311                                 return true;
3312                 }
3313         }
3314
3315         return false;
3316 }
3317
3318 static void PRVM_MarkReferencedEdicts(prvm_prog_t *prog)
3319 {
3320         int i, j;
3321         qboolean found_new;
3322         int stage;
3323
3324         // Stage 1: world, all entities that are relevant, and all entities that are referenced by globals.
3325         stage = 1;
3326         for(j = 0; j < prog->num_edicts; ++j)
3327         {
3328                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3329                 if(ed->priv.required->free)
3330                         continue;
3331                 ed->priv.required->mark = PRVM_IsEdictRelevant(prog, ed) ? stage : 0;
3332         }
3333         for (i = 0;i < prog->numglobaldefs;i++)
3334         {
3335                 ddef_t *d = &prog->globaldefs[i];
3336                 prvm_edict_t *ed;
3337                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
3338                         continue;
3339                 j = PRVM_GLOBALFIELDEDICT(d->ofs);
3340                 if (i < 0 || j >= prog->max_edicts) {
3341                         Con_Printf("Invalid entity reference from global %s.\n", PRVM_GetString(prog, d->s_name));
3342                         continue;
3343                 }
3344                 ed = PRVM_EDICT_NUM(j);;
3345                 ed->priv.required->mark = stage;
3346         }
3347
3348         // Future stages: all entities that are referenced by an entity of the previous stage.
3349         do
3350         {
3351                 found_new = false;
3352                 for(j = 0; j < prog->num_edicts; ++j)
3353                 {
3354                         prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3355                         if(ed->priv.required->free)
3356                                 continue;
3357                         if(ed->priv.required->mark)
3358                                 continue;
3359                         if(PRVM_IsEdictReferenced(prog, ed, stage))
3360                         {
3361                                 ed->priv.required->mark = stage + 1;
3362                                 found_new = true;
3363                         }
3364                 }
3365                 ++stage;
3366         }
3367         while(found_new);
3368         Con_DPrintf("leak check used %d stages to find all references\n", stage);
3369 }
3370
3371 void PRVM_LeakTest(prvm_prog_t *prog)
3372 {
3373         int i, j;
3374         qboolean leaked = false;
3375
3376         if(!prog->leaktest_active)
3377                 return;
3378
3379         // 1. Strings
3380         for (i = 0; i < prog->numknownstrings; ++i)
3381         {
3382                 if(prog->knownstrings[i])
3383                 if(prog->knownstrings_freeable[i])
3384                 if(prog->knownstrings_origin[i])
3385                 if(!PRVM_IsStringReferenced(prog, PRVM_KNOWNSTRINGBASE + i))
3386                 {
3387                         Con_Printf("Unreferenced string found!\n  Value: %s\n  Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
3388                         leaked = true;
3389                 }
3390         }
3391
3392         // 2. Edicts
3393         PRVM_MarkReferencedEdicts(prog);
3394         for(j = 0; j < prog->num_edicts; ++j)
3395         {
3396                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
3397                 if(ed->priv.required->free)
3398                         continue;
3399                 if(!ed->priv.required->mark)
3400                 if(ed->priv.required->allocation_origin)
3401                 {
3402                         Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
3403                         PRVM_ED_Print(prog, ed, NULL);
3404                         Con_Print("\n");
3405                         leaked = true;
3406                 }
3407
3408                 ed->priv.required->mark = 0; // clear marks again when done
3409         }
3410
3411         for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
3412         {
3413                 prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
3414                 if(stringbuffer)
3415                 if(stringbuffer->origin)
3416                 {
3417                         Con_Printf("Open string buffer handle found!\n  Allocated at: %s\n", stringbuffer->origin);
3418                         leaked = true;
3419                 }
3420         }
3421
3422         for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
3423         {
3424                 if(prog->openfiles[i])
3425                 if(prog->openfiles_origin[i])
3426                 {
3427                         Con_Printf("Open file handle found!\n  Allocated at: %s\n", prog->openfiles_origin[i]);
3428                         leaked = true;
3429                 }
3430         }
3431
3432         for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
3433         {
3434                 if(prog->opensearches[i])
3435                 if(prog->opensearches_origin[i])
3436                 {
3437                         Con_Printf("Open search handle found!\n  Allocated at: %s\n", prog->opensearches_origin[i]);
3438                         leaked = true;
3439                 }
3440         }
3441
3442         if(!leaked)
3443                 Con_Printf("Congratulations. No leaks found.\n");
3444 }