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