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