]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - misc/source/fteqcc-src/initlib.c
22602574374f14e82fa5bfc0fa12af87aa8d68bf
[voretournament/voretournament.git] / misc / source / fteqcc-src / initlib.c
1 #define PROGSUSED
2 #include "progsint.h"
3 #include <stdlib.h>
4
5 typedef struct prmemb_s {
6         struct prmemb_s *prev;
7         int level;
8 } prmemb_t;
9 void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount)
10 {
11         prmemb_t *mem;
12         ammount = sizeof(prmemb_t)+((ammount + 3)&~3);
13         mem = memalloc(ammount); 
14         memset(mem, 0, ammount);
15         mem->prev = memb;
16         if (!memb)
17                 mem->level = 1;
18         else
19                 mem->level = ((prmemb_t *)memb)->level+1;
20         memb = mem;
21
22         return ((char *)mem)+sizeof(prmemb_t);
23 }
24
25 int PRHunkMark(progfuncs_t *progfuncs)
26 {
27         return ((prmemb_t *)memb)->level;
28 }
29 void PRHunkFree(progfuncs_t *progfuncs, int mark)
30 {
31         prmemb_t *omem;
32         while(memb)
33         {
34                 if (memb->level <= mark)
35                         return;
36
37                 omem = memb;
38                 memb = memb->prev;
39                 memfree(omem);
40         }
41         return;
42 }
43
44 /*if we ran out of memory, the vm can allocate a new block, but doing so requires fixing up all sorts of pointers*/
45 void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int oldlen)
46 {
47         unsigned int i;
48         edictrun_t *e;
49         for (i=0 ; i<maxedicts; i++)
50         {
51                 e = (edictrun_t *)(prinst->edicttable[i]);
52                 if (e && (char*)e->fields >= oldb && (char*)e->fields < oldb+oldlen)
53                         e->fields = ((char*)e->fields - oldb) + newb;
54         }
55
56         if (progfuncs->stringtable >= oldb && progfuncs->stringtable < oldb+oldlen)
57                 progfuncs->stringtable = (progfuncs->stringtable - oldb) + newb;
58
59         for (i=0; i < maxprogs; i++)
60         {
61                 if ((char*)prinst->progstate[i].globals >= oldb && (char*)prinst->progstate[i].globals < oldb+oldlen)
62                         prinst->progstate[i].globals = (float*)(((char*)prinst->progstate[i].globals - oldb) + newb);
63                 if (prinst->progstate[i].strings >= oldb && prinst->progstate[i].strings < oldb+oldlen)
64                         prinst->progstate[i].strings = (prinst->progstate[i].strings - oldb) + newb;
65         }
66
67         for (i = 0; i < numfields; i++)
68         {
69                 if (field[i].name >= oldb && field[i].name < oldb+oldlen)
70                         field[i].name = (field[i].name - oldb) + newb;
71         }
72
73         externs->addressablerelocated(progfuncs, oldb, newb, oldlen);
74 }
75
76 //for 64bit systems. :)
77 //addressable memory is memory available to the vm itself for writing.
78 //once allocated, it cannot be freed for the lifetime of the VM.
79 void *PRAddressableExtend(progfuncs_t *progfuncs, int ammount)
80 {
81         ammount = (ammount + 4)&~3;     //round up to 4
82         if (prinst->addressableused + ammount > prinst->addressablesize)
83         {
84                 /*only do this if the caller states that it can cope with addressable-block relocations/resizes*/
85                 if (externs->addressablerelocated)
86                 {
87 #ifdef _WIN32
88                         char *newblock;
89                 #if 0//def _DEBUG
90                         int oldtot = addressablesize;
91                 #endif
92                         int newsize = (prinst->addressableused + ammount + 4096) & ~(4096-1);
93                         newblock = VirtualAlloc (NULL, prinst->addressablesize, MEM_RESERVE, PAGE_NOACCESS);
94                         if (newblock)
95                         {
96                                 VirtualAlloc (newblock, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE);
97                                 memcpy(newblock, prinst->addressablehunk, prinst->addressableused);
98                 #if 0//def _DEBUG
99                                 VirtualAlloc (prinst->addressablehunk, oldtot, MEM_RESERVE, PAGE_NOACCESS);
100                 #else
101                                 VirtualFree (prinst->addressablehunk, 0, MEM_RELEASE);
102                 #endif
103                                 PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
104                                 prinst->addressablehunk = newblock;
105                                 prinst->addressablesize = newsize;
106                         }
107 #else
108                         char *newblock;
109                         int newsize = (prinst->addressableused + ammount + 1024*1024) & ~(1024*1024-1);
110                         newblock = realloc(newblock, prinst->addressablesize);
111                         if (newblock)
112                         {
113                                 PRAddressableRelocate(progfuncs, prinst->addressablehunk, newblock, prinst->addressableused);
114                                 prinst->addressablehunk = newblock;
115                                 prinst->addressablesize = newsize;
116                         }
117 #endif
118                 }
119
120                 if (prinst->addressableused + ammount > prinst->addressablesize)
121                         Sys_Error("Not enough addressable memory for progs VM");
122         }
123
124         prinst->addressableused += ammount;
125
126 #ifdef _WIN32
127         if (!VirtualAlloc (prinst->addressablehunk, prinst->addressableused, MEM_COMMIT, PAGE_READWRITE))
128                 Sys_Error("VirtualAlloc failed. Blame windows.");
129 #endif
130
131         return &prinst->addressablehunk[prinst->addressableused-ammount];
132 }
133
134
135 #define MARKER 0xF1E3E3E7u
136 typedef struct
137 {
138         unsigned int next;
139         unsigned int prev;
140         unsigned int size;
141 } qcmemfreeblock_t;
142 typedef struct
143 {
144         unsigned int marker;
145         unsigned int size;
146 } qcmemusedblock_t;
147 static void PF_fmem_unlink(progfuncs_t *pr, qcmemfreeblock_t *p)
148 {
149         qcmemfreeblock_t *np;
150         if (p->prev)
151         {
152                 np = (qcmemfreeblock_t*)(pr->stringtable + p->prev);
153                 np->next = p->next;
154         }
155         else
156                 pr->inst->mfreelist = p->next;
157         if (p->next)
158         {
159                 np = (qcmemfreeblock_t*)(pr->stringtable + p->next);
160                 np->prev = p->prev;
161         }
162 }
163 static void *PR_memalloc (progfuncs_t *progfuncs, unsigned int size)
164 {
165         qcmemfreeblock_t *p, *np;
166         qcmemusedblock_t *ub = NULL;
167         unsigned int b,n;
168         /*round size up*/
169         size = (size+sizeof(qcmemusedblock_t) + 63) & ~63;
170
171         b = prinst->mfreelist;
172         while (b)
173         {
174                 if (b < 0 || b >= prinst->addressableused)
175                 {
176                         printf("PF_memalloc: memory corruption\n");
177                         PR_StackTrace(progfuncs);
178                         return NULL;
179                 }
180                 p = (qcmemfreeblock_t*)(progfuncs->stringtable + b);
181                 if (p->size >= size)
182                 {
183                         if (p->next && p->next < b + p->size ||
184                                 p->next >= prinst->addressableused ||
185                                 b + p->size >= prinst->addressableused ||
186                                 p->prev >= b)
187                         {
188                                 printf("PF_memalloc: memory corruption\n");
189                                 PR_StackTrace(progfuncs);
190                                 return NULL;
191                         }
192
193                         ub = (qcmemusedblock_t*)p;
194                         if (p->size > size + 63)
195                         {
196                                 /*make a new header just after it, with basically the same properties, and shift the important fields over*/
197                                 n = b + size;
198                                 np = (qcmemfreeblock_t*)(progfuncs->stringtable + b + size);
199                                 np->prev = p->prev;
200                                 np->next = p->next;
201                                 np->size = p->size - size;
202                                 if (np->prev)
203                                 {
204                                         p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->prev);
205                                         p->next = n;
206                                 }
207                                 else
208                                         prinst->mfreelist = n;
209                                 if (p->next)
210                                 {
211                                         p = (qcmemfreeblock_t*)(progfuncs->stringtable + np->next);
212                                         p->prev = n;
213                                 }
214                         }
215                         else
216                         {
217                                 size = p->size; /*alloc the entire block*/
218                                 /*unlink this entry*/
219                                 PF_fmem_unlink(progfuncs, p);
220                         }
221                         break;
222                 }
223         }
224
225         /*assign more space*/
226         if (!ub)
227         {
228                 ub = PRAddressableExtend(progfuncs, size);
229                 if (!ub)
230                 {
231                         printf("PF_memalloc: memory exausted\n");
232                         PR_StackTrace(progfuncs);
233                         return NULL;
234                 }
235         }
236         memset(ub, 0, size);
237         ub->marker = MARKER;
238         ub->size = size;
239         return ub+1;
240 }
241 static void PR_memfree (progfuncs_t *progfuncs, void *memptr)
242 {
243         qcmemusedblock_t *ub;
244         qcmemfreeblock_t *p, *np; 
245         unsigned int l, ln;
246         unsigned int size;
247         unsigned int ptr = memptr?((char*)memptr - progfuncs->stringtable):0;
248
249         /*freeing NULL is ignored*/
250         if (!ptr)
251                 return;
252         if (ptr < sizeof(qcmemusedblock_t) || ptr >= prinst->addressableused)
253         {
254                 printf("PF_memfree: pointer invalid - out of range (%u >= %u)\n", ptr, prinst->addressableused);
255                 PR_StackTrace(progfuncs);
256                 return;
257         }
258
259         ub = (qcmemusedblock_t*)(progfuncs->stringtable + ptr);
260         ub--;
261         ptr = (char*)ub - progfuncs->stringtable;
262         if (ub->marker != MARKER || ub->size <= sizeof(*ub) || ptr + ub->size > (unsigned int)prinst->addressableused)
263         {
264                 printf("PF_memfree: memory corruption or double free\n");
265                 PR_StackTrace(progfuncs);
266                 return;
267         }
268         ub->marker = 0;
269         size = ub->size;
270
271         for (ln = prinst->mfreelist, l = 0; ;)
272         {
273                 if (ln < 0 || ln >= prinst->addressableused)
274                 {
275                         printf("PF_memfree: memory corruption\n");
276                         PR_StackTrace(progfuncs);
277                         return;
278                 }
279                 if (!ln || ln >= ptr)
280                 {
281                         np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
282                         if (l && l+np->size>ptr)
283                         {
284                                 printf("PF_memfree: double free\n");
285                                 PR_StackTrace(progfuncs);
286                                 return;
287                         }
288
289                         /*generate the free block, now we know its proper values*/
290                         p = (qcmemfreeblock_t*)(progfuncs->stringtable + ptr);
291                         p->prev = l;
292                         p->next = ln;
293                         p->size = size;
294
295                         /*update the next's previous*/
296                         if (p->next)
297                         {
298                                 np = (qcmemfreeblock_t*)(progfuncs->stringtable + p->next);
299                                 np->prev = p->prev;
300                         
301                                 /*extend this block and kill the next if they are adjacent*/
302                                 if (p->next == ptr + size)
303                                 {
304                                         p->size += np->size; 
305                                         PF_fmem_unlink(progfuncs, np);
306                                 }
307                         }
308
309                         /*update the link to get here*/
310                         if (!l)
311                                 prinst->mfreelist = ptr;
312                         else
313                         {
314                                 np = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
315                                 np->next = ptr;
316
317                                 /*we're adjacent to the previous block, so merge them by killing the newly freed region*/
318                                 if (l + np->size == ptr)
319                                 {
320                                         np->size += size;
321                                         PF_fmem_unlink(progfuncs, p);
322                                 }
323                         }
324                         break;
325                 }
326
327                 l = ln;
328                 p = (qcmemfreeblock_t*)(progfuncs->stringtable + l);
329                 ln = p->next;
330         }
331 }
332
333 void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount)
334 {
335         prinst->addressableused = 0;
336         if (totalammount < 0)   //flush
337         {
338                 totalammount = prinst->addressablesize;
339 //              return;
340         }
341
342 #ifdef _WIN32
343         if (prinst->addressablehunk && prinst->addressablesize != totalammount)
344         {
345                 VirtualFree(prinst->addressablehunk, 0, MEM_RELEASE);   //doesn't this look complicated? :p
346                 prinst->addressablehunk = NULL;
347         }
348         if (!prinst->addressablehunk)
349                 prinst->addressablehunk = VirtualAlloc (prinst->addressablehunk, totalammount, MEM_RESERVE, PAGE_NOACCESS);
350 #else
351         if (prinst->addressablehunk && prinst->addressablesize != totalammount)
352         {
353                 free(prinst->addressablehunk);
354                 prinst->addressablehunk = NULL;
355         }
356         if (!prinst->addressablehunk)
357                 prinst->addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
358 //      memset(prinst->addressablehunk, 0xff, totalammount);
359 #endif
360         if (!prinst->addressablehunk)
361                 Sys_Error("Out of memory\n");
362         prinst->addressablesize = totalammount;
363 }
364
365 int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
366 {
367         maxedicts = max_ents;
368
369         sv_num_edicts = 0;
370
371         max_fields_size = fields_size;
372
373         prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
374         sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize);
375         prinst->edicttable[0] = sv_edicts;
376         ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableExtend(progfuncs, max_fields_size);
377         QC_ClearEdict(progfuncs, sv_edicts);
378         sv_num_edicts = 1;
379
380         if (externs->entspawn)
381                 externs->entspawn((struct edict_s *)sv_edicts, false);
382
383         return max_fields_size;
384 }
385 edictrun_t tempedict;   //used as a safty buffer
386 float tempedictfields[2048];
387
388 void PR_Configure (progfuncs_t *progfuncs, int addressable_size, int max_progs) //can be used to wipe all memory
389 {
390         unsigned int i;
391         edictrun_t *e;
392
393         max_fields_size=0;
394         fields_size = 0;
395         progfuncs->stringtable = 0;
396         QC_StartShares(progfuncs);
397         QC_InitShares(progfuncs);
398
399         for ( i=1 ; i<maxedicts; i++)
400         {
401                 e = (edictrun_t *)(prinst->edicttable[i]);
402                 prinst->edicttable[i] = NULL;
403 //              e->entnum = i;
404                 if (e)
405                         memfree(e);
406         }
407
408         PRHunkFree(progfuncs, 0);       //clear mem - our hunk may not be a real hunk.
409         if (addressable_size<0)
410                 addressable_size = 8*1024*1024;
411         PRAddressableFlush(progfuncs, addressable_size);
412
413         pr_progstate = PRHunkAlloc(progfuncs, sizeof(progstate_t) * max_progs);
414
415 /*              for(a = 0; a < max_progs; a++)
416                 {
417                         pr_progstate[a].progs = NULL;
418                 }               
419 */
420                 
421         maxprogs = max_progs;
422         pr_typecurrent=-1;
423
424         prinst->reorganisefields = false;
425
426         maxedicts = 1;
427         prinst->edicttable = &sv_edicts;
428         sv_num_edicts = 1;      //set up a safty buffer so things won't go horribly wrong too often
429         sv_edicts=(struct edict_s *)&tempedict;
430         tempedict.readonly = true;
431         tempedict.fields = tempedictfields;
432         tempedict.isfree = false;
433 }
434
435
436
437 struct globalvars_s *PR_globals (progfuncs_t *progfuncs, progsnum_t pnum)
438 {
439         if (pnum < 0)
440         {
441                 if (!current_progstate)
442                 {
443                         static float fallback[RESERVED_OFS];
444                         return (struct globalvars_s *)fallback; //err.. you've not loaded one yet.
445                 }
446                 return (struct globalvars_s *)current_progstate->globals;
447         }
448         return (struct globalvars_s *)pr_progstate[pnum].globals;
449 }
450
451 struct entvars_s *PR_entvars (progfuncs_t *progfuncs, struct edict_s *ed)
452 {
453         if (((edictrun_t *)ed)->isfree)
454                 return NULL;
455
456         return (struct entvars_s *)edvars(ed);
457 }
458
459 int PR_GetFuncArgCount(progfuncs_t *progfuncs, func_t func)
460 {
461         unsigned int pnum;
462         unsigned int fnum;
463         dfunction_t *f;
464
465         pnum = (func & 0xff000000)>>24;
466         fnum = (func & 0x00ffffff);
467
468         if (pnum >= (unsigned)maxprogs || !pr_progstate[pnum].functions)
469                 return -1;
470         else if (fnum >= pr_progstate[pnum].progs->numfunctions)
471                 return -1;
472         else
473         {
474                 f = pr_progstate[pnum].functions + fnum;
475                 return f->numparms;
476         }
477 }
478
479 func_t PR_FindFunc(progfuncs_t *progfuncs, char *funcname, progsnum_t pnum)
480 {
481         dfunction_t *f=NULL;
482         if (pnum == PR_ANY)
483         {
484                 for (pnum = 0; (unsigned)pnum < maxprogs; pnum++)
485                 {
486                         if (!pr_progstate[pnum].progs)
487                                 continue;
488                         f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
489                         if (f)
490                                 break;
491                 }
492         }
493         else if (pnum == PR_ANYBACK)    //run backwards
494         {
495                 for (pnum = maxprogs-1; pnum >= 0; pnum--)
496                 {
497                         if (!pr_progstate[pnum].progs)
498                                 continue;
499                         f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
500                         if (f)
501                                 break;
502                 }
503         }
504         else
505                 f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
506         if (!f)
507                 return 0;
508
509         {
510         ddef16_t *var16;
511         ddef32_t *var32;
512         switch(pr_progstate[pnum].structtype)
513         {
514         case PST_KKQWSV:
515         case PST_DEFAULT:
516                 var16 = ED_FindTypeGlobalFromProgs16(progfuncs, funcname, pnum, ev_function);   //we must make sure we actually have a function def - 'light' is defined as a field before it is defined as a function.
517                 if (!var16)
518                         return (f - pr_progstate[pnum].functions) | (pnum << 24);
519                 return *(int *)&pr_progstate[pnum].globals[var16->ofs];
520         case PST_QTEST:
521         case PST_FTE32:
522                 var32 = ED_FindTypeGlobalFromProgs32(progfuncs, funcname, pnum, ev_function);   //we must make sure we actually have a function def - 'light' is defined as a field before it is defined as a function.
523                 if (!var32)
524                         return (f - pr_progstate[pnum].functions) | (pnum << 24);
525                 return *(int *)&pr_progstate[pnum].globals[var32->ofs]; 
526         }
527         Sys_Error("Error with def size (PR_FindFunc)"); 
528         }
529         return 0;
530 }
531
532 void QC_FindPrefixedGlobals(progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) )
533 {
534         unsigned int i;
535         ddef16_t                *def16;
536         ddef32_t                *def32;
537         int len = strlen(prefix);
538         unsigned int pnum;
539
540         for (pnum = 0; pnum < maxprogs; pnum++)
541         {
542                 if (!pr_progstate[pnum].progs)
543                         continue;
544
545                 switch(pr_progstate[pnum].structtype)
546                 {
547                 case PST_DEFAULT:
548                 case PST_KKQWSV:
549                         for (i=1 ; i<pr_progstate[pnum].progs->numglobaldefs ; i++)
550                         {
551                                 def16 = &pr_progstate[pnum].globaldefs16[i];
552                                 if (!strncmp(def16->s_name+progfuncs->stringtable,prefix, len))
553                                         found(progfuncs, def16->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def16->ofs], def16->type);
554                         }
555                         break;
556                 case PST_QTEST:
557                 case PST_FTE32:
558                         for (i=1 ; i<pr_progstate[pnum].progs->numglobaldefs ; i++)
559                         {
560                                 def32 = &pr_progstate[pnum].globaldefs32[i];
561                                 if (!strncmp(def32->s_name+progfuncs->stringtable,prefix, len))
562                                         found(progfuncs, def32->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def32->ofs], def32->type);
563                         }
564                         break;
565                 }
566         }
567 }
568
569 eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum, etype_t *type)
570 {
571         unsigned int i;
572         ddef16_t *var16;
573         ddef32_t *var32;
574         if (pnum == PR_CURRENT)
575                 pnum = pr_typecurrent;
576         if (pnum == PR_ANY)
577         {
578                 eval_t *ev;
579                 for (i = 0; i < maxprogs; i++)
580                 {
581                         if (!pr_progstate[i].progs)
582                                 continue;
583                         ev = PR_FindGlobal(progfuncs, globname, i, type);
584                         if (ev)
585                                 return ev;
586                 }
587                 return NULL;
588         }
589         if (pnum < 0 || (unsigned)pnum >= maxprogs || !pr_progstate[pnum].progs)
590                 return NULL;
591         switch(pr_progstate[pnum].structtype)
592         {
593         case PST_DEFAULT:
594         case PST_KKQWSV:
595                 if (!(var16 = ED_FindGlobalFromProgs16(progfuncs, globname, pnum)))
596                         return NULL;
597
598                 if (type)
599                         *type = var16->type;
600                 return (eval_t *)&pr_progstate[pnum].globals[var16->ofs];
601         case PST_QTEST:
602         case PST_FTE32:
603                 if (!(var32 = ED_FindGlobalFromProgs32(progfuncs, globname, pnum)))
604                         return NULL;
605
606                 if (type)
607                         *type = var32->type;
608                 return (eval_t *)&pr_progstate[pnum].globals[var32->ofs];
609         }
610         Sys_Error("Error with def size (PR_FindGlobal)");
611         return NULL;
612 }
613
614 void SetGlobalEdict(progfuncs_t *progfuncs, struct edict_s *ed, int ofs)
615 {
616         ((int*)pr_globals)[ofs] = EDICT_TO_PROG(progfuncs, ed);
617 }
618
619 char *PR_VarString (progfuncs_t *progfuncs, int first)
620 {
621         int             i;
622         static char out[1024];
623         char *s;
624         
625         out[0] = 0;
626         for (i=first ; i<pr_argc ; i++)
627         {
628                 if (G_STRING(OFS_PARM0+i*3))
629                 {
630                         s=G_STRING((OFS_PARM0+i*3)) + progfuncs->stringtable;
631                         if (strlen(out) + strlen(s) + 1 >= sizeof(out))
632                                 return out;
633                         strcat (out, s);
634                 }
635         }
636         return out;
637 }
638
639 int PR_QueryField (progfuncs_t *progfuncs, unsigned int fieldoffset, etype_t *type, char **name, evalc_t *fieldcache)
640 {
641         fdef_t *var;
642         var = ED_FieldAtOfs(progfuncs, fieldoffset);
643         if (!var)
644                 return false;
645
646         if (type)
647                 *type = var->type & ~(DEF_SAVEGLOBAL|DEF_SHARED);
648         if (name)
649                 *name = var->name;
650         if (fieldcache)
651         {
652                 fieldcache->ofs32 = var;
653                 fieldcache->varname = var->name;
654         }
655                 
656         return true;
657 }
658
659 eval_t *GetEdictFieldValue(progfuncs_t *progfuncs, struct edict_s *ed, char *name, evalc_t *cache)
660 {
661         fdef_t *var;
662         if (!cache)
663         {
664                 var = ED_FindField(progfuncs, name);
665                 if (!var)
666                         return NULL;
667                 return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
668         }
669         if (!cache->varname)
670         {
671                 cache->varname = name;
672                 var = ED_FindField(progfuncs, name);            
673                 if (!var)
674                 {
675                         cache->ofs32 = NULL;
676                         return NULL;
677                 }
678                 cache->ofs32 = var;
679                 cache->varname = var->name;
680                 if (!ed)
681                         return (void*)~0;       //something not null
682                 return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
683         }
684         if (cache->ofs32 == NULL)
685                 return NULL;
686         return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[cache->ofs32->ofs]);
687 }
688
689 struct edict_s *ProgsToEdict (progfuncs_t *progfuncs, int progs)
690 {
691         if ((unsigned)progs >= (unsigned)maxedicts)
692         {
693                 printf("Bad entity index %i\n", progs);
694                 progs = 0;
695         }
696         return (struct edict_s *)PROG_TO_EDICT(progfuncs, progs);
697 }
698 int EdictToProgs (progfuncs_t *progfuncs, struct edict_s *ed)
699 {
700         return EDICT_TO_PROG(progfuncs, ed);
701 }
702
703 string_t PR_StringToProgs                       (progfuncs_t *progfuncs, char *str)
704 {
705         char **ntable;
706         int i, free=-1;
707
708         if (!str)
709                 return 0;
710
711         if (str >= progfuncs->stringtable && str < progfuncs->stringtable + prinst->addressableused)
712                 return str - progfuncs->stringtable;
713
714         for (i = prinst->numallocedstrings-1; i >= 0; i--)
715         {
716                 if (prinst->allocedstrings[i] == str)
717                         return (string_t)((unsigned int)i | 0x80000000);
718                 if (!prinst->allocedstrings[i])
719                         free = i;
720         }
721
722         if (free != -1)
723         {
724                 i = free;
725                 prinst->allocedstrings[i] = str;
726                 return (string_t)((unsigned int)i | 0x80000000);
727         }
728
729         prinst->maxallocedstrings += 1024;
730         ntable = memalloc(sizeof(char*) * prinst->maxallocedstrings); 
731         memcpy(ntable, prinst->allocedstrings, sizeof(char*) * prinst->numallocedstrings);
732         memset(ntable + prinst->numallocedstrings, 0, sizeof(char*) * (prinst->maxallocedstrings - prinst->numallocedstrings));
733         prinst->numallocedstrings = prinst->maxallocedstrings;
734         if (prinst->allocedstrings)
735                 memfree(prinst->allocedstrings);
736         prinst->allocedstrings = ntable;
737
738         for (i = prinst->numallocedstrings-1; i >= 0; i--)
739         {
740                 if (!prinst->allocedstrings[i])
741                 {
742                         prinst->allocedstrings[i] = str;
743                         return (string_t)((unsigned int)i | 0x80000000);
744                 }
745         }
746
747         return 0;
748 }
749
750 char *PR_RemoveProgsString                              (progfuncs_t *progfuncs, string_t str)
751 {
752         char *ret;
753
754         //input string is expected to be an allocated string
755         //if its a temp, or a constant, just return NULL.
756         if ((unsigned int)str & 0xc0000000)
757         {
758                 if ((unsigned int)str & 0x80000000)
759                 {
760                         int i = str & ~0x80000000;
761                         if (i >= prinst->numallocedstrings)
762                         {
763                                 pr_trace = 1;
764                                 return NULL;
765                         }
766                         if (prinst->allocedstrings[i])
767                         {
768                                 ret = prinst->allocedstrings[i];
769                                 prinst->allocedstrings[i] = NULL;       //remove it
770                                 return ret;
771                         }
772                         else
773                         {
774                                 pr_trace = 1;
775                                 return NULL;    //urm, was freed...
776                         }
777                 }
778         }
779         pr_trace = 1;
780         return NULL;
781 }
782
783 char *ASMCALL PR_StringToNative                         (progfuncs_t *progfuncs, string_t str)
784 {
785         if ((unsigned int)str & 0xc0000000)
786         {
787                 if ((unsigned int)str & 0x80000000)
788                 {
789                         int i = str & ~0x80000000;
790                         if (i >= prinst->numallocedstrings)
791                         {
792                                 printf("invalid string %x\n", str);
793                                 PR_StackTrace(progfuncs);
794                                 pr_trace = 1;
795                                 return "";
796                         }
797                         if (prinst->allocedstrings[i])
798                                 return prinst->allocedstrings[i];
799                         else
800                         {
801                                 printf("invalid string %x\n", str);
802                                 PR_StackTrace(progfuncs);
803                                 pr_trace = 1;
804                                 return "";      //urm, was freed...
805                         }
806                 }
807                 if ((unsigned int)str & 0x40000000)
808                 {
809                         int i = str & ~0x40000000;
810                         if (i >= prinst->numtempstrings)
811                         {
812                                 printf("invalid temp string %x\n", str);
813                                 PR_StackTrace(progfuncs);
814                                 pr_trace = 1;
815                                 return "";
816                         }
817                         return prinst->tempstrings[i];
818                 }
819         }
820
821         if ((unsigned int)str >= (unsigned int)prinst->addressableused)
822         {
823                 printf("invalid string offset %x\n", str);
824                 PR_StackTrace(progfuncs);
825                 pr_trace = 1;
826                 return "";
827         }
828         return progfuncs->stringtable + str;
829 }
830
831
832 string_t PR_AllocTempString                     (progfuncs_t *progfuncs, char *str)
833 {
834         char **ntable;
835         int newmax;
836         int i;
837
838         if (!str)
839                 return 0;
840
841         if (prinst->numtempstrings == prinst->maxtempstrings)
842         {
843                 newmax = prinst->maxtempstrings += 1024;
844                 prinst->maxtempstrings += 1024;
845                 ntable = memalloc(sizeof(char*) * newmax);
846                 memcpy(ntable, prinst->tempstrings, sizeof(char*) * prinst->numtempstrings);
847                 prinst->maxtempstrings = newmax;
848                 if (prinst->tempstrings)
849                         memfree(prinst->tempstrings);
850                 prinst->tempstrings = ntable;
851         }
852
853         i = prinst->numtempstrings;
854         if (i == 0x10000000)
855                 return 0;
856
857         prinst->numtempstrings++;
858
859         prinst->tempstrings[i] = memalloc(strlen(str)+1);
860         strcpy(prinst->tempstrings[i], str);
861
862         return (string_t)((unsigned int)i | 0x40000000);
863 }
864 string_t PR_AllocTempStringLen                  (progfuncs_t *progfuncs, char **str, unsigned int len)
865 {
866         char **ntable;
867         int newmax;
868         int i;
869
870         if (!str)
871                 return 0;
872
873         if (prinst->numtempstrings == prinst->maxtempstrings)
874         {
875                 newmax = prinst->maxtempstrings += 1024;
876                 prinst->maxtempstrings += 1024;
877                 ntable = memalloc(sizeof(char*) * newmax);
878                 memcpy(ntable, prinst->tempstrings, sizeof(char*) * prinst->numtempstrings);
879                 prinst->maxtempstrings = newmax;
880                 if (prinst->tempstrings)
881                         memfree(prinst->tempstrings);
882                 prinst->tempstrings = ntable;
883         }
884
885         i = prinst->numtempstrings;
886         if (i == 0x10000000)
887                 return 0;
888
889         prinst->numtempstrings++;
890
891         prinst->tempstrings[i] = memalloc(len);
892         *str = prinst->tempstrings[i];
893
894         return (string_t)((unsigned int)i | 0x40000000);
895 }
896
897 void PR_FreeTemps                       (progfuncs_t *progfuncs, int depth)
898 {
899         int i;
900         if (depth > prinst->numtempstrings)
901         {
902                 Sys_Error("QC Temp stack inverted\n");
903                 return;
904         }
905         for (i = depth; i < prinst->numtempstrings; i++)
906         {
907                 memfree(prinst->tempstrings[i]);
908         }
909
910         prinst->numtempstrings = depth;
911 }
912
913
914 struct qcthread_s *PR_ForkStack (progfuncs_t *progfuncs);
915 void PR_ResumeThread                    (progfuncs_t *progfuncs, struct qcthread_s *thread);
916 void    PR_AbortStack                   (progfuncs_t *progfuncs);
917
918
919 void RegisterBuiltin(progfuncs_t *progfncs, char *name, builtin_t func);
920
921 progfuncs_t deffuncs = {
922         PROGSTRUCT_VERSION,
923         PR_Configure,
924         PR_LoadProgs,
925         PR_InitEnts,
926         PR_ExecuteProgram,
927         PR_SwitchProgs,
928         PR_globals,
929         PR_entvars,
930         PR_RunError,
931         ED_Print,
932         ED_Alloc,
933         ED_Free,
934
935         EDICT_NUM,
936         NUM_FOR_EDICT,
937
938
939         SetGlobalEdict,
940
941         PR_VarString,
942
943         NULL,
944         PR_FindFunc,
945 #ifdef MINIMAL
946         NULL,
947         NULL,
948 #else
949         Comp_Begin,
950         Comp_Continue,
951 #endif
952
953         filefromprogs,
954         NULL,//filefromnewprogs,
955
956         SaveEnts,
957         LoadEnts,
958
959         SaveEnt,
960         RestoreEnt,
961
962         PR_FindGlobal,
963         ED_NewString,
964         (void*)PRHunkAlloc,
965
966         GetEdictFieldValue,
967         ProgsToEdict,
968         EdictToProgs,
969
970         EvaluateDebugString,
971
972         NULL,
973         PR_StackTrace,
974
975         PR_ToggleBreakpoint,
976         0,
977         NULL,
978 #ifdef MINIMAL
979         NULL,
980 #else
981         Decompile,
982 #endif
983         NULL,
984         NULL,
985         RegisterBuiltin,
986
987         0,
988         0,
989
990         PR_ForkStack,
991         PR_ResumeThread,
992         PR_AbortStack,
993
994         0,
995
996         QC_RegisterFieldVar,
997
998         0,
999         0,
1000
1001         PR_AllocTempString,
1002
1003         PR_StringToProgs,
1004         PR_StringToNative,
1005         0,
1006         PR_QueryField,
1007         QC_ClearEdict,
1008         QC_FindPrefixedGlobals,
1009         PR_memalloc,
1010         PR_AllocTempStringLen,
1011         PR_memfree,
1012 };
1013 #undef printf
1014
1015 //defs incase following structure is not passed.
1016 struct edict_s *safesv_edicts;
1017 int safesv_num_edicts;
1018 double safetime=0;
1019
1020 progexterns_t defexterns = {
1021         PROGSTRUCT_VERSION,             
1022
1023         NULL, //char *(*ReadFile) (char *fname, void *buffer, int len);
1024         NULL, //int (*FileSize) (char *fname);  //-1 if file does not exist
1025         NULL, //bool (*WriteFile) (char *name, void *data, int len);
1026         printf, //void (*printf) (char *, ...);
1027         (void*)exit, //void (*Sys_Error) (char *, ...);
1028         NULL, //void (*Abort) (char *, ...);
1029         sizeof(edictrun_t), //int edictsize;    //size of edict_t
1030
1031         NULL, //void (*entspawn) (struct edict_s *ent); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
1032         NULL, //bool (*entcanfree) (struct edict_s *ent);       //return true to stop ent from being freed
1033         NULL, //void (*stateop) (float var, func_t func);
1034         NULL,
1035         NULL,
1036         NULL,
1037
1038         //used when loading a game
1039         NULL, //builtin_t *(*builtinsfor) (int num);    //must return a pointer to the builtins that were used before the state was saved.
1040         NULL, //void (*loadcompleate) (int edictsize);  //notification to reset any pointers.
1041         NULL,
1042
1043         (void*)malloc, //void *(*memalloc) (int size);  //small string allocation       malloced and freed randomly by the executor. (use memalloc if you want)
1044         free, //void (*memfree) (void * mem);
1045
1046
1047         NULL, //builtin_t *globalbuiltins;      //these are available to all progs
1048         0, //int numglobalbuiltins;
1049
1050         PR_NOCOMPILE,
1051
1052         &safetime, //double *gametime;
1053
1054         &safesv_edicts, //struct edict_s **sv_edicts;
1055         &safesv_num_edicts, //int *sv_num_edicts;
1056
1057         NULL, //int (*useeditor) (char *filename, int line, int nump, char **parms);
1058 };
1059
1060 //progfuncs_t *progfuncs = NULL;
1061 #undef memfree
1062 #undef prinst
1063 #undef extensionbuiltin
1064 #undef field
1065 #undef shares
1066 #undef maxedicts
1067 #undef sv_num_edicts
1068
1069
1070 #ifdef QCLIBDLL_EXPORTS
1071 __declspec(dllexport)
1072 #endif 
1073 void CloseProgs(progfuncs_t *inst)
1074 {
1075 //      extensionbuiltin_t *eb;
1076         void (VARGS *f) (void *);
1077
1078         unsigned int i;
1079         edictrun_t *e;
1080
1081         f = inst->parms->memfree;
1082
1083         for ( i=1 ; i<inst->inst->maxedicts; i++)
1084         {
1085                 e = (edictrun_t *)(inst->inst->edicttable[i]);
1086                 inst->inst->edicttable[i] = NULL;
1087                 if (e)
1088                 {
1089 //                      e->entnum = i;
1090                         f(e);
1091                 }
1092         }
1093
1094         PRHunkFree(inst, 0);
1095
1096 #ifdef _WIN32
1097         VirtualFree(inst->inst->addressablehunk, 0, MEM_RELEASE);       //doesn't this look complicated? :p
1098 #else
1099         free(inst->inst->addressablehunk);
1100 #endif
1101
1102         if (inst->inst->allocedstrings)
1103                 f(inst->inst->allocedstrings);
1104         inst->inst->allocedstrings = NULL;
1105         if (inst->inst->tempstrings)
1106                 f(inst->inst->tempstrings);
1107         inst->inst->tempstrings = NULL;
1108
1109
1110 /*
1111         while(inst->prinst->extensionbuiltin)
1112         {
1113                 eb = inst->prinst->extensionbuiltin->prev;
1114                 f(inst->prinst->extensionbuiltin);
1115                 inst->prinst->extensionbuiltin = eb;
1116         }
1117 */
1118         if (inst->inst->field)
1119                 f(inst->inst->field);
1120         if (inst->inst->shares)
1121                 f(inst->inst->shares);  //free memory
1122         f(inst->inst);
1123         f(inst);
1124 }
1125
1126 void RegisterBuiltin(progfuncs_t *progfuncs, char *name, builtin_t func)
1127 {
1128 /*
1129         extensionbuiltin_t *eb;
1130         eb = memalloc(sizeof(extensionbuiltin_t));
1131         eb->prev = progfuncs->prinst->extensionbuiltin;
1132         progfuncs->prinst->extensionbuiltin = eb;
1133         eb->name = name;
1134         eb->func = func;
1135 */
1136 }
1137
1138 #ifndef WIN32
1139 #define QCLIBINT        //don't use dllspecifications
1140 #endif
1141
1142 #if defined(QCLIBDLL_EXPORTS)
1143 __declspec(dllexport)
1144 #endif
1145 progfuncs_t * InitProgs(progexterns_t *ext)
1146 {       
1147         progfuncs_t *funcs;
1148
1149         if (!ext)
1150                 ext = &defexterns;
1151         else
1152         {
1153                 int i;
1154                 if (ext->progsversion > PROGSTRUCT_VERSION)
1155                         return NULL;
1156
1157                 for (i=0;i<sizeof(progexterns_t); i+=4) //make sure there are no items left out.
1158                         if (!*(int *)((char *)ext+i))
1159                                 *(int *)((char *)ext+i) = *(int *)((char *)&defexterns+i);              
1160         }       
1161 #undef memalloc
1162 #undef pr_trace
1163 #undef pr_progstate
1164 #undef pr_argc
1165         funcs = ext->memalloc(sizeof(progfuncs_t));     
1166         memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
1167
1168         funcs->inst = ext->memalloc(sizeof(prinst_t));
1169         memset(funcs->inst,0, sizeof(prinst_t));
1170
1171         funcs->pr_trace = &funcs->inst->pr_trace;
1172         funcs->progstate = &funcs->inst->progstate;
1173         funcs->callargc = &funcs->inst->pr_argc;
1174
1175         funcs->parms = ext;
1176
1177         SetEndian();
1178         
1179         return funcs;
1180 }
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197 #ifdef QCC
1198 void main (int argc, char **argv)
1199 {
1200         progexterns_t ext;
1201
1202         progfuncs_t *funcs;
1203         funcs = InitProgs(&ext);
1204         if (funcs->PR_StartCompile(argc, argv))
1205                 while(funcs->PR_ContinueCompile());
1206 }
1207 #endif