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