]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_edict.c
added curl function: Curl_Begin_ToMemory; will later use this to load stuff into...
[divverent/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.SendFlags                      = PRVM_ED_FindFieldOffset("SendFlags");
1373         prog->fieldoffsets.Version                        = PRVM_ED_FindFieldOffset("Version");
1374         prog->fieldoffsets.alpha                          = PRVM_ED_FindFieldOffset("alpha");
1375         prog->fieldoffsets.ammo_cells1                    = PRVM_ED_FindFieldOffset("ammo_cells1");
1376         prog->fieldoffsets.ammo_lava_nails                = PRVM_ED_FindFieldOffset("ammo_lava_nails");
1377         prog->fieldoffsets.ammo_multi_rockets             = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
1378         prog->fieldoffsets.ammo_nails1                    = PRVM_ED_FindFieldOffset("ammo_nails1");
1379         prog->fieldoffsets.ammo_plasma                    = PRVM_ED_FindFieldOffset("ammo_plasma");
1380         prog->fieldoffsets.ammo_rockets1                  = PRVM_ED_FindFieldOffset("ammo_rockets1");
1381         prog->fieldoffsets.ammo_shells1                   = PRVM_ED_FindFieldOffset("ammo_shells1");
1382         prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
1383         prog->fieldoffsets.button3                        = PRVM_ED_FindFieldOffset("button3");
1384         prog->fieldoffsets.button4                        = PRVM_ED_FindFieldOffset("button4");
1385         prog->fieldoffsets.button5                        = PRVM_ED_FindFieldOffset("button5");
1386         prog->fieldoffsets.button6                        = PRVM_ED_FindFieldOffset("button6");
1387         prog->fieldoffsets.button7                        = PRVM_ED_FindFieldOffset("button7");
1388         prog->fieldoffsets.button8                        = PRVM_ED_FindFieldOffset("button8");
1389         prog->fieldoffsets.button9                        = PRVM_ED_FindFieldOffset("button9");
1390         prog->fieldoffsets.button10                       = PRVM_ED_FindFieldOffset("button10");
1391         prog->fieldoffsets.button11                       = PRVM_ED_FindFieldOffset("button11");
1392         prog->fieldoffsets.button12                       = PRVM_ED_FindFieldOffset("button12");
1393         prog->fieldoffsets.button13                       = PRVM_ED_FindFieldOffset("button13");
1394         prog->fieldoffsets.button14                       = PRVM_ED_FindFieldOffset("button14");
1395         prog->fieldoffsets.button15                       = PRVM_ED_FindFieldOffset("button15");
1396         prog->fieldoffsets.button16                       = PRVM_ED_FindFieldOffset("button16");
1397         prog->fieldoffsets.buttonchat                     = PRVM_ED_FindFieldOffset("buttonchat");
1398         prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
1399         prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
1400         prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
1401         prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
1402         prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
1403         prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
1404         prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
1405         prog->fieldoffsets.cursor_active                  = PRVM_ED_FindFieldOffset("cursor_active");
1406         prog->fieldoffsets.cursor_screen                  = PRVM_ED_FindFieldOffset("cursor_screen");
1407         prog->fieldoffsets.cursor_trace_endpos            = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
1408         prog->fieldoffsets.cursor_trace_ent               = PRVM_ED_FindFieldOffset("cursor_trace_ent");
1409         prog->fieldoffsets.cursor_trace_start             = PRVM_ED_FindFieldOffset("cursor_trace_start");
1410         prog->fieldoffsets.customizeentityforclient       = PRVM_ED_FindFieldOffset("customizeentityforclient");
1411         prog->fieldoffsets.dimension_hit                  = PRVM_ED_FindFieldOffset("dimension_hit");
1412         prog->fieldoffsets.dimension_solid                = PRVM_ED_FindFieldOffset("dimension_solid");
1413         prog->fieldoffsets.disableclientprediction        = PRVM_ED_FindFieldOffset("disableclientprediction");
1414         prog->fieldoffsets.dphitcontentsmask              = PRVM_ED_FindFieldOffset("dphitcontentsmask");
1415         prog->fieldoffsets.drawonlytoclient               = PRVM_ED_FindFieldOffset("drawonlytoclient");
1416         prog->fieldoffsets.exteriormodeltoclient          = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
1417         prog->fieldoffsets.fatness                        = PRVM_ED_FindFieldOffset("fatness");
1418         prog->fieldoffsets.forceshader                    = PRVM_ED_FindFieldOffset("forceshader");
1419         prog->fieldoffsets.frame                          = PRVM_ED_FindFieldOffset("frame");
1420         prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
1421         prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
1422         prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
1423         prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
1424         prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
1425         prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
1426         prog->fieldoffsets.glow_trail                     = PRVM_ED_FindFieldOffset("glow_trail");
1427         prog->fieldoffsets.gravity                        = PRVM_ED_FindFieldOffset("gravity");
1428         prog->fieldoffsets.groundentity                   = PRVM_ED_FindFieldOffset("groundentity");
1429         prog->fieldoffsets.hull                           = PRVM_ED_FindFieldOffset("hull");
1430         prog->fieldoffsets.ideal_yaw                      = PRVM_ED_FindFieldOffset("ideal_yaw");
1431         prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
1432         prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
1433         prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
1434         prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
1435         prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
1436         prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
1437         prog->fieldoffsets.movement                       = PRVM_ED_FindFieldOffset("movement");
1438         prog->fieldoffsets.movetypesteplandevent          = PRVM_ED_FindFieldOffset("movetypesteplandevent");
1439         prog->fieldoffsets.netaddress                     = PRVM_ED_FindFieldOffset("netaddress");
1440         prog->fieldoffsets.nextthink                      = PRVM_ED_FindFieldOffset("nextthink");
1441         prog->fieldoffsets.nodrawtoclient                 = PRVM_ED_FindFieldOffset("nodrawtoclient");
1442         prog->fieldoffsets.pflags                         = PRVM_ED_FindFieldOffset("pflags");
1443         prog->fieldoffsets.ping                           = PRVM_ED_FindFieldOffset("ping");
1444         prog->fieldoffsets.pitch_speed                    = PRVM_ED_FindFieldOffset("pitch_speed");
1445         prog->fieldoffsets.playermodel                    = PRVM_ED_FindFieldOffset("playermodel");
1446         prog->fieldoffsets.playerskin                     = PRVM_ED_FindFieldOffset("playerskin");
1447         prog->fieldoffsets.pmodel                         = PRVM_ED_FindFieldOffset("pmodel");
1448         prog->fieldoffsets.punchvector                    = PRVM_ED_FindFieldOffset("punchvector");
1449         prog->fieldoffsets.renderamt                      = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
1450         prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
1451         prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
1452         prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
1453         prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
1454         prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
1455         prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
1456         prog->fieldoffsets.think                          = PRVM_ED_FindFieldOffset("think");
1457         prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
1458         prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
1459         prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
1460         prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
1461         prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
1462         prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
1463         prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
1464         prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
1465         prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
1466         prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
1467         prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
1468         prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
1469         prog->funcoffsets.CSQC_InputEvent                 = PRVM_ED_FindFunctionOffset("CSQC_InputEvent");
1470         prog->funcoffsets.CSQC_Parse_CenterPrint          = PRVM_ED_FindFunctionOffset("CSQC_Parse_CenterPrint");
1471         prog->funcoffsets.CSQC_Parse_Print                = PRVM_ED_FindFunctionOffset("CSQC_Parse_Print");
1472         prog->funcoffsets.CSQC_Parse_StuffCmd             = PRVM_ED_FindFunctionOffset("CSQC_Parse_StuffCmd");
1473         prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
1474         prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
1475         prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
1476         prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
1477         prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
1478         prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
1479         prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
1480         prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
1481         prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
1482         prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
1483         prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
1484         prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
1485         prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
1486         prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
1487         prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
1488         prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
1489         prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
1490         prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
1491         prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
1492         prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
1493         prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
1494         prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
1495         prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
1496         prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
1497         prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
1498         prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
1499         prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
1500         prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
1501         prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
1502         prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
1503         prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
1504         prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
1505         prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
1506         prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
1507         prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
1508         prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
1509         prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
1510         prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
1511         prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
1512         prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
1513         prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
1514         prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
1515
1516         // menu qc only uses some functions, nothing else
1517         prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
1518         prog->funcoffsets.m_init                          = PRVM_ED_FindFunctionOffset("m_init");
1519         prog->funcoffsets.m_keydown                       = PRVM_ED_FindFunctionOffset("m_keydown");
1520         prog->funcoffsets.m_keyup                         = PRVM_ED_FindFunctionOffset("m_keyup");
1521         prog->funcoffsets.m_shutdown                      = PRVM_ED_FindFunctionOffset("m_shutdown");
1522         prog->funcoffsets.m_toggle                        = PRVM_ED_FindFunctionOffset("m_toggle");
1523 }
1524
1525 // not used
1526 /*
1527 typedef struct dpfield_s
1528 {
1529         int type;
1530         char *string;
1531 }
1532 dpfield_t;
1533
1534 #define DPFIELDS (sizeof(dpfields) / sizeof(dpfield_t))
1535
1536 dpfield_t dpfields[] =
1537 {
1538 };
1539 */
1540
1541 /*
1542 ===============
1543 PRVM_ResetProg
1544 ===============
1545 */
1546
1547 void PRVM_LeakTest();
1548 void PRVM_ResetProg()
1549 {
1550         PRVM_LeakTest();
1551         PRVM_GCALL(reset_cmd)();
1552         Mem_FreePool(&prog->progs_mempool);
1553         memset(prog,0,sizeof(prvm_prog_t));
1554         prog->starttime = Sys_DoubleTime();
1555 }
1556
1557 /*
1558 ===============
1559 PRVM_LoadLNO
1560 ===============
1561 */
1562 void PRVM_LoadLNO( const char *progname ) {
1563         fs_offset_t filesize;
1564         unsigned char *lno;
1565         unsigned int *header;
1566         char filename[512];
1567
1568         FS_StripExtension( progname, filename, sizeof( filename ) );
1569         strlcat( filename, ".lno", sizeof( filename ) );
1570
1571         lno = FS_LoadFile( filename, tempmempool, false, &filesize );
1572         if( !lno ) {
1573                 return;
1574         }
1575
1576 /*
1577 <Spike>    SafeWrite (h, &lnotype, sizeof(int));
1578 <Spike>    SafeWrite (h, &version, sizeof(int));
1579 <Spike>    SafeWrite (h, &numglobaldefs, sizeof(int));
1580 <Spike>    SafeWrite (h, &numpr_globals, sizeof(int));
1581 <Spike>    SafeWrite (h, &numfielddefs, sizeof(int));
1582 <Spike>    SafeWrite (h, &numstatements, sizeof(int));
1583 <Spike>    SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1584 */
1585         if( (unsigned) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) {
1586                 Mem_Free(lno);
1587                 return;
1588         }
1589
1590         header = (unsigned int *) lno;
1591         if( header[ 0 ] == *(unsigned int *) "LNOF" &&
1592                 LittleLong( header[ 1 ] ) == 1 &&
1593                 (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs &&
1594                 (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals &&
1595                 (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs &&
1596                 (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements )
1597         {
1598                 prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) );
1599                 memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) );
1600         }
1601         Mem_Free( lno );
1602 }
1603
1604 /*
1605 ===============
1606 PRVM_LoadProgs
1607 ===============
1608 */
1609 void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_required_field_t *required_field, int numrequiredglobals, char **required_global)
1610 {
1611         int i;
1612         dstatement_t *st;
1613         ddef_t *infielddefs;
1614         dfunction_t *dfunctions;
1615         fs_offset_t filesize;
1616
1617         if( prog->loaded ) {
1618                 PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
1619         }
1620
1621         prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
1622         if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
1623                 PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
1624
1625         Con_DPrintf("%s programs occupy %iK.\n", PRVM_NAME, (int)(filesize/1024));
1626
1627         prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize);
1628
1629 // byte swap the header
1630         for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++)
1631                 ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] );
1632
1633         if (prog->progs->version != PROG_VERSION)
1634                 PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, PROG_VERSION);
1635         if (prog->progs->crc != prog->headercrc && prog->progs->crc != prog->headercrc2)
1636                 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);
1637
1638         //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions);
1639         dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions);
1640
1641         if (prog->progs->ofs_strings + prog->progs->numstrings >= (int)filesize)
1642                 PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename);
1643         prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
1644         prog->stringssize = prog->progs->numstrings;
1645
1646         prog->numknownstrings = 0;
1647         prog->maxknownstrings = 0;
1648         prog->knownstrings = NULL;
1649         prog->knownstrings_freeable = NULL;
1650
1651         Mem_ExpandableArray_NewArray(&prog->stringbuffersarray, prog->progs_mempool, sizeof(prvm_stringbuffer_t), 64);
1652
1653         prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs);
1654
1655         // we need to expand the fielddefs list to include all the engine fields,
1656         // so allocate a new place for it
1657         infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs);
1658         //                                                                                              ( + DPFIELDS                       )
1659         prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numrequiredfields) * sizeof(ddef_t));
1660
1661         prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements);
1662
1663         prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile));
1664
1665         // moved edict_size calculation down below field adding code
1666
1667         //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals);
1668         prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals);
1669
1670 // byte swap the lumps
1671         for (i=0 ; i<prog->progs->numstatements ; i++)
1672         {
1673                 prog->statements[i].op = LittleShort(prog->statements[i].op);
1674                 prog->statements[i].a = LittleShort(prog->statements[i].a);
1675                 prog->statements[i].b = LittleShort(prog->statements[i].b);
1676                 prog->statements[i].c = LittleShort(prog->statements[i].c);
1677         }
1678
1679         prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions);
1680         for (i = 0;i < prog->progs->numfunctions;i++)
1681         {
1682                 prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement);
1683                 prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start);
1684                 prog->functions[i].s_name = LittleLong (dfunctions[i].s_name);
1685                 prog->functions[i].s_file = LittleLong (dfunctions[i].s_file);
1686                 prog->functions[i].numparms = LittleLong (dfunctions[i].numparms);
1687                 prog->functions[i].locals = LittleLong (dfunctions[i].locals);
1688                 memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size));
1689         }
1690
1691         for (i=0 ; i<prog->progs->numglobaldefs ; i++)
1692         {
1693                 prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type);
1694                 prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs);
1695                 prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name);
1696         }
1697
1698         // copy the progs fields to the new fields list
1699         for (i = 0;i < prog->progs->numfielddefs;i++)
1700         {
1701                 prog->fielddefs[i].type = LittleShort (infielddefs[i].type);
1702                 if (prog->fielddefs[i].type & DEF_SAVEGLOBAL)
1703                         PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME);
1704                 prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs);
1705                 prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name);
1706         }
1707
1708         // append the required fields
1709         for (i = 0;i < (int) numrequiredfields;i++)
1710         {
1711                 prog->fielddefs[prog->progs->numfielddefs].type = required_field[i].type;
1712                 prog->fielddefs[prog->progs->numfielddefs].ofs = prog->progs->entityfields;
1713                 prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(required_field[i].name);
1714                 if (prog->fielddefs[prog->progs->numfielddefs].type == ev_vector)
1715                         prog->progs->entityfields += 3;
1716                 else
1717                         prog->progs->entityfields++;
1718                 prog->progs->numfielddefs++;
1719         }
1720
1721         // check required functions
1722         for(i=0 ; i < numrequiredfunc ; i++)
1723                 if(PRVM_ED_FindFunction(required_func[i]) == 0)
1724                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_func[i], filename);
1725
1726         // check required globals
1727         for(i=0 ; i < numrequiredglobals ; i++)
1728                 if(PRVM_ED_FindGlobal(required_global[i]) == 0)
1729                         PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, required_global[i], filename);
1730
1731         for (i=0 ; i<prog->progs->numglobals ; i++)
1732                 ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]);
1733
1734         // moved edict_size calculation down here, below field adding code
1735         // LordHavoc: this no longer includes the prvm_edict_t header
1736         prog->edict_size = prog->progs->entityfields * 4;
1737         prog->edictareasize = prog->edict_size * prog->limit_edicts;
1738
1739         // LordHavoc: bounds check anything static
1740         for (i = 0,st = prog->statements;i < prog->progs->numstatements;i++,st++)
1741         {
1742                 switch (st->op)
1743                 {
1744                 case OP_IF:
1745                 case OP_IFNOT:
1746                         if ((unsigned short) st->a >= prog->progs->numglobals || st->b + i < 0 || st->b + i >= prog->progs->numstatements)
1747                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME);
1748                         break;
1749                 case OP_GOTO:
1750                         if (st->a + i < 0 || st->a + i >= prog->progs->numstatements)
1751                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME);
1752                         break;
1753                 // global global global
1754                 case OP_ADD_F:
1755                 case OP_ADD_V:
1756                 case OP_SUB_F:
1757                 case OP_SUB_V:
1758                 case OP_MUL_F:
1759                 case OP_MUL_V:
1760                 case OP_MUL_FV:
1761                 case OP_MUL_VF:
1762                 case OP_DIV_F:
1763                 case OP_BITAND:
1764                 case OP_BITOR:
1765                 case OP_GE:
1766                 case OP_LE:
1767                 case OP_GT:
1768                 case OP_LT:
1769                 case OP_AND:
1770                 case OP_OR:
1771                 case OP_EQ_F:
1772                 case OP_EQ_V:
1773                 case OP_EQ_S:
1774                 case OP_EQ_E:
1775                 case OP_EQ_FNC:
1776                 case OP_NE_F:
1777                 case OP_NE_V:
1778                 case OP_NE_S:
1779                 case OP_NE_E:
1780                 case OP_NE_FNC:
1781                 case OP_ADDRESS:
1782                 case OP_LOAD_F:
1783                 case OP_LOAD_FLD:
1784                 case OP_LOAD_ENT:
1785                 case OP_LOAD_S:
1786                 case OP_LOAD_FNC:
1787                 case OP_LOAD_V:
1788                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1789                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i);
1790                         break;
1791                 // global none global
1792                 case OP_NOT_F:
1793                 case OP_NOT_V:
1794                 case OP_NOT_S:
1795                 case OP_NOT_FNC:
1796                 case OP_NOT_ENT:
1797                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->c >= prog->progs->numglobals)
1798                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1799                         break;
1800                 // 2 globals
1801                 case OP_STOREP_F:
1802                 case OP_STOREP_ENT:
1803                 case OP_STOREP_FLD:
1804                 case OP_STOREP_S:
1805                 case OP_STOREP_FNC:
1806                 case OP_STORE_F:
1807                 case OP_STORE_ENT:
1808                 case OP_STORE_FLD:
1809                 case OP_STORE_S:
1810                 case OP_STORE_FNC:
1811                 case OP_STATE:
1812                 case OP_STOREP_V:
1813                 case OP_STORE_V:
1814                         if ((unsigned short) st->a >= prog->progs->numglobals || (unsigned short) st->b >= prog->progs->numglobals)
1815                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1816                         break;
1817                 // 1 global
1818                 case OP_CALL0:
1819                 case OP_CALL1:
1820                 case OP_CALL2:
1821                 case OP_CALL3:
1822                 case OP_CALL4:
1823                 case OP_CALL5:
1824                 case OP_CALL6:
1825                 case OP_CALL7:
1826                 case OP_CALL8:
1827                 case OP_DONE:
1828                 case OP_RETURN:
1829                         if ((unsigned short) st->a >= prog->progs->numglobals)
1830                                 PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME);
1831                         break;
1832                 default:
1833                         Con_DPrintf("PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME);
1834                         break;
1835                 }
1836         }
1837
1838         PRVM_LoadLNO(filename);
1839
1840         PRVM_Init_Exec();
1841
1842         prog->loaded = TRUE;
1843
1844         // set flags & ddef_ts in prog
1845
1846         prog->flag = 0;
1847
1848         PRVM_FindOffsets();
1849
1850         PRVM_GCALL(init_cmd)();
1851
1852         // init mempools
1853         PRVM_MEM_Alloc();
1854 }
1855
1856
1857 void PRVM_Fields_f (void)
1858 {
1859         int i, j, ednum, used, usedamount;
1860         int *counts;
1861         char tempstring[MAX_INPUTLINE], tempstring2[260];
1862         const char *name;
1863         prvm_edict_t *ed;
1864         ddef_t *d;
1865         int *v;
1866
1867         // TODO
1868         /*
1869         if (!sv.active)
1870         {
1871                 Con_Print("no progs loaded\n");
1872                 return;
1873         }
1874         */
1875
1876         if(Cmd_Argc() != 2)
1877         {
1878                 Con_Print("prvm_fields <program name>\n");
1879                 return;
1880         }
1881
1882         PRVM_Begin;
1883         if(!PRVM_SetProgFromString(Cmd_Argv(1)))
1884                 return;
1885
1886         counts = (int *)Mem_Alloc(tempmempool, prog->progs->numfielddefs * sizeof(int));
1887         for (ednum = 0;ednum < prog->max_edicts;ednum++)
1888         {
1889                 ed = PRVM_EDICT_NUM(ednum);
1890                 if (ed->priv.required->free)
1891                         continue;
1892                 for (i = 1;i < prog->progs->numfielddefs;i++)
1893                 {
1894                         d = &prog->fielddefs[i];
1895                         name = PRVM_GetString(d->s_name);
1896                         if (name[strlen(name)-2] == '_')
1897                                 continue;       // skip _x, _y, _z vars
1898                         v = (int *)((char *)ed->fields.vp + d->ofs*4);
1899                         // if the value is still all 0, skip the field
1900                         for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
1901                         {
1902                                 if (v[j])
1903                                 {
1904                                         counts[i]++;
1905                                         break;
1906                                 }
1907                         }
1908                 }
1909         }
1910         used = 0;
1911         usedamount = 0;
1912         tempstring[0] = 0;
1913         for (i = 0;i < prog->progs->numfielddefs;i++)
1914         {
1915                 d = &prog->fielddefs[i];
1916                 name = PRVM_GetString(d->s_name);
1917                 if (name[strlen(name)-2] == '_')
1918                         continue;       // skip _x, _y, _z vars
1919                 switch(d->type & ~DEF_SAVEGLOBAL)
1920                 {
1921                 case ev_string:
1922                         strlcat(tempstring, "string   ", sizeof(tempstring));
1923                         break;
1924                 case ev_entity:
1925                         strlcat(tempstring, "entity   ", sizeof(tempstring));
1926                         break;
1927                 case ev_function:
1928                         strlcat(tempstring, "function ", sizeof(tempstring));
1929                         break;
1930                 case ev_field:
1931                         strlcat(tempstring, "field    ", sizeof(tempstring));
1932                         break;
1933                 case ev_void:
1934                         strlcat(tempstring, "void     ", sizeof(tempstring));
1935                         break;
1936                 case ev_float:
1937                         strlcat(tempstring, "float    ", sizeof(tempstring));
1938                         break;
1939                 case ev_vector:
1940                         strlcat(tempstring, "vector   ", sizeof(tempstring));
1941                         break;
1942                 case ev_pointer:
1943                         strlcat(tempstring, "pointer  ", sizeof(tempstring));
1944                         break;
1945                 default:
1946                         dpsnprintf (tempstring2, sizeof(tempstring2), "bad type %i ", d->type & ~DEF_SAVEGLOBAL);
1947                         strlcat(tempstring, tempstring2, sizeof(tempstring));
1948                         break;
1949                 }
1950                 if (strlen(name) > sizeof(tempstring2)-4)
1951                 {
1952                         memcpy (tempstring2, name, sizeof(tempstring2)-4);
1953                         tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.';
1954                         tempstring2[sizeof(tempstring2)-1] = 0;
1955                         name = tempstring2;
1956                 }
1957                 strlcat(tempstring, name, sizeof(tempstring));
1958                 for (j = (int)strlen(name);j < 25;j++)
1959                         strlcat(tempstring, " ", sizeof(tempstring));
1960                 dpsnprintf(tempstring2, sizeof(tempstring2), "%5d", counts[i]);
1961                 strlcat(tempstring, tempstring2, sizeof(tempstring));
1962                 strlcat(tempstring, "\n", sizeof(tempstring));
1963                 if (strlen(tempstring) >= sizeof(tempstring)/2)
1964                 {
1965                         Con_Print(tempstring);
1966                         tempstring[0] = 0;
1967                 }
1968                 if (counts[i])
1969                 {
1970                         used++;
1971                         usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL];
1972                 }
1973         }
1974         Mem_Free(counts);
1975         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);
1976
1977         PRVM_End;
1978 }
1979
1980 void PRVM_Globals_f (void)
1981 {
1982         int i;
1983         const char *wildcard;
1984         int numculled;
1985                 numculled = 0;
1986         // TODO
1987         /*if (!sv.active)
1988         {
1989                 Con_Print("no progs loaded\n");
1990                 return;
1991         }*/
1992         if(Cmd_Argc () < 2 || Cmd_Argc() > 3)
1993         {
1994                 Con_Print("prvm_globals <program name> <optional name wildcard>\n");
1995                 return;
1996         }
1997
1998         PRVM_Begin;
1999         if(!PRVM_SetProgFromString (Cmd_Argv (1)))
2000                 return;
2001
2002         if( Cmd_Argc() == 3)
2003                 wildcard = Cmd_Argv(2);
2004         else
2005                 wildcard = NULL;
2006
2007         Con_Printf("%s :", PRVM_NAME);
2008
2009         for (i = 0;i < prog->progs->numglobaldefs;i++)
2010         {
2011                 if(wildcard)
2012                         if( !matchpattern( PRVM_GetString(prog->globaldefs[i].s_name), wildcard, 1) )
2013                         {
2014                                 numculled++;
2015                                 continue;
2016                         }
2017                 Con_Printf("%s\n", PRVM_GetString(prog->globaldefs[i].s_name));
2018         }
2019         Con_Printf("%i global variables, %i culled, totalling %i bytes\n", prog->progs->numglobals, numculled, prog->progs->numglobals * 4);
2020
2021         PRVM_End;
2022 }
2023
2024 /*
2025 ===============
2026 PRVM_Global
2027 ===============
2028 */
2029 void PRVM_Global_f(void)
2030 {
2031         ddef_t *global;
2032         if( Cmd_Argc() != 3 ) {
2033                 Con_Printf( "prvm_global <program name> <global name>\n" );
2034                 return;
2035         }
2036
2037         PRVM_Begin;
2038         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2039                 return;
2040
2041         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2042         if( !global )
2043                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2044         else
2045                 Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) );
2046         PRVM_End;
2047 }
2048
2049 /*
2050 ===============
2051 PRVM_GlobalSet
2052 ===============
2053 */
2054 void PRVM_GlobalSet_f(void)
2055 {
2056         ddef_t *global;
2057         if( Cmd_Argc() != 4 ) {
2058                 Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
2059                 return;
2060         }
2061
2062         PRVM_Begin;
2063         if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
2064                 return;
2065
2066         global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
2067         if( !global )
2068                 Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
2069         else
2070                 PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3), true );
2071         PRVM_End;
2072 }
2073
2074 /*
2075 ===============
2076 PRVM_Init
2077 ===============
2078 */
2079 void PRVM_Init (void)
2080 {
2081         Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f, "print all data about an entity number in the selected VM (server, client, menu)");
2082         Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f, "prints all data about all entities in the selected VM (server, client, menu)");
2083         Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f, "prints number of active entities in the selected VM (server, client, menu)");
2084         Cmd_AddCommand ("prvm_profile", PRVM_Profile_f, "prints execution statistics about the most used QuakeC functions in the selected VM (server, client, menu)");
2085         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)");
2086         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)");
2087         Cmd_AddCommand ("prvm_globals", PRVM_Globals_f, "prints all global variables in the selected VM (server, client, menu)");
2088         Cmd_AddCommand ("prvm_global", PRVM_Global_f, "prints value of a specified global variable in the selected VM (server, client, menu)");
2089         Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f, "sets value of a specified global variable in the selected VM (server, client, menu)");
2090         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)");
2091         Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f, "prints a disassembly (QuakeC instructions) of the specified function in the selected VM (server, client, menu)");
2092         Cmd_AddCommand ("cl_cmd", PRVM_GameCommand_Client_f, "calls the client QC function GameCommand with the supplied string as argument");
2093         Cmd_AddCommand ("menu_cmd", PRVM_GameCommand_Menu_f, "calls the menu QC function GameCommand with the supplied string as argument");
2094         Cmd_AddCommand ("sv_cmd", PRVM_GameCommand_Server_f, "calls the server QC function GameCommand with the supplied string as argument");
2095         // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
2096 #ifdef PRVM_BOUNDSCHECK_CVAR
2097         Cvar_RegisterVariable (&prvm_boundscheck);
2098 #endif
2099         Cvar_RegisterVariable (&prvm_traceqc);
2100         Cvar_RegisterVariable (&prvm_statementprofiling);
2101         Cvar_RegisterVariable (&prvm_backtraceforwarnings);
2102         Cvar_RegisterVariable (&prvm_leaktest);
2103         Cvar_RegisterVariable (&prvm_leaktest_ignore_classnames);
2104         Cvar_RegisterVariable (&prvm_errordump);
2105
2106         //VM_Cmd_Init();
2107 }
2108
2109 /*
2110 ===============
2111 PRVM_InitProg
2112 ===============
2113 */
2114 void PRVM_InitProg(int prognr)
2115 {
2116         if(prognr < 0 || prognr >= PRVM_MAXPROGS)
2117                 Sys_Error("PRVM_InitProg: Invalid program number %i",prognr);
2118
2119         prog = &prog_list[prognr];
2120
2121         if(prog->loaded)
2122                 PRVM_ResetProg();
2123
2124         memset(prog, 0, sizeof(prvm_prog_t));
2125         prog->starttime = Sys_DoubleTime();
2126
2127         prog->error_cmd = Host_Error;
2128         prog->leaktest_active = prvm_leaktest.integer;
2129 }
2130
2131 int PRVM_GetProgNr()
2132 {
2133         return prog - prog_list;
2134 }
2135
2136 void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
2137 {
2138         return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
2139 }
2140
2141 void _PRVM_Free(void *buffer, const char *filename, int fileline)
2142 {
2143         _Mem_Free(buffer, filename, fileline);
2144 }
2145
2146 void _PRVM_FreeAll(const char *filename, int fileline)
2147 {
2148         prog->progs = NULL;
2149         prog->fielddefs = NULL;
2150         prog->functions = NULL;
2151         _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
2152 }
2153
2154 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
2155 unsigned int PRVM_EDICT_NUM_ERROR(unsigned int n, char *filename, int fileline)
2156 {
2157         PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline);
2158         return 0;
2159 }
2160
2161 /*
2162 int NUM_FOR_EDICT_ERROR(prvm_edict_t *e)
2163 {
2164         PRVM_ERROR ("PRVM_NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, prog->edicts, e - prog->edicts);
2165         return 0;
2166 }
2167
2168 int PRVM_NUM_FOR_EDICT(prvm_edict_t *e)
2169 {
2170         int n;
2171         n = e - prog->edicts;
2172         if ((unsigned int)n >= prog->limit_edicts)
2173                 Host_Error ("PRVM_NUM_FOR_EDICT: bad pointer");
2174         return n;
2175 }
2176
2177 //int NoCrash_NUM_FOR_EDICT(prvm_edict_t *e)
2178 //{
2179 //      return e - prog->edicts;
2180 //}
2181
2182 //#define       PRVM_EDICT_TO_PROG(e) ((unsigned char *)(((prvm_edict_t *)e)->v) - (unsigned char *)(prog->edictsfields))
2183 //#define PRVM_PROG_TO_EDICT(e) (prog->edicts + ((e) / (progs->entityfields * 4)))
2184 int PRVM_EDICT_TO_PROG(prvm_edict_t *e)
2185 {
2186         int n;
2187         n = e - prog->edicts;
2188         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2189                 Host_Error("PRVM_EDICT_TO_PROG: invalid edict %8p (number %i compared to world at %8p)", e, n, prog->edicts);
2190         return n;// EXPERIMENTAL
2191         //return (unsigned char *)e->v - (unsigned char *)prog->edictsfields;
2192 }
2193 prvm_edict_t *PRVM_PROG_TO_EDICT(int n)
2194 {
2195         if ((unsigned int)n >= (unsigned int)prog->max_edicts)
2196                 Host_Error("PRVM_PROG_TO_EDICT: invalid edict number %i", n);
2197         return prog->edicts + n; // EXPERIMENTAL
2198         //return prog->edicts + ((n) / (progs->entityfields * 4));
2199 }
2200 */
2201
2202
2203 sizebuf_t vm_tempstringsbuf;
2204
2205 const char *PRVM_GetString(int num)
2206 {
2207         if (num >= 0)
2208         {
2209                 if (num < prog->stringssize)
2210                         return prog->strings + num;
2211                 else
2212 #if 1
2213                 if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
2214                 {
2215                         num -= prog->stringssize;
2216                         if (num < vm_tempstringsbuf.cursize)
2217                                 return (char *)vm_tempstringsbuf.data + num;
2218                         else
2219                         {
2220                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2221                                 return "";
2222                         }
2223                 }
2224                 else
2225 #endif
2226                 {
2227                         VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)\n", num, prog->stringssize);
2228                         return "";
2229                 }
2230         }
2231         else
2232         {
2233                 num = -1 - num;
2234 #if 0
2235                 if (num >= (1<<30))
2236                 {
2237                         // special range reserved for tempstrings
2238                         num -= (1<<30);
2239                         if (num < vm_tempstringsbuf.cursize)
2240                                 return (char *)vm_tempstringsbuf.data + num;
2241                         else
2242                         {
2243                                 VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)\n", num, vm_tempstringsbuf.cursize);
2244                                 return "";
2245                         }
2246                 }
2247                 else
2248 #endif
2249                 if (num < prog->numknownstrings)
2250                 {
2251                         if (!prog->knownstrings[num])
2252                                 VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)\n", num);
2253                         return prog->knownstrings[num];
2254                 }
2255                 else
2256                 {
2257                         VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)\n", num, prog->numknownstrings);
2258                         return "";
2259                 }
2260         }
2261 }
2262
2263 int PRVM_SetEngineString(const char *s)
2264 {
2265         int i;
2266         if (!s)
2267                 return 0;
2268         if (s >= prog->strings && s <= prog->strings + prog->stringssize)
2269                 PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
2270         // if it's in the tempstrings area, use a reserved range
2271         // (otherwise we'd get millions of useless string offsets cluttering the database)
2272         if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
2273 #if 1
2274                 return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
2275 #else
2276                 return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
2277 #endif
2278         // see if it's a known string address
2279         for (i = 0;i < prog->numknownstrings;i++)
2280                 if (prog->knownstrings[i] == s)
2281                         return -1 - i;
2282         // new unknown engine string
2283         if (developer.integer >= 200)
2284                 Con_Printf("new engine string %p = \"%s\"\n", s, s);
2285         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2286                 if (!prog->knownstrings[i])
2287                         break;
2288         if (i >= prog->numknownstrings)
2289         {
2290                 if (i >= prog->maxknownstrings)
2291                 {
2292                         const char **oldstrings = prog->knownstrings;
2293                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2294                         const char **oldstrings_origin = prog->knownstrings_origin;
2295                         prog->maxknownstrings += 128;
2296                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2297                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2298                         if(prog->leaktest_active)
2299                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2300                         if (prog->numknownstrings)
2301                         {
2302                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2303                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2304                                 if(prog->leaktest_active)
2305                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2306                         }
2307                 }
2308                 prog->numknownstrings++;
2309         }
2310         prog->firstfreeknownstring = i + 1;
2311         prog->knownstrings[i] = s;
2312         prog->knownstrings_freeable[i] = false;
2313         if(prog->leaktest_active)
2314                 prog->knownstrings_origin[i] = NULL;
2315         return -1 - i;
2316 }
2317
2318 // temp string handling
2319
2320 // all tempstrings go into this buffer consecutively, and it is reset
2321 // whenever PRVM_ExecuteProgram returns to the engine
2322 // (technically each PRVM_ExecuteProgram call saves the cursize value and
2323 //  restores it on return, so multiple recursive calls can share the same
2324 //  buffer)
2325 // the buffer size is automatically grown as needed
2326
2327 int PRVM_SetTempString(const char *s)
2328 {
2329         int size;
2330         char *t;
2331         if (!s)
2332                 return 0;
2333         size = (int)strlen(s) + 1;
2334         if (developer.integer >= 300)
2335                 Con_Printf("PRVM_SetTempString: cursize %i, size %i\n", vm_tempstringsbuf.cursize, size);
2336         if (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2337         {
2338                 sizebuf_t old = vm_tempstringsbuf;
2339                 if (vm_tempstringsbuf.cursize + size >= 1<<28)
2340                         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);
2341                 vm_tempstringsbuf.maxsize = max(vm_tempstringsbuf.maxsize, 65536);
2342                 while (vm_tempstringsbuf.maxsize < vm_tempstringsbuf.cursize + size)
2343                         vm_tempstringsbuf.maxsize *= 2;
2344                 if (vm_tempstringsbuf.maxsize != old.maxsize || vm_tempstringsbuf.data == NULL)
2345                 {
2346                         if (developer.integer >= 100)
2347                                 Con_Printf("PRVM_SetTempString: enlarging tempstrings buffer (%iKB -> %iKB)\n", old.maxsize/1024, vm_tempstringsbuf.maxsize/1024);
2348                         vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
2349                         if (old.cursize)
2350                                 memcpy(vm_tempstringsbuf.data, old.data, old.cursize);
2351                         if (old.data)
2352                                 Mem_Free(old.data);
2353                 }
2354         }
2355         t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
2356         memcpy(t, s, size);
2357         vm_tempstringsbuf.cursize += size;
2358         return PRVM_SetEngineString(t);
2359 }
2360
2361 int PRVM_AllocString(size_t bufferlength, char **pointer)
2362 {
2363         int i;
2364         if (!bufferlength)
2365                 return 0;
2366         for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++)
2367                 if (!prog->knownstrings[i])
2368                         break;
2369         if (i >= prog->numknownstrings)
2370         {
2371                 if (i >= prog->maxknownstrings)
2372                 {
2373                         const char **oldstrings = prog->knownstrings;
2374                         const unsigned char *oldstrings_freeable = prog->knownstrings_freeable;
2375                         const char **oldstrings_origin = prog->knownstrings_origin;
2376                         prog->maxknownstrings += 128;
2377                         prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2378                         prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char));
2379                         if(prog->leaktest_active)
2380                                 prog->knownstrings_origin = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
2381                         if (prog->numknownstrings)
2382                         {
2383                                 memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
2384                                 memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char));
2385                                 if(prog->leaktest_active)
2386                                         memcpy((char **)prog->knownstrings_origin, oldstrings_origin, prog->numknownstrings * sizeof(char *));
2387                         }
2388                         // TODO why not Mem_Free the old ones?
2389                 }
2390                 prog->numknownstrings++;
2391         }
2392         prog->firstfreeknownstring = i + 1;
2393         prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength);
2394         prog->knownstrings_freeable[i] = true;
2395         if(prog->leaktest_active)
2396                 prog->knownstrings_origin[i] = PRVM_AllocationOrigin();
2397         if (pointer)
2398                 *pointer = (char *)(prog->knownstrings[i]);
2399         return -1 - i;
2400 }
2401
2402 void PRVM_FreeString(int num)
2403 {
2404         if (num == 0)
2405                 PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string");
2406         else if (num >= 0 && num < prog->stringssize)
2407                 PRVM_ERROR("PRVM_FreeString: attempt to free a constant string");
2408         else if (num < 0 && num >= -prog->numknownstrings)
2409         {
2410                 num = -1 - num;
2411                 if (!prog->knownstrings[num])
2412                         PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string");
2413                 if (!prog->knownstrings_freeable[num])
2414                         PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine");
2415                 PRVM_Free((char *)prog->knownstrings[num]);
2416                 if(prog->leaktest_active)
2417                         if(prog->knownstrings_origin[num])
2418                                 PRVM_Free((char *)prog->knownstrings_origin[num]);
2419                 prog->knownstrings[num] = NULL;
2420                 prog->knownstrings_freeable[num] = false;
2421                 prog->firstfreeknownstring = min(prog->firstfreeknownstring, num);
2422         }
2423         else
2424                 PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num);
2425 }
2426
2427 static qboolean PRVM_IsStringReferenced(string_t string)
2428 {
2429         int i, j;
2430
2431         for (i = 0;i < prog->progs->numglobaldefs;i++)
2432         {
2433                 ddef_t *d = &prog->globaldefs[i];
2434                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2435                         continue;
2436                 if(string == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->string)
2437                         return true;
2438         }
2439
2440         for(j = 0; j < prog->num_edicts; ++j)
2441         {
2442                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2443                 if (ed->priv.required->free)
2444                         continue;
2445                 for (i=0; i<prog->progs->numfielddefs; ++i)
2446                 {
2447                         ddef_t *d = &prog->fielddefs[i];
2448                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_string)
2449                                 continue;
2450                         if(string == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->string)
2451                                 return true;
2452                 }
2453         }
2454
2455         return false;
2456 }
2457
2458 static qboolean PRVM_IsEdictRelevant(prvm_edict_t *edict)
2459 {
2460         if(PRVM_NUM_FOR_EDICT(edict) <= prog->reserved_edicts)
2461                 return true; // world or clients
2462         switch(prog - prog_list)
2463         {
2464                 case PRVM_SERVERPROG:
2465                         {
2466                                 entvars_t *ev = edict->fields.server;
2467                                 if(ev->solid) // can block other stuff, or is a trigger?
2468                                         return true;
2469                                 if(ev->modelindex) // visible ent?
2470                                         return true;
2471                                 if(ev->effects) // particle effect?
2472                                         return true;
2473                                 if(ev->think) // has a think function?
2474                                         if(ev->nextthink > 0) // that actually will eventually run?
2475                                                 return true;
2476                                 if(ev->takedamage)
2477                                         return true;
2478                                 if(*prvm_leaktest_ignore_classnames.string)
2479                                 {
2480                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2481                                                 return true;
2482                                 }
2483                         }
2484                         break;
2485                 case PRVM_CLIENTPROG:
2486                         {
2487                                 // TODO someone add more stuff here
2488                                 cl_entvars_t *ev = edict->fields.client;
2489                                 if(ev->entnum) // csqc networked
2490                                         return true;
2491                                 if(ev->modelindex) // visible ent?
2492                                         return true;
2493                                 if(ev->effects) // particle effect?
2494                                         return true;
2495                                 if(ev->think) // has a think function?
2496                                         if(ev->nextthink > 0) // that actually will eventually run?
2497                                                 return true;
2498                                 if(*prvm_leaktest_ignore_classnames.string)
2499                                 {
2500                                         if(strstr(va(" %s ", prvm_leaktest_ignore_classnames.string), va(" %s ", PRVM_GetString(ev->classname))))
2501                                                 return true;
2502                                 }
2503                         }
2504                         break;
2505                 case PRVM_MENUPROG:
2506                         // menu prog does not have classnames
2507                         break;
2508         }
2509         return false;
2510 }
2511
2512 static qboolean PRVM_IsEdictReferenced(prvm_edict_t *edict, int mark)
2513 {
2514         int i, j;
2515         int edictnum = PRVM_NUM_FOR_EDICT(edict);
2516         const char *targetname = NULL;
2517
2518         switch(prog - prog_list)
2519         {
2520                 case PRVM_SERVERPROG:
2521                         targetname = PRVM_GetString(edict->fields.server->targetname);
2522                         break;
2523         }
2524
2525         if(targetname)
2526                 if(!*targetname) // ""
2527                         targetname = NULL;
2528
2529         for (i = 0;i < prog->progs->numglobaldefs;i++)
2530         {
2531                 ddef_t *d = &prog->globaldefs[i];
2532                 if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2533                         continue;
2534                 if(edictnum == ((prvm_eval_t *) &prog->globals.generic[d->ofs])->edict)
2535                         return true;
2536         }
2537
2538         for(j = 0; j < prog->num_edicts; ++j)
2539         {
2540                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2541                 if (ed->priv.required->mark < mark)
2542                         continue;
2543                 if(ed == edict)
2544                         continue;
2545                 if(targetname)
2546                 {
2547                         const char *target = PRVM_GetString(ed->fields.server->target);
2548                         if(target)
2549                                 if(!strcmp(target, targetname))
2550                                         return true;
2551                 }
2552                 for (i=0; i<prog->progs->numfielddefs; ++i)
2553                 {
2554                         ddef_t *d = &prog->fielddefs[i];
2555                         if((etype_t)((int) d->type & ~DEF_SAVEGLOBAL) != ev_entity)
2556                                 continue;
2557                         if(edictnum == ((prvm_eval_t *) &((float*)ed->fields.vp)[d->ofs])->edict)
2558                                 return true;
2559                 }
2560         }
2561
2562         return false;
2563 }
2564
2565 static void PRVM_MarkReferencedEdicts()
2566 {
2567         int j;
2568         qboolean found_new;
2569         int stage;
2570
2571         for(j = 0; j < prog->num_edicts; ++j)
2572         {
2573                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2574                 if(ed->priv.required->free)
2575                         continue;
2576                 ed->priv.required->mark = PRVM_IsEdictRelevant(ed) ? 1 : 0;
2577         }
2578
2579         stage = 1;
2580         do
2581         {
2582                 found_new = false;
2583                 for(j = 0; j < prog->num_edicts; ++j)
2584                 {
2585                         prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2586                         if(ed->priv.required->free)
2587                                 continue;
2588                         if(ed->priv.required->mark)
2589                                 continue;
2590                         if(PRVM_IsEdictReferenced(ed, stage))
2591                         {
2592                                 ed->priv.required->mark = stage + 1;
2593                                 found_new = true;
2594                         }
2595                 }
2596                 ++stage;
2597         }
2598         while(found_new);
2599         Con_DPrintf("leak check used %d stages to find all references\n", stage);
2600 }
2601
2602 void PRVM_LeakTest()
2603 {
2604         int i, j;
2605         qboolean leaked = false;
2606
2607         if(!prog->leaktest_active)
2608                 return;
2609
2610         // 1. Strings
2611         for (i = 0; i < prog->numknownstrings; ++i)
2612         {
2613                 if(prog->knownstrings[i])
2614                 if(prog->knownstrings_freeable[i])
2615                 if(prog->knownstrings_origin[i])
2616                 if(!PRVM_IsStringReferenced(-1 - i))
2617                 {
2618                         Con_Printf("Unreferenced string found!\n  Value: %s\n  Origin: %s\n", prog->knownstrings[i], prog->knownstrings_origin[i]);
2619                         leaked = true;
2620                 }
2621         }
2622
2623         // 2. Edicts
2624         PRVM_MarkReferencedEdicts();
2625         for(j = 0; j < prog->num_edicts; ++j)
2626         {
2627                 prvm_edict_t *ed = PRVM_EDICT_NUM(j);
2628                 if(ed->priv.required->free)
2629                         continue;
2630                 if(!ed->priv.required->mark)
2631                 if(ed->priv.required->allocation_origin)
2632                 {
2633                         Con_Printf("Unreferenced edict found!\n  Allocated at: %s\n", ed->priv.required->allocation_origin);
2634                         PRVM_ED_Print(ed, NULL);
2635                         Con_Print("\n");
2636                         leaked = true;
2637                 }
2638         }
2639
2640         for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); ++i)
2641         {
2642                 prvm_stringbuffer_t *stringbuffer = Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
2643                 if(stringbuffer)
2644                 if(stringbuffer->origin)
2645                 {
2646                         Con_Printf("Open string buffer handle found!\n  Allocated at: %s\n", stringbuffer->origin);
2647                         leaked = true;
2648                 }
2649         }
2650
2651         for(i = 0; i < PRVM_MAX_OPENFILES; ++i)
2652         {
2653                 if(prog->openfiles[i])
2654                 if(prog->openfiles_origin[i])
2655                 {
2656                         Con_Printf("Open file handle found!\n  Allocated at: %s\n", prog->openfiles_origin[i]);
2657                         leaked = true;
2658                 }
2659         }
2660
2661         for(i = 0; i < PRVM_MAX_OPENSEARCHES; ++i)
2662         {
2663                 if(prog->opensearches[i])
2664                 if(prog->opensearches_origin[i])
2665                 {
2666                         Con_Printf("Open search handle found!\n  Allocated at: %s\n", prog->opensearches_origin[i]);
2667                         leaked = true;
2668                 }
2669         }
2670
2671         if(!leaked)
2672                 Con_Printf("Congratulations. No leaks found.\n");
2673 }