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