5 typedef struct prmemb_s {
9 void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount)
12 ammount = sizeof(prmemb_t)+((ammount + 3)&~3);
13 mem = memalloc(ammount);
14 memset(mem, 0, ammount);
19 mem->level = ((prmemb_t *)memb)->level+1;
22 return ((char *)mem)+sizeof(prmemb_t);
25 int PRHunkMark(progfuncs_t *progfuncs)
27 return ((prmemb_t *)memb)->level;
29 void PRHunkFree(progfuncs_t *progfuncs, int mark)
34 if (memb->level <= mark)
44 //for 64bit systems. :)
45 //addressable memory is memory available to the vm itself for writing.
46 //once allocated, it cannot be freed for the lifetime of the VM.
47 void *PRAddressableAlloc(progfuncs_t *progfuncs, int ammount)
49 ammount = (ammount + 4)&~3; //round up to 4
50 if (addressableused + ammount > addressablesize)
51 Sys_Error("Not enough addressable memory for progs VM");
53 addressableused += ammount;
56 if (!VirtualAlloc (addressablehunk, addressableused, MEM_COMMIT, PAGE_READWRITE))
57 Sys_Error("VirtualAlloc failed. Blame windows.");
60 return &addressablehunk[addressableused-ammount];
63 void PRAddressableFlush(progfuncs_t *progfuncs, int totalammount)
66 if (totalammount < 0) //flush
68 totalammount = addressablesize;
74 VirtualFree(addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
75 addressablehunk = VirtualAlloc (NULL, totalammount, MEM_RESERVE, PAGE_NOACCESS);
77 free(addressablehunk);
78 addressablehunk = malloc(totalammount); //linux will allocate-on-use anyway, which is handy.
79 // memset(addressablehunk, 0xff, totalammount);
82 Sys_Error("Out of memory\n");
83 addressablesize = totalammount;
86 int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
92 max_fields_size = fields_size;
94 prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
95 sv_edicts = PRHunkAlloc(progfuncs, externs->edictsize);
96 prinst->edicttable[0] = sv_edicts;
97 ((edictrun_t*)prinst->edicttable[0])->fields = PRAddressableAlloc(progfuncs, max_fields_size);
98 QC_ClearEdict(progfuncs, sv_edicts);
101 if (externs->entspawn)
102 externs->entspawn((struct edict_s *)sv_edicts, false);
104 return max_fields_size;
106 edictrun_t tempedict; //used as a safty buffer
107 float tempedictfields[2048];
109 void PR_Configure (progfuncs_t *progfuncs, int addressable_size, int max_progs) //can be used to wipe all memory
116 progfuncs->stringtable = 0;
117 QC_StartShares(progfuncs);
118 QC_InitShares(progfuncs);
120 for ( i=1 ; i<maxedicts; i++)
122 e = (edictrun_t *)(prinst->edicttable[i]);
123 prinst->edicttable[i] = NULL;
129 PRHunkFree(progfuncs, 0); //clear mem - our hunk may not be a real hunk.
130 if (addressable_size<0)
131 addressable_size = 8*1024*1024;
132 PRAddressableFlush(progfuncs, addressable_size);
134 pr_progstate = PRHunkAlloc(progfuncs, sizeof(progstate_t) * max_progs);
136 /* for(a = 0; a < max_progs; a++)
138 pr_progstate[a].progs = NULL;
142 maxprogs = max_progs;
145 prinst->reorganisefields = false;
148 prinst->edicttable = &sv_edicts;
149 sv_num_edicts = 1; //set up a safty buffer so things won't go horribly wrong too often
150 sv_edicts=(struct edict_s *)&tempedict;
151 tempedict.readonly = true;
152 tempedict.fields = tempedictfields;
153 tempedict.isfree = false;
158 struct globalvars_s *PR_globals (progfuncs_t *progfuncs, progsnum_t pnum)
162 if (!current_progstate)
163 return NULL; //err.. you've not loaded one yet.
164 return (struct globalvars_s *)current_progstate->globals;
166 return (struct globalvars_s *)pr_progstate[pnum].globals;
169 struct entvars_s *PR_entvars (progfuncs_t *progfuncs, struct edict_s *ed)
171 if (((edictrun_t *)ed)->isfree)
174 return (struct entvars_s *)edvars(ed);
177 int PR_GetFuncArgCount(progfuncs_t *progfuncs, func_t func)
183 pnum = (func & 0xff000000)>>24;
184 fnum = (func & 0x00ffffff);
186 if (pnum >= (unsigned)maxprogs || !pr_progstate[pnum].functions)
188 else if (fnum >= pr_progstate[pnum].progs->numfunctions)
192 f = pr_progstate[pnum].functions + fnum;
197 func_t PR_FindFunc(progfuncs_t *progfuncs, char *funcname, progsnum_t pnum)
202 for (pnum = 0; (unsigned)pnum < maxprogs; pnum++)
204 if (!pr_progstate[pnum].progs)
206 f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
211 else if (pnum == PR_ANYBACK) //run backwards
213 for (pnum = maxprogs-1; pnum >= 0; pnum--)
215 if (!pr_progstate[pnum].progs)
217 f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
223 f = ED_FindFunction(progfuncs, funcname, &pnum, pnum);
230 switch(pr_progstate[pnum].structtype)
234 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.
236 return (f - pr_progstate[pnum].functions) | (pnum << 24);
237 return *(int *)&pr_progstate[pnum].globals[var16->ofs];
240 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.
242 return (f - pr_progstate[pnum].functions) | (pnum << 24);
243 return *(int *)&pr_progstate[pnum].globals[var32->ofs];
245 Sys_Error("Error with def size (PR_FindFunc)");
250 void QC_FindPrefixedGlobals(progfuncs_t *progfuncs, char *prefix, void (*found) (progfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type) )
255 int len = strlen(prefix);
258 for (pnum = 0; pnum < maxprogs; pnum++)
260 if (!pr_progstate[pnum].progs)
263 switch(pr_progstate[pnum].structtype)
267 for (i=1 ; i<pr_progstate[pnum].progs->numglobaldefs ; i++)
269 def16 = &pr_progstate[pnum].globaldefs16[i];
270 if (!strncmp(def16->s_name+progfuncs->stringtable,prefix, len))
271 found(progfuncs, def16->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def16->ofs], def16->type);
276 for (i=1 ; i<pr_progstate[pnum].progs->numglobaldefs ; i++)
278 def32 = &pr_progstate[pnum].globaldefs32[i];
279 if (!strncmp(def32->s_name+progfuncs->stringtable,prefix, len))
280 found(progfuncs, def32->s_name+progfuncs->stringtable, (eval_t *)&pr_progstate[pnum].globals[def32->ofs], def32->type);
287 eval_t *PR_FindGlobal(progfuncs_t *progfuncs, char *globname, progsnum_t pnum, etype_t *type)
292 if (pnum == PR_CURRENT)
293 pnum = pr_typecurrent;
297 for (i = 0; i < maxprogs; i++)
299 if (!pr_progstate[i].progs)
301 ev = PR_FindGlobal(progfuncs, globname, i, type);
307 if (pnum < 0 || (unsigned)pnum >= maxprogs || !pr_progstate[pnum].progs)
309 switch(pr_progstate[pnum].structtype)
313 if (!(var16 = ED_FindGlobalFromProgs16(progfuncs, globname, pnum)))
318 return (eval_t *)&pr_progstate[pnum].globals[var16->ofs];
321 if (!(var32 = ED_FindGlobalFromProgs32(progfuncs, globname, pnum)))
326 return (eval_t *)&pr_progstate[pnum].globals[var32->ofs];
328 Sys_Error("Error with def size (PR_FindGlobal)");
332 void SetGlobalEdict(progfuncs_t *progfuncs, struct edict_s *ed, int ofs)
334 ((int*)pr_globals)[ofs] = EDICT_TO_PROG(progfuncs, ed);
337 char *PR_VarString (progfuncs_t *progfuncs, int first)
340 static char out[1024];
344 for (i=first ; i<pr_argc ; i++)
346 if (G_STRING(OFS_PARM0+i*3))
348 s=G_STRING((OFS_PARM0+i*3)) + progfuncs->stringtable;
349 if (strlen(out) + strlen(s) + 1 >= sizeof(out))
357 int PR_QueryField (progfuncs_t *progfuncs, unsigned int fieldoffset, etype_t *type, char **name, evalc_t *fieldcache)
360 var = ED_FieldAtOfs(progfuncs, fieldoffset);
365 *type = var->type & ~(DEF_SAVEGLOBAL|DEF_SHARED);
370 fieldcache->ofs32 = var;
371 fieldcache->varname = var->name;
377 eval_t *GetEdictFieldValue(progfuncs_t *progfuncs, struct edict_s *ed, char *name, evalc_t *cache)
382 var = ED_FindField(progfuncs, name);
385 return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
389 cache->varname = name;
390 var = ED_FindField(progfuncs, name);
397 cache->varname = var->name;
399 return (void*)~0; //something not null
400 return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[var->ofs]);
402 if (cache->ofs32 == NULL)
404 return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[cache->ofs32->ofs]);
407 struct edict_s *ProgsToEdict (progfuncs_t *progfuncs, int progs)
409 if ((unsigned)progs >= (unsigned)maxedicts)
411 printf("Bad entity index %i\n", progs);
414 return (struct edict_s *)PROG_TO_EDICT(progfuncs, progs);
416 int EdictToProgs (progfuncs_t *progfuncs, struct edict_s *ed)
418 return EDICT_TO_PROG(progfuncs, ed);
421 string_t PR_StringToProgs (progfuncs_t *progfuncs, char *str)
429 // if (str-progfuncs->stringtable < progfuncs->stringtablesize)
430 // return str - progfuncs->stringtable;
432 for (i = prinst->numallocedstrings-1; i >= 0; i--)
434 if (prinst->allocedstrings[i] == str)
435 return (string_t)((unsigned int)i | 0x80000000);
436 if (!prinst->allocedstrings[i])
443 prinst->allocedstrings[i] = str;
444 return (string_t)((unsigned int)i | 0x80000000);
447 prinst->maxallocedstrings += 1024;
448 ntable = memalloc(sizeof(char*) * prinst->maxallocedstrings);
449 memcpy(ntable, prinst->allocedstrings, sizeof(char*) * prinst->numallocedstrings);
450 memset(ntable + prinst->numallocedstrings, 0, sizeof(char*) * (prinst->maxallocedstrings - prinst->numallocedstrings));
451 prinst->numallocedstrings = prinst->maxallocedstrings;
452 if (prinst->allocedstrings)
453 memfree(prinst->allocedstrings);
454 prinst->allocedstrings = ntable;
456 for (i = prinst->numallocedstrings-1; i >= 0; i--)
458 if (!prinst->allocedstrings[i])
460 prinst->allocedstrings[i] = str;
461 return (string_t)((unsigned int)i | 0x80000000);
468 char *PR_RemoveProgsString (progfuncs_t *progfuncs, string_t str)
472 //input string is expected to be an allocated string
473 //if its a temp, or a constant, just return NULL.
474 if ((unsigned int)str & 0xc0000000)
476 if ((unsigned int)str & 0x80000000)
478 int i = str & ~0x80000000;
479 if (i >= prinst->numallocedstrings)
484 if (prinst->allocedstrings[i])
486 ret = prinst->allocedstrings[i];
487 prinst->allocedstrings[i] = NULL; //remove it
493 return NULL; //urm, was freed...
501 char *ASMCALL PR_StringToNative (progfuncs_t *progfuncs, string_t str)
503 if ((unsigned int)str & 0xc0000000)
505 if ((unsigned int)str & 0x80000000)
507 int i = str & ~0x80000000;
508 if (i >= prinst->numallocedstrings)
513 if (prinst->allocedstrings[i])
514 return prinst->allocedstrings[i];
518 return ""; //urm, was freed...
521 if ((unsigned int)str & 0x40000000)
523 int i = str & ~0x40000000;
524 if (i >= prinst->numtempstrings)
529 return prinst->tempstrings[i];
533 if (str >= progfuncs->stringtablesize)
538 return progfuncs->stringtable + str;
542 string_t PR_AllocTempString (progfuncs_t *progfuncs, char *str)
551 if (prinst->numtempstrings == prinst->maxtempstrings)
553 newmax = prinst->maxtempstrings += 1024;
554 prinst->maxtempstrings += 1024;
555 ntable = memalloc(sizeof(char*) * newmax);
556 memcpy(ntable, prinst->tempstrings, sizeof(char*) * prinst->numtempstrings);
557 prinst->maxtempstrings = newmax;
558 if (prinst->tempstrings)
559 memfree(prinst->tempstrings);
560 prinst->tempstrings = ntable;
563 i = prinst->numtempstrings;
567 prinst->numtempstrings++;
569 prinst->tempstrings[i] = memalloc(strlen(str)+1);
570 strcpy(prinst->tempstrings[i], str);
572 return (string_t)((unsigned int)i | 0x40000000);
575 void PR_FreeTemps (progfuncs_t *progfuncs, int depth)
578 if (depth > prinst->numtempstrings)
580 Sys_Error("QC Temp stack inverted\n");
583 for (i = depth; i < prinst->numtempstrings; i++)
585 memfree(prinst->tempstrings[i]);
588 prinst->numtempstrings = depth;
592 struct qcthread_s *PR_ForkStack (progfuncs_t *progfuncs);
593 void PR_ResumeThread (progfuncs_t *progfuncs, struct qcthread_s *thread);
594 void PR_AbortStack (progfuncs_t *progfuncs);
597 void RegisterBuiltin(progfuncs_t *progfncs, char *name, builtin_t func);
599 progfuncs_t deffuncs = {
632 NULL,//filefromnewprogs,
686 QC_FindPrefixedGlobals
690 //defs incase following structure is not passed.
691 struct edict_s *safesv_edicts;
692 int safesv_num_edicts;
695 progexterns_t defexterns = {
698 NULL, //char *(*ReadFile) (char *fname, void *buffer, int len);
699 NULL, //int (*FileSize) (char *fname); //-1 if file does not exist
700 NULL, //bool (*WriteFile) (char *name, void *data, int len);
701 printf, //void (*printf) (char *, ...);
702 (void*)exit, //void (*Sys_Error) (char *, ...);
703 NULL, //void (*Abort) (char *, ...);
704 sizeof(edictrun_t), //int edictsize; //size of edict_t
706 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
707 NULL, //bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
708 NULL, //void (*stateop) (float var, func_t func);
713 //used when loading a game
714 NULL, //builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved.
715 NULL, //void (*loadcompleate) (int edictsize); //notification to reset any pointers.
718 (void*)malloc, //void *(*memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use memalloc if you want)
719 free, //void (*memfree) (void * mem);
722 NULL, //builtin_t *globalbuiltins; //these are available to all progs
723 0, //int numglobalbuiltins;
727 &safetime, //double *gametime;
729 &safesv_edicts, //struct edict_s **sv_edicts;
730 &safesv_num_edicts, //int *sv_num_edicts;
732 NULL, //int (*useeditor) (char *filename, int line, int nump, char **parms);
735 //progfuncs_t *progfuncs = NULL;
738 #undef extensionbuiltin
744 #ifdef QCLIBDLL_EXPORTS
745 __declspec(dllexport)
747 void CloseProgs(progfuncs_t *inst)
749 // extensionbuiltin_t *eb;
750 void (VARGS *f) (void *);
755 f = inst->parms->memfree;
757 for ( i=1 ; i<inst->maxedicts; i++)
759 e = (edictrun_t *)(inst->prinst->edicttable[i]);
760 inst->prinst->edicttable[i] = NULL;
771 VirtualFree(inst->addressablehunk, 0, MEM_RELEASE); //doesn't this look complicated? :p
773 free(inst->addressablehunk);
776 if (inst->prinst->allocedstrings)
777 f(inst->prinst->allocedstrings);
778 inst->prinst->allocedstrings = NULL;
779 if (inst->prinst->tempstrings)
780 f(inst->prinst->tempstrings);
781 inst->prinst->tempstrings = NULL;
785 while(inst->prinst->extensionbuiltin)
787 eb = inst->prinst->extensionbuiltin->prev;
788 f(inst->prinst->extensionbuiltin);
789 inst->prinst->extensionbuiltin = eb;
792 if (inst->prinst->field)
793 f(inst->prinst->field);
794 if (inst->prinst->shares)
795 f(inst->prinst->shares); //free memory
800 void RegisterBuiltin(progfuncs_t *progfuncs, char *name, builtin_t func)
803 extensionbuiltin_t *eb;
804 eb = memalloc(sizeof(extensionbuiltin_t));
805 eb->prev = progfuncs->prinst->extensionbuiltin;
806 progfuncs->prinst->extensionbuiltin = eb;
813 #define QCLIBINT //don't use dllspecifications
816 #if defined(QCLIBDLL_EXPORTS)
817 __declspec(dllexport)
819 progfuncs_t * InitProgs(progexterns_t *ext)
828 if (ext->progsversion > PROGSTRUCT_VERSION)
831 for (i=0;i<sizeof(progexterns_t); i+=4) //make sure there are no items left out.
832 if (!*(int *)((char *)ext+i))
833 *(int *)((char *)ext+i) = *(int *)((char *)&defexterns+i);
837 funcs = ext->memalloc(sizeof(progfuncs_t));
838 memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
840 funcs->prinst = ext->memalloc(sizeof(prinst_t));
841 memset(funcs->prinst,0, sizeof(prinst_t));
843 funcs->pr_trace = &funcs->prinst->pr_trace;
844 funcs->progstate = &funcs->pr_progstate;
845 funcs->callargc = &funcs->pr_argc;
870 void main (int argc, char **argv)
875 funcs = InitProgs(&ext);
876 if (funcs->PR_StartCompile(argc, argv))
877 while(funcs->PR_ContinueCompile());