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