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