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