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