2004-08-23 01:38:21 +00:00
# define PROGSUSED
# include "progsint.h"
2005-04-17 02:22:51 +00:00
# include <stdlib.h>
2004-08-23 01:38:21 +00:00
typedef struct prmemb_s {
struct prmemb_s * prev ;
int level ;
} prmemb_t ;
void * PRHunkAlloc ( progfuncs_t * progfuncs , int ammount )
{
2005-03-28 00:11:59 +00:00
prmemb_t * mem ;
ammount = sizeof ( prmemb_t ) + ( ( ammount + 3 ) & ~ 3 ) ;
mem = memalloc ( ammount ) ;
memset ( mem , 0 , ammount ) ;
mem - > prev = memb ;
if ( ! memb )
mem - > level = 1 ;
else
mem - > level = ( ( prmemb_t * ) memb ) - > level + 1 ;
memb = mem ;
2004-08-23 01:38:21 +00:00
2005-03-28 00:11:59 +00:00
return ( ( char * ) mem ) + sizeof ( prmemb_t ) ;
2004-08-23 01:38:21 +00:00
}
int PRHunkMark ( progfuncs_t * progfuncs )
{
2005-03-28 00:11:59 +00:00
return ( ( prmemb_t * ) memb ) - > level ;
2004-08-23 01:38:21 +00:00
}
void PRHunkFree ( progfuncs_t * progfuncs , int mark )
{
2005-03-28 00:11:59 +00:00
prmemb_t * omem ;
while ( memb )
2004-08-23 01:38:21 +00:00
{
2005-03-28 00:11:59 +00:00
if ( memb - > level < = mark )
return ;
2004-08-23 01:38:21 +00:00
2005-03-28 00:11:59 +00:00
omem = memb ;
memb = memb - > prev ;
memfree ( omem ) ;
}
return ;
}
//for 64bit systems. :)
//addressable memory is memory available to the vm itself for writing.
//once allocated, it cannot be freed for the lifetime of the VM.
void * PRAddressableAlloc ( progfuncs_t * progfuncs , int ammount )
{
ammount = ( ammount + 4 ) & ~ 3 ; //round up to 4
if ( addressableused + ammount > addressablesize )
Sys_Error ( " Not enough addressable memory for progs VM " ) ;
addressableused + = ammount ;
# ifdef _WIN32
if ( ! VirtualAlloc ( addressablehunk , addressableused , MEM_COMMIT , PAGE_READWRITE ) )
Sys_Error ( " VirtualAlloc failed. Blame windows. " ) ;
# endif
return & addressablehunk [ addressableused - ammount ] ;
}
2005-05-15 18:49:04 +00:00
2005-03-28 00:11:59 +00:00
void PRAddressableFlush ( progfuncs_t * progfuncs , int totalammount )
{
addressableused = 0 ;
if ( totalammount < 0 ) //flush
{
totalammount = addressablesize ;
// return;
2004-08-23 01:38:21 +00:00
}
2005-03-28 00:11:59 +00:00
if ( addressablehunk )
# ifdef _WIN32
VirtualFree ( addressablehunk , 0 , MEM_RELEASE ) ; //doesn't this look complicated? :p
addressablehunk = VirtualAlloc ( NULL , totalammount , MEM_RESERVE , PAGE_NOACCESS ) ;
# else
free ( addressablehunk ) ;
addressablehunk = malloc ( totalammount ) ; //linux will allocate-on-use anyway, which is handy.
2005-05-17 02:36:54 +00:00
// memset(addressablehunk, 0xff, totalammount);
2005-03-28 00:11:59 +00:00
# endif
addressablesize = totalammount ;
2004-08-23 01:38:21 +00:00
}
int PR_InitEnts ( progfuncs_t * progfuncs , int max_ents )
{
maxedicts = max_ents ;
sv_num_edicts = 0 ;
2005-03-28 00:11:59 +00:00
max_fields_size = fields_size ;
2004-08-23 01:38:21 +00:00
prinst - > edicttable = PRHunkAlloc ( progfuncs , maxedicts * sizeof ( struct edicts_s * ) ) ;
2005-03-28 00:11:59 +00:00
sv_edicts = PRHunkAlloc ( progfuncs , externs - > edictsize ) ;
2004-08-23 01:38:21 +00:00
prinst - > edicttable [ 0 ] = sv_edicts ;
2005-03-28 00:11:59 +00:00
( ( edictrun_t * ) prinst - > edicttable [ 0 ] ) - > fields = PRAddressableAlloc ( progfuncs , max_fields_size ) ;
2005-05-17 02:36:54 +00:00
ED_ClearEdict ( progfuncs , sv_edicts ) ;
2004-08-23 01:38:21 +00:00
sv_num_edicts = 1 ;
2005-03-28 00:11:59 +00:00
return max_fields_size ;
2004-08-23 01:38:21 +00:00
}
char tempedicts [ 2048 ] ; //used as a safty buffer
2005-03-28 00:11:59 +00:00
void PR_Configure ( progfuncs_t * progfuncs , int addressable_size , int max_progs ) //can be used to wipe all memory
2004-08-23 01:38:21 +00:00
{
int i ;
edictrun_t * e ;
// int a;
2005-03-28 00:11:59 +00:00
max_fields_size = 0 ;
fields_size = 0 ;
2004-08-23 01:38:21 +00:00
progfuncs - > stringtable = 0 ;
QC_StartShares ( progfuncs ) ;
QC_InitShares ( progfuncs ) ;
for ( i = 1 ; i < maxedicts ; i + + )
{
2004-09-20 23:25:38 +00:00
e = ( edictrun_t * ) ( prinst - > edicttable [ i ] ) ;
2004-08-23 01:38:21 +00:00
prinst - > edicttable [ i ] = NULL ;
// e->entnum = i;
if ( e )
memfree ( e ) ;
}
PRHunkFree ( progfuncs , 0 ) ; //clear mem - our hunk may not be a real hunk.
2005-03-28 00:11:59 +00:00
if ( addressable_size < 0 )
addressable_size = 8 * 1024 * 1024 ;
PRAddressableFlush ( progfuncs , addressable_size ) ;
2004-08-23 01:38:21 +00:00
pr_progstate = PRHunkAlloc ( progfuncs , sizeof ( progstate_t ) * max_progs ) ;
/* for(a = 0; a < max_progs; a++)
{
pr_progstate [ a ] . progs = NULL ;
}
*/
maxprogs = max_progs ;
pr_typecurrent = - 1 ;
prinst - > reorganisefields = false ;
maxedicts = 1 ;
sv_num_edicts = 1 ; //set up a safty buffer so things won't go horribly wrong too often
sv_edicts = ( struct edict_s * ) tempedicts ;
2005-03-28 00:11:59 +00:00
( ( edictrun_t * ) sv_edicts ) - > readonly = true ;
2004-08-23 01:38:21 +00:00
}
struct globalvars_s * PR_globals ( progfuncs_t * progfuncs , progsnum_t pnum )
{
if ( pnum < 0 )
2005-04-02 18:00:45 +00:00
{
if ( ! current_progstate )
return NULL ; //err.. you've not loaded one yet.
2004-08-23 01:38:21 +00:00
return ( struct globalvars_s * ) current_progstate - > globals ;
2005-04-02 18:00:45 +00:00
}
2004-08-23 01:38:21 +00:00
return ( struct globalvars_s * ) pr_progstate [ pnum ] . globals ;
}
struct entvars_s * PR_entvars ( progfuncs_t * progfuncs , struct edict_s * ed )
{
if ( ( ( edictrun_t * ) ed ) - > isfree )
return NULL ;
return ( struct entvars_s * ) edvars ( ed ) ;
}
func_t PR_FindFunc ( progfuncs_t * progfuncs , char * funcname , progsnum_t pnum )
{
dfunction_t * f = NULL ;
2005-04-02 18:00:45 +00:00
if ( pnum = = PR_ANY )
{
for ( pnum = 0 ; pnum < maxprogs ; pnum + + )
{
if ( ! pr_progstate [ pnum ] . progs )
continue ;
f = ED_FindFunction ( progfuncs , funcname , & pnum , pnum ) ;
if ( f )
break ;
}
}
else if ( pnum = = PR_ANYBACK ) //run backwards
2004-08-23 01:38:21 +00:00
{
2005-04-02 18:00:45 +00:00
for ( pnum = maxprogs - 1 ; pnum > = 0 ; pnum - - )
2004-08-23 01:38:21 +00:00
{
if ( ! pr_progstate [ pnum ] . progs )
continue ;
f = ED_FindFunction ( progfuncs , funcname , & pnum , pnum ) ;
if ( f )
break ;
}
}
else
f = ED_FindFunction ( progfuncs , funcname , & pnum , pnum ) ;
if ( ! f )
return 0 ;
{
ddef16_t * var16 ;
ddef32_t * var32 ;
switch ( pr_progstate [ pnum ] . intsize )
{
case 24 :
case 16 :
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.
if ( ! var16 )
return ( f - pr_progstate [ pnum ] . functions ) | ( pnum < < 24 ) ;
return * ( int * ) & pr_progstate [ pnum ] . globals [ var16 - > ofs ] ;
case 32 :
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.
if ( ! var32 )
2005-04-02 18:00:45 +00:00
return ( f - pr_progstate [ pnum ] . functions ) | ( pnum < < 24 ) ;
2004-08-23 01:38:21 +00:00
return * ( int * ) & pr_progstate [ pnum ] . globals [ var32 - > ofs ] ;
}
Sys_Error ( " Error with def size (PR_FindFunc) " ) ;
}
return 0 ;
}
eval_t * PR_FindGlobal ( progfuncs_t * progfuncs , char * globname , progsnum_t pnum )
{
ddef16_t * var16 ;
ddef32_t * var32 ;
2004-11-23 00:23:25 +00:00
if ( pnum = = PR_CURRENT )
pnum = pr_typecurrent ;
2004-08-23 01:38:21 +00:00
switch ( pr_progstate [ pnum ] . intsize )
{
case 16 :
case 24 :
if ( ! ( var16 = ED_FindGlobalFromProgs16 ( progfuncs , globname , pnum ) ) )
return NULL ;
return ( eval_t * ) & pr_progstate [ pnum ] . globals [ var16 - > ofs ] ;
case 32 :
if ( ! ( var32 = ED_FindGlobalFromProgs32 ( progfuncs , globname , pnum ) ) )
return NULL ;
return ( eval_t * ) & pr_progstate [ pnum ] . globals [ var32 - > ofs ] ;
}
Sys_Error ( " Error with def size (PR_FindGlobal) " ) ;
return NULL ;
}
void SetGlobalEdict ( progfuncs_t * progfuncs , struct edict_s * ed , int ofs )
{
2005-03-28 00:11:59 +00:00
( ( int * ) pr_globals ) [ ofs ] = EDICT_TO_PROG ( progfuncs , ed ) ;
2004-08-23 01:38:21 +00:00
}
char * PR_VarString ( progfuncs_t * progfuncs , int first )
{
int i ;
static char out [ 1024 ] ;
char * s ;
out [ 0 ] = 0 ;
for ( i = first ; i < pr_argc ; i + + )
{
if ( G_STRING ( OFS_PARM0 + i * 3 ) )
{
2005-05-15 18:49:04 +00:00
s = G_STRING ( ( OFS_PARM0 + i * 3 ) ) + progfuncs - > stringtable ;
strcat ( out , s ) ;
2004-08-23 01:38:21 +00:00
//#ifdef PARANOID
if ( strlen ( out ) + 1 > = sizeof ( out ) )
Sys_Error ( " VarString (builtin call ending with strings) exceeded maximum string length of %i chars " , sizeof ( out ) ) ;
//#endif
}
}
return out ;
}
eval_t * GetEdictFieldValue ( progfuncs_t * progfuncs , struct edict_s * ed , char * name , evalc_t * cache )
{
fdef_t * var ;
if ( ! cache )
{
var = ED_FindField ( progfuncs , name ) ;
if ( ! var )
return NULL ;
2005-03-28 00:11:59 +00:00
return ( eval_t * ) & ( ( ( int * ) ( ( ( edictrun_t * ) ed ) - > fields ) ) [ var - > ofs ] ) ;
2004-08-23 01:38:21 +00:00
}
if ( ! cache - > varname )
{
cache - > varname = name ;
var = ED_FindField ( progfuncs , name ) ;
if ( ! var )
{
cache - > ofs32 = NULL ;
return NULL ;
}
cache - > ofs32 = var ;
2005-03-28 00:11:59 +00:00
return ( eval_t * ) & ( ( ( int * ) ( ( ( edictrun_t * ) ed ) - > fields ) ) [ var - > ofs ] ) ;
2004-08-23 01:38:21 +00:00
}
if ( cache - > ofs32 = = NULL )
return NULL ;
2005-03-28 00:11:59 +00:00
return ( eval_t * ) & ( ( ( int * ) ( ( ( edictrun_t * ) ed ) - > fields ) ) [ cache - > ofs32 - > ofs ] ) ;
2004-08-23 01:38:21 +00:00
}
struct edict_s * ProgsToEdict ( progfuncs_t * progfuncs , int progs )
{
2005-03-28 00:11:59 +00:00
return ( struct edict_s * ) PROG_TO_EDICT ( progfuncs , progs ) ;
2004-08-23 01:38:21 +00:00
}
int EdictToProgs ( progfuncs_t * progfuncs , struct edict_s * ed )
{
2005-03-28 00:11:59 +00:00
return EDICT_TO_PROG ( progfuncs , ed ) ;
2004-08-23 01:38:21 +00:00
}
struct qcthread_s * PR_ForkStack ( progfuncs_t * progfuncs ) ;
void PR_ResumeThread ( progfuncs_t * progfuncs , struct qcthread_s * thread ) ;
void PR_AbortStack ( progfuncs_t * progfuncs ) ;
void RegisterBuiltin ( progfuncs_t * progfncs , char * name , builtin_t func ) ;
progfuncs_t deffuncs = {
PROGSTRUCT_VERSION ,
PR_Configure ,
PR_LoadProgs ,
PR_InitEnts ,
PR_ExecuteProgram ,
PR_SwitchProgs ,
PR_globals ,
PR_entvars ,
PR_RunError ,
ED_Print ,
ED_Alloc ,
ED_Free ,
EDICT_NUM ,
NUM_FOR_EDICT ,
SetGlobalEdict ,
PR_VarString ,
NULL ,
PR_FindFunc ,
# ifdef MINIMAL
NULL ,
NULL ,
# else
Comp_Begin ,
Comp_Continue ,
# endif
filefromprogs ,
filefromnewprogs ,
SaveEnts ,
LoadEnts ,
SaveEnt ,
RestoreEnt ,
PR_FindGlobal ,
ED_NewString ,
( void * ) PRHunkAlloc ,
GetEdictFieldValue ,
ProgsToEdict ,
EdictToProgs ,
EvaluateDebugString ,
NULL ,
PR_StackTrace ,
PR_ToggleBreakpoint ,
0 ,
NULL ,
# ifdef MINIMAL
NULL ,
# else
Decompile ,
# endif
NULL ,
NULL ,
RegisterBuiltin ,
0 ,
0 ,
PR_ForkStack ,
PR_ResumeThread ,
2004-09-01 00:05:04 +00:00
PR_AbortStack ,
2005-02-12 18:56:04 +00:00
0 ,
2005-05-20 03:32:53 +00:00
QC_RegisterFieldVar ,
0 ,
0
2004-08-23 01:38:21 +00:00
} ;
# undef printf
//defs incase following structure is not passed.
struct edict_s * safesv_edicts ;
int safesv_num_edicts ;
double safetime = 0 ;
progexterns_t defexterns = {
PROGSTRUCT_VERSION ,
NULL , //char *(*ReadFile) (char *fname, void *buffer, int len);
NULL , //int (*FileSize) (char *fname); //-1 if file does not exist
NULL , //bool (*WriteFile) (char *name, void *data, int len);
printf , //void (*printf) (char *, ...);
( void * ) exit , //void (*Sys_Error) (char *, ...);
NULL , //void (*Abort) (char *, ...);
sizeof ( edictrun_t ) , //int edictsize; //size of edict_t
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
NULL , //bool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
NULL , //void (*stateop) (float var, func_t func);
NULL ,
NULL ,
NULL ,
//used when loading a game
NULL , //builtin_t *(*builtinsfor) (int num); //must return a pointer to the builtins that were used before the state was saved.
NULL , //void (*loadcompleate) (int edictsize); //notification to reset any pointers.
( void * ) malloc , //void *(*memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use memalloc if you want)
free , //void (*memfree) (void * mem);
NULL , //builtin_t *globalbuiltins; //these are available to all progs
0 , //int numglobalbuiltins;
2005-02-28 07:16:19 +00:00
PR_NOCOMPILE ,
2004-08-23 01:38:21 +00:00
& safetime , //double *gametime;
& safesv_edicts , //struct edict_s **sv_edicts;
& safesv_num_edicts , //int *sv_num_edicts;
NULL , //int (*useeditor) (char *filename, int line, int nump, char **parms);
} ;
//progfuncs_t *progfuncs = NULL;
# undef memfree
# undef prinst
# undef extensionbuiltin
# undef field
# undef shares
# undef sv_num_edicts
# ifdef QCLIBDLL_EXPORTS
__declspec ( dllexport )
# endif
void CloseProgs ( progfuncs_t * inst )
{
2005-05-15 18:49:04 +00:00
// extensionbuiltin_t *eb;
2004-08-23 01:38:21 +00:00
void ( VARGS * f ) ( void * ) ;
int i ;
edictrun_t * e ;
f = inst - > parms - > memfree ;
for ( i = 1 ; i < inst - > maxedicts ; i + + )
{
2004-09-20 23:25:38 +00:00
e = ( edictrun_t * ) ( inst - > prinst - > edicttable [ i ] ) ;
2004-08-23 01:38:21 +00:00
inst - > prinst - > edicttable [ i ] = NULL ;
if ( e )
{
// e->entnum = i;
f ( e ) ;
}
}
PRHunkFree ( inst , 0 ) ;
2005-05-15 18:49:04 +00:00
/*
2004-08-23 01:38:21 +00:00
while ( inst - > prinst - > extensionbuiltin )
{
eb = inst - > prinst - > extensionbuiltin - > prev ;
f ( inst - > prinst - > extensionbuiltin ) ;
inst - > prinst - > extensionbuiltin = eb ;
}
2005-05-15 18:49:04 +00:00
*/
2004-08-23 01:38:21 +00:00
if ( inst - > prinst - > field )
f ( inst - > prinst - > field ) ;
if ( inst - > prinst - > shares )
f ( inst - > prinst - > shares ) ; //free memory
f ( inst - > prinst ) ;
f ( inst ) ;
}
void RegisterBuiltin ( progfuncs_t * progfuncs , char * name , builtin_t func )
{
2005-05-15 18:49:04 +00:00
/*
2004-08-23 01:38:21 +00:00
extensionbuiltin_t * eb ;
eb = memalloc ( sizeof ( extensionbuiltin_t ) ) ;
eb - > prev = progfuncs - > prinst - > extensionbuiltin ;
progfuncs - > prinst - > extensionbuiltin = eb ;
eb - > name = name ;
eb - > func = func ;
2005-05-15 18:49:04 +00:00
*/
2004-08-23 01:38:21 +00:00
}
# ifndef WIN32
# define QCLIBINT //don't use dllspecifications
# endif
# if defined(QCLIBDLL_EXPORTS)
__declspec ( dllexport )
# endif
progfuncs_t * InitProgs ( progexterns_t * ext )
{
progfuncs_t * funcs ;
if ( ! ext )
ext = & defexterns ;
else
{
int i ;
if ( ext - > progsversion > PROGSTRUCT_VERSION )
return NULL ;
for ( i = 0 ; i < sizeof ( progexterns_t ) ; i + = 4 ) //make sure there are no items left out.
if ( ! * ( int * ) ( ( char * ) ext + i ) )
* ( int * ) ( ( char * ) ext + i ) = * ( int * ) ( ( char * ) & defexterns + i ) ;
}
# undef memalloc
# undef pr_trace
funcs = ext - > memalloc ( sizeof ( progfuncs_t ) ) ;
2005-03-28 00:11:59 +00:00
memcpy ( funcs , & deffuncs , sizeof ( progfuncs_t ) ) ;
2004-08-23 01:38:21 +00:00
funcs - > prinst = ext - > memalloc ( sizeof ( prinst_t ) ) ;
memset ( funcs - > prinst , 0 , sizeof ( prinst_t ) ) ;
funcs - > pr_trace = & funcs - > prinst - > pr_trace ;
funcs - > progstate = & funcs - > pr_progstate ;
funcs - > callargc = & funcs - > pr_argc ;
funcs - > parms = ext ;
return funcs ;
}
# ifdef QCC
void main ( int argc , char * * argv )
{
progexterns_t ext ;
progfuncs_t * funcs ;
funcs = InitProgs ( & ext ) ;
if ( funcs - > PR_StartCompile ( argc , argv ) )
while ( funcs - > PR_ContinueCompile ( ) ) ;
}
# endif