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