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