mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-29 15:12:19 +00:00
Initial Checkin
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@18 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
d7b2ae0270
commit
7c00f2b190
25 changed files with 26992 additions and 0 deletions
238
engine/qclib/Comprout.c
Normal file
238
engine/qclib/Comprout.c
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
//compile routines
|
||||||
|
|
||||||
|
#include "qcc.h"
|
||||||
|
#undef progfuncs
|
||||||
|
|
||||||
|
char errorfile[128];
|
||||||
|
int errorline;
|
||||||
|
|
||||||
|
progfuncs_t *qccprogfuncs;
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
extern int qcc_compileactive;
|
||||||
|
jmp_buf qcccompileerror;
|
||||||
|
char qcc_gamedir[128];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MINIMAL
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int qccalloced;
|
||||||
|
int qcchunksize;
|
||||||
|
char *qcchunk;
|
||||||
|
void *qccHunkAlloc(size_t mem)
|
||||||
|
{
|
||||||
|
qccalloced+=mem;
|
||||||
|
if (qccalloced > qcchunksize)
|
||||||
|
QCC_Error(ERR_INTERNAL, "Compile hunk was filled");
|
||||||
|
|
||||||
|
memset(qcchunk+qccalloced-mem, 0, mem);
|
||||||
|
return qcchunk+qccalloced-mem;
|
||||||
|
}
|
||||||
|
void qccClearHunk(void)
|
||||||
|
{
|
||||||
|
if (qcchunk)
|
||||||
|
{
|
||||||
|
free(qcchunk);
|
||||||
|
qcchunk=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PostCompile(void)
|
||||||
|
{
|
||||||
|
#ifndef QCCONLY //QCCONLY has a frontend that browses defs.
|
||||||
|
qccClearHunk();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (asmfile)
|
||||||
|
{
|
||||||
|
fclose(asmfile);
|
||||||
|
asmfile = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PreCompile(void)
|
||||||
|
{
|
||||||
|
qccClearHunk();
|
||||||
|
strcpy(qcc_gamedir, "");
|
||||||
|
qcchunk = malloc(qcchunksize=16*1024*1024);
|
||||||
|
qccalloced=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCC_main (int argc, char **argv);
|
||||||
|
void QCC_ContinueCompile(void);
|
||||||
|
void QCC_FinishCompile(void);
|
||||||
|
|
||||||
|
int comp_nump;char **comp_parms;
|
||||||
|
//void Editor(char *fname, int line, int numparms, char **compileparms);
|
||||||
|
pbool CompileParams(progfuncs_t *progfuncs, int doall, int nump, char **parms)
|
||||||
|
{
|
||||||
|
comp_nump = nump;
|
||||||
|
comp_parms = parms;
|
||||||
|
*errorfile = '\0';
|
||||||
|
qccprogfuncs = progfuncs;
|
||||||
|
if (setjmp(qcccompileerror))
|
||||||
|
{
|
||||||
|
PostCompile();
|
||||||
|
if (*errorfile)
|
||||||
|
{
|
||||||
|
if (!externs->useeditor)
|
||||||
|
printf("Error in %s on line %i\n", errorfile, errorline);
|
||||||
|
else
|
||||||
|
externs->useeditor(errorfile, errorline, nump, parms);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreCompile();
|
||||||
|
QCC_main(nump, parms);
|
||||||
|
|
||||||
|
while(qcc_compileactive)
|
||||||
|
QCC_ContinueCompile();
|
||||||
|
|
||||||
|
PostCompile();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int Comp_Begin(progfuncs_t *progfuncs, int nump, char **parms)
|
||||||
|
{
|
||||||
|
comp_nump = nump;
|
||||||
|
comp_parms = parms;
|
||||||
|
qccprogfuncs = progfuncs;
|
||||||
|
*errorfile = '\0';
|
||||||
|
if (setjmp(qcccompileerror))
|
||||||
|
{
|
||||||
|
PostCompile();
|
||||||
|
if (*errorfile)
|
||||||
|
externs->useeditor(errorfile, errorline, nump, parms);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PreCompile();
|
||||||
|
QCC_main(nump, parms);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int Comp_Continue(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
qccprogfuncs = progfuncs;
|
||||||
|
if (setjmp(qcccompileerror))
|
||||||
|
{
|
||||||
|
PostCompile();
|
||||||
|
if (*errorfile)
|
||||||
|
externs->useeditor(errorfile, errorline, comp_nump, comp_parms);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qcc_compileactive)
|
||||||
|
QCC_ContinueCompile();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PostCompile();
|
||||||
|
|
||||||
|
if (*errorfile)
|
||||||
|
externs->useeditor(errorfile, errorline, comp_nump, comp_parms);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pbool CompileFile(progfuncs_t *progfuncs, char *filename)
|
||||||
|
{
|
||||||
|
#ifdef MINIMAL
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
char srcfile[32];
|
||||||
|
char newname[32];
|
||||||
|
static char *p[5];
|
||||||
|
int parms;
|
||||||
|
char *s, *s2;
|
||||||
|
|
||||||
|
p[0] = NULL;
|
||||||
|
parms = 1;
|
||||||
|
|
||||||
|
strcpy(newname, filename);
|
||||||
|
s = newname;
|
||||||
|
if (strchr(s+1, '/'))
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
s2 = strchr(s+1, '/');
|
||||||
|
if (!s2)
|
||||||
|
{
|
||||||
|
*s = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s = s2;
|
||||||
|
}
|
||||||
|
p[parms] = "-src";
|
||||||
|
p[parms+1] = newname;
|
||||||
|
parms+=2;
|
||||||
|
|
||||||
|
strcpy(srcfile, s+1);
|
||||||
|
srcfile[strlen(srcfile)-4] = '\0';
|
||||||
|
strcat(srcfile, ".src");
|
||||||
|
|
||||||
|
if (externs->FileSize(qcva("%s/%s", newname, srcfile))>0)
|
||||||
|
{
|
||||||
|
p[parms] = "-srcfile";
|
||||||
|
p[parms+1] = srcfile;
|
||||||
|
parms+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p[parms] = "-srcfile";
|
||||||
|
p[parms+1] = newname;
|
||||||
|
newname[strlen(newname)-4] = '\0';
|
||||||
|
strcat(newname, ".src");
|
||||||
|
parms+=2;
|
||||||
|
}
|
||||||
|
// p[2][strlen(p[2])-4] = '\0';
|
||||||
|
// strcat(p[2], "/");
|
||||||
|
|
||||||
|
while (!CompileParams(progfuncs, true, parms, p))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int QC_strncasecmp(const char *s1, const char *s2, int n)
|
||||||
|
{
|
||||||
|
int c1, c2;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
c1 = *s1++;
|
||||||
|
c2 = *s2++;
|
||||||
|
|
||||||
|
if (!n--)
|
||||||
|
return 0; // strings are equal until end point
|
||||||
|
|
||||||
|
if (c1 != c2)
|
||||||
|
{
|
||||||
|
if (c1 >= 'a' && c1 <= 'z')
|
||||||
|
c1 -= ('a' - 'A');
|
||||||
|
if (c2 >= 'a' && c2 <= 'z')
|
||||||
|
c2 -= ('a' - 'A');
|
||||||
|
if (c1 != c2)
|
||||||
|
return -1; // strings not equal
|
||||||
|
}
|
||||||
|
if (!c1)
|
||||||
|
return 0; // strings are equal
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void editbadfile(char *fname, int line)
|
||||||
|
{
|
||||||
|
strcpy(errorfile, fname);
|
||||||
|
errorline = line;
|
||||||
|
}
|
||||||
|
|
490
engine/qclib/PR_COMP.H
Normal file
490
engine/qclib/PR_COMP.H
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
// this file is shared by the execution and compiler
|
||||||
|
|
||||||
|
/*i'm part way through making this work
|
||||||
|
I've given up now that I can't work out a way to load pointers.
|
||||||
|
Setting them should be fine.
|
||||||
|
*/
|
||||||
|
#ifndef __PR_COMP_H__
|
||||||
|
#define __PR_COMP_H__
|
||||||
|
|
||||||
|
|
||||||
|
/*this distinction is made as the execution uses c pointers while compiler uses pointers from the start of the string table of the current progs*/
|
||||||
|
#ifdef COMPILER
|
||||||
|
typedef int QCC_string_t;
|
||||||
|
#else
|
||||||
|
//typedef char *string_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_struct, ev_union} etype_t;
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 10
|
||||||
|
|
||||||
|
#define OFS_NULL 0
|
||||||
|
#define OFS_RETURN 1
|
||||||
|
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
|
||||||
|
#define OFS_PARM1 7
|
||||||
|
#define OFS_PARM2 10
|
||||||
|
#define OFS_PARM3 13
|
||||||
|
#define OFS_PARM4 16
|
||||||
|
#define OFS_PARM5 19
|
||||||
|
#define OFS_PARM6 22
|
||||||
|
#define OFS_PARM7 25
|
||||||
|
#define RESERVED_OFS 28
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OP_DONE, //0
|
||||||
|
OP_MUL_F,
|
||||||
|
OP_MUL_V,
|
||||||
|
OP_MUL_FV,
|
||||||
|
OP_MUL_VF,
|
||||||
|
OP_DIV_F,
|
||||||
|
OP_ADD_F,
|
||||||
|
OP_ADD_V,
|
||||||
|
OP_SUB_F,
|
||||||
|
OP_SUB_V,
|
||||||
|
|
||||||
|
OP_EQ_F, //10
|
||||||
|
OP_EQ_V,
|
||||||
|
OP_EQ_S,
|
||||||
|
OP_EQ_E,
|
||||||
|
OP_EQ_FNC,
|
||||||
|
|
||||||
|
OP_NE_F,
|
||||||
|
OP_NE_V,
|
||||||
|
OP_NE_S,
|
||||||
|
OP_NE_E,
|
||||||
|
OP_NE_FNC,
|
||||||
|
|
||||||
|
OP_LE, //20
|
||||||
|
OP_GE,
|
||||||
|
OP_LT,
|
||||||
|
OP_GT,
|
||||||
|
|
||||||
|
OP_LOAD_F,
|
||||||
|
OP_LOAD_V,
|
||||||
|
OP_LOAD_S,
|
||||||
|
OP_LOAD_ENT,
|
||||||
|
OP_LOAD_FLD,
|
||||||
|
OP_LOAD_FNC,
|
||||||
|
|
||||||
|
OP_ADDRESS, //30
|
||||||
|
|
||||||
|
OP_STORE_F,
|
||||||
|
OP_STORE_V,
|
||||||
|
OP_STORE_S,
|
||||||
|
OP_STORE_ENT,
|
||||||
|
OP_STORE_FLD,
|
||||||
|
OP_STORE_FNC,
|
||||||
|
|
||||||
|
OP_STOREP_F,
|
||||||
|
OP_STOREP_V,
|
||||||
|
OP_STOREP_S,
|
||||||
|
OP_STOREP_ENT, //40
|
||||||
|
OP_STOREP_FLD,
|
||||||
|
OP_STOREP_FNC,
|
||||||
|
|
||||||
|
OP_RETURN,
|
||||||
|
OP_NOT_F,
|
||||||
|
OP_NOT_V,
|
||||||
|
OP_NOT_S,
|
||||||
|
OP_NOT_ENT,
|
||||||
|
OP_NOT_FNC,
|
||||||
|
OP_IF,
|
||||||
|
OP_IFNOT, //50
|
||||||
|
OP_CALL0, //careful... hexen2 and q1 have different calling conventions
|
||||||
|
OP_CALL1, //remap hexen2 calls to OP_CALL2H
|
||||||
|
OP_CALL2,
|
||||||
|
OP_CALL3,
|
||||||
|
OP_CALL4,
|
||||||
|
OP_CALL5,
|
||||||
|
OP_CALL6,
|
||||||
|
OP_CALL7,
|
||||||
|
OP_CALL8,
|
||||||
|
OP_STATE, //60
|
||||||
|
OP_GOTO,
|
||||||
|
OP_AND,
|
||||||
|
OP_OR,
|
||||||
|
|
||||||
|
OP_BITAND,
|
||||||
|
OP_BITOR,
|
||||||
|
|
||||||
|
|
||||||
|
//these following ones are Hexen 2 constants.
|
||||||
|
|
||||||
|
OP_MULSTORE_F,
|
||||||
|
OP_MULSTORE_V,
|
||||||
|
OP_MULSTOREP_F,
|
||||||
|
OP_MULSTOREP_V,
|
||||||
|
|
||||||
|
OP_DIVSTORE_F, //70
|
||||||
|
OP_DIVSTOREP_F,
|
||||||
|
|
||||||
|
OP_ADDSTORE_F,
|
||||||
|
OP_ADDSTORE_V,
|
||||||
|
OP_ADDSTOREP_F,
|
||||||
|
OP_ADDSTOREP_V,
|
||||||
|
|
||||||
|
OP_SUBSTORE_F,
|
||||||
|
OP_SUBSTORE_V,
|
||||||
|
OP_SUBSTOREP_F,
|
||||||
|
OP_SUBSTOREP_V,
|
||||||
|
|
||||||
|
OP_FETCH_GBL_F, //80
|
||||||
|
OP_FETCH_GBL_V,
|
||||||
|
OP_FETCH_GBL_S,
|
||||||
|
OP_FETCH_GBL_E,
|
||||||
|
OP_FETCH_GBL_FNC,
|
||||||
|
|
||||||
|
OP_CSTATE,
|
||||||
|
OP_CWSTATE,
|
||||||
|
|
||||||
|
OP_THINKTIME,
|
||||||
|
|
||||||
|
OP_BITSET,
|
||||||
|
OP_BITSETP,
|
||||||
|
OP_BITCLR, //90
|
||||||
|
OP_BITCLRP,
|
||||||
|
|
||||||
|
OP_RAND0,
|
||||||
|
OP_RAND1,
|
||||||
|
OP_RAND2,
|
||||||
|
OP_RANDV0,
|
||||||
|
OP_RANDV1,
|
||||||
|
OP_RANDV2,
|
||||||
|
|
||||||
|
OP_SWITCH_F,
|
||||||
|
OP_SWITCH_V,
|
||||||
|
OP_SWITCH_S, //100
|
||||||
|
OP_SWITCH_E,
|
||||||
|
OP_SWITCH_FNC,
|
||||||
|
|
||||||
|
OP_CASE,
|
||||||
|
OP_CASERANGE,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//the rest are added
|
||||||
|
//mostly they are various different ways of adding two vars with conversions.
|
||||||
|
|
||||||
|
OP_CALL1H,
|
||||||
|
OP_CALL2H,
|
||||||
|
OP_CALL3H,
|
||||||
|
OP_CALL4H,
|
||||||
|
OP_CALL5H,
|
||||||
|
OP_CALL6H, //110
|
||||||
|
OP_CALL7H,
|
||||||
|
OP_CALL8H,
|
||||||
|
|
||||||
|
|
||||||
|
OP_STORE_I,
|
||||||
|
OP_STORE_IF,
|
||||||
|
OP_STORE_FI,
|
||||||
|
|
||||||
|
OP_ADD_I,
|
||||||
|
OP_ADD_FI,
|
||||||
|
OP_ADD_IF, //110
|
||||||
|
|
||||||
|
OP_SUB_I,
|
||||||
|
OP_SUB_FI,
|
||||||
|
OP_SUB_IF,
|
||||||
|
|
||||||
|
OP_CONV_ITOF,
|
||||||
|
OP_CONV_FTOI,
|
||||||
|
OP_CP_ITOF,
|
||||||
|
OP_CP_FTOI,
|
||||||
|
OP_LOAD_I,
|
||||||
|
OP_STOREP_I,
|
||||||
|
OP_STOREP_IF, //120
|
||||||
|
OP_STOREP_FI,
|
||||||
|
|
||||||
|
OP_BITAND_I,
|
||||||
|
OP_BITOR_I,
|
||||||
|
|
||||||
|
OP_MUL_I,
|
||||||
|
OP_DIV_I,
|
||||||
|
OP_EQ_I,
|
||||||
|
OP_NE_I,
|
||||||
|
|
||||||
|
OP_IFNOTS,
|
||||||
|
OP_IFS,
|
||||||
|
|
||||||
|
OP_NOT_I, //130
|
||||||
|
|
||||||
|
OP_DIV_VF,
|
||||||
|
|
||||||
|
OP_POWER_I,
|
||||||
|
OP_RSHIFT_I,
|
||||||
|
OP_LSHIFT_I,
|
||||||
|
|
||||||
|
OP_GLOBALADDRESS,
|
||||||
|
OP_POINTER_ADD, //32 bit pointers
|
||||||
|
|
||||||
|
OP_LOADA_F,
|
||||||
|
OP_LOADA_V,
|
||||||
|
OP_LOADA_S,
|
||||||
|
OP_LOADA_ENT, //140
|
||||||
|
OP_LOADA_FLD,
|
||||||
|
OP_LOADA_FNC,
|
||||||
|
OP_LOADA_I,
|
||||||
|
|
||||||
|
OP_STORE_P,
|
||||||
|
OP_LOAD_P,
|
||||||
|
|
||||||
|
OP_LOADP_F,
|
||||||
|
OP_LOADP_V,
|
||||||
|
OP_LOADP_S,
|
||||||
|
OP_LOADP_ENT,
|
||||||
|
OP_LOADP_FLD, //150
|
||||||
|
OP_LOADP_FNC,
|
||||||
|
OP_LOADP_I,
|
||||||
|
|
||||||
|
OP_LE_I,
|
||||||
|
OP_GE_I,
|
||||||
|
OP_LT_I,
|
||||||
|
OP_GT_I,
|
||||||
|
|
||||||
|
OP_LE_IF,
|
||||||
|
OP_GE_IF,
|
||||||
|
OP_LT_IF,
|
||||||
|
OP_GT_IF, //160
|
||||||
|
|
||||||
|
OP_LE_FI,
|
||||||
|
OP_GE_FI,
|
||||||
|
OP_LT_FI,
|
||||||
|
OP_GT_FI,
|
||||||
|
|
||||||
|
OP_EQ_IF,
|
||||||
|
OP_EQ_FI,
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
//string manipulation.
|
||||||
|
OP_ADD_SF, //(char*)c = (char*)a + (float)b
|
||||||
|
OP_SUB_S, //(float)c = (char*)a - (char*)b
|
||||||
|
OP_STOREP_C,//(float)c = *(char*)b = (float)a
|
||||||
|
OP_LOADP_C, //(float)c = *(char*) //170
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
OP_MUL_IF,
|
||||||
|
OP_MUL_FI,
|
||||||
|
OP_MUL_VI,
|
||||||
|
OP_MUL_IV,
|
||||||
|
OP_DIV_IF,
|
||||||
|
OP_DIV_FI,
|
||||||
|
OP_BITAND_IF,
|
||||||
|
OP_BITOR_IF,
|
||||||
|
OP_BITAND_FI,
|
||||||
|
OP_BITOR_FI, //180
|
||||||
|
OP_AND_I,
|
||||||
|
OP_OR_I,
|
||||||
|
OP_AND_IF,
|
||||||
|
OP_OR_IF,
|
||||||
|
OP_AND_FI,
|
||||||
|
OP_OR_FI,
|
||||||
|
OP_NE_IF,
|
||||||
|
OP_NE_FI,
|
||||||
|
OP_GSTOREP_I,
|
||||||
|
OP_GSTOREP_F, //190
|
||||||
|
OP_GSTOREP_ENT,
|
||||||
|
OP_GSTOREP_FLD, // integers
|
||||||
|
OP_GSTOREP_S,
|
||||||
|
OP_GSTOREP_FNC, // pointers
|
||||||
|
OP_GSTOREP_V,
|
||||||
|
OP_GADDRESS,
|
||||||
|
OP_GLOAD_I,
|
||||||
|
OP_GLOAD_F,
|
||||||
|
OP_GLOAD_FLD,
|
||||||
|
OP_GLOAD_ENT, //200
|
||||||
|
OP_GLOAD_S,
|
||||||
|
OP_GLOAD_FNC,
|
||||||
|
OP_BOUNDCHECK,
|
||||||
|
|
||||||
|
OP_NUMOPS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef struct statement16_s
|
||||||
|
{
|
||||||
|
unsigned short op;
|
||||||
|
unsigned short a,b,c;
|
||||||
|
} dstatement16_t;
|
||||||
|
typedef struct statement32_s
|
||||||
|
{
|
||||||
|
unsigned int op;
|
||||||
|
unsigned int a,b,c;
|
||||||
|
} dstatement32_t;
|
||||||
|
#else
|
||||||
|
typedef struct QCC_statement16_s
|
||||||
|
{
|
||||||
|
unsigned short op;
|
||||||
|
unsigned short a,b,c;
|
||||||
|
} QCC_dstatement16_t;
|
||||||
|
typedef struct QCC_statement32_s
|
||||||
|
{
|
||||||
|
unsigned int op;
|
||||||
|
unsigned int a,b,c;
|
||||||
|
} QCC_dstatement32_t;
|
||||||
|
#define QCC_dstatement_t QCC_dstatement32_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//these should be the same except the string type
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef struct ddef16_s
|
||||||
|
{
|
||||||
|
unsigned short type; // if DEF_SAVEGLOBAL bit is set
|
||||||
|
// the variable needs to be saved in savegames
|
||||||
|
unsigned short ofs;
|
||||||
|
string_t s_name;
|
||||||
|
} ddef16_t;
|
||||||
|
|
||||||
|
typedef struct ddef32_s
|
||||||
|
{
|
||||||
|
unsigned int type; // if DEF_SAVEGLOBAL bit is set
|
||||||
|
// the variable needs to be saved in savegames
|
||||||
|
unsigned int ofs;
|
||||||
|
string_t s_name;
|
||||||
|
} ddef32_t;
|
||||||
|
|
||||||
|
typedef struct fdef_s
|
||||||
|
{
|
||||||
|
unsigned int type; // if DEF_SAVEGLOBAL bit is set
|
||||||
|
// the variable needs to be saved in savegames
|
||||||
|
unsigned int ofs;
|
||||||
|
unsigned int requestedofs;
|
||||||
|
string_t s_name;
|
||||||
|
} fdef_t;
|
||||||
|
|
||||||
|
typedef void *ddefXX_t;
|
||||||
|
#else
|
||||||
|
typedef struct QCC_ddef16_s
|
||||||
|
{
|
||||||
|
unsigned short type; // if DEF_SAVEGLOBAL bit is set
|
||||||
|
// the variable needs to be saved in savegames
|
||||||
|
unsigned short ofs;
|
||||||
|
QCC_string_t s_name;
|
||||||
|
} QCC_ddef16_t;
|
||||||
|
|
||||||
|
typedef struct QCC_ddef32_s
|
||||||
|
{
|
||||||
|
unsigned int type; // if DEF_SAVEGLOBAL bit is set
|
||||||
|
// the variable needs to be saved in savegames
|
||||||
|
unsigned int ofs;
|
||||||
|
QCC_string_t s_name;
|
||||||
|
} QCC_ddef32_t;
|
||||||
|
|
||||||
|
#define QCC_ddef_t QCC_ddef32_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEF_SAVEGLOBAL (1<<15)
|
||||||
|
#define DEF_SHARED (1<<14)
|
||||||
|
|
||||||
|
#define MAX_PARMS 8
|
||||||
|
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int first_statement; // negative numbers are builtins
|
||||||
|
int parm_start;
|
||||||
|
int locals; // total ints of parms + locals
|
||||||
|
|
||||||
|
int profile; // runtime
|
||||||
|
|
||||||
|
string_t s_name;
|
||||||
|
string_t s_file; // source file defined in
|
||||||
|
|
||||||
|
int numparms;
|
||||||
|
qbyte parm_size[MAX_PARMS];
|
||||||
|
} dfunction_t;
|
||||||
|
#else
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int first_statement; // negative numbers are builtins
|
||||||
|
unsigned int parm_start;
|
||||||
|
int locals; // total ints of parms + locals
|
||||||
|
|
||||||
|
int profile; // runtime
|
||||||
|
|
||||||
|
QCC_string_t s_name;
|
||||||
|
QCC_string_t s_file; // source file defined in
|
||||||
|
|
||||||
|
int numparms;
|
||||||
|
qbyte parm_size[MAX_PARMS];
|
||||||
|
} QCC_dfunction_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define PROG_VERSION 6
|
||||||
|
#define PROG_DEBUGVERSION 7
|
||||||
|
#define PROG_SECONDARYVERSION16 (*(int*)"1FTE" ^ *(int*)"PROG") //something unlikly and still meaningful (to me)
|
||||||
|
#define PROG_SECONDARYVERSION32 (*(int*)"1FTE" ^ *(int*)"32B ") //something unlikly and still meaningful (to me)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
int crc; // check of header file
|
||||||
|
|
||||||
|
unsigned int ofs_statements; //comp 1
|
||||||
|
unsigned int numstatements; // statement 0 is an error
|
||||||
|
|
||||||
|
unsigned int ofs_globaldefs; //comp 2
|
||||||
|
unsigned int numglobaldefs;
|
||||||
|
|
||||||
|
unsigned int ofs_fielddefs; //comp 4
|
||||||
|
unsigned int numfielddefs;
|
||||||
|
|
||||||
|
unsigned int ofs_functions; //comp 8
|
||||||
|
unsigned int numfunctions; // function 0 is an empty
|
||||||
|
|
||||||
|
unsigned int ofs_strings; //comp 16
|
||||||
|
unsigned int numstrings; // first string is a null string
|
||||||
|
|
||||||
|
unsigned int ofs_globals; //comp 32
|
||||||
|
unsigned int numglobals;
|
||||||
|
|
||||||
|
unsigned int entityfields;
|
||||||
|
|
||||||
|
//debug / version 7 extensions
|
||||||
|
unsigned int ofsfiles; //non list format. no comp
|
||||||
|
unsigned int ofslinenums; //numstatements big //comp 64
|
||||||
|
unsigned int ofsbodylessfuncs; //no comp
|
||||||
|
unsigned int numbodylessfuncs;
|
||||||
|
|
||||||
|
unsigned int ofs_types; //comp 128
|
||||||
|
unsigned int numtypes;
|
||||||
|
unsigned int blockscompressed;
|
||||||
|
|
||||||
|
int secondaryversion; //Constant - to say that any version 7 progs are actually ours, not someone else's alterations.
|
||||||
|
} dprograms_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char filename[128];
|
||||||
|
int size;
|
||||||
|
int compsize;
|
||||||
|
int compmethod;
|
||||||
|
int ofs;
|
||||||
|
} includeddatafile_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct typeinfo_s
|
||||||
|
{
|
||||||
|
etype_t type;
|
||||||
|
|
||||||
|
int next;
|
||||||
|
int aux_type;
|
||||||
|
int num_parms;
|
||||||
|
|
||||||
|
int ofs; //inside a structure.
|
||||||
|
int size;
|
||||||
|
char *name;
|
||||||
|
} typeinfo_t;
|
1090
engine/qclib/Pr_exec.c
Normal file
1090
engine/qclib/Pr_exec.c
Normal file
File diff suppressed because it is too large
Load diff
446
engine/qclib/Progsint.h
Normal file
446
engine/qclib/Progsint.h
Normal file
|
@ -0,0 +1,446 @@
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
#ifndef AVAIL_ZLIB
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
//#define AVAIL_ZLIB
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
enum{false, true};
|
||||||
|
#else
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifndef __declspec
|
||||||
|
#define __declspec(mode)
|
||||||
|
#endif
|
||||||
|
typedef enum{false, true} boolean;
|
||||||
|
//#define _inline inline
|
||||||
|
#endif
|
||||||
|
typedef unsigned char qbyte;
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DLL_PROG
|
||||||
|
#ifndef PROGSUSED
|
||||||
|
#define PROGSUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DYNAMIC_ENTS
|
||||||
|
|
||||||
|
extern int maxedicts;
|
||||||
|
extern int maxprogs;
|
||||||
|
extern int hunksize;
|
||||||
|
|
||||||
|
#include "progtype.h"
|
||||||
|
#include "progslib.h"
|
||||||
|
|
||||||
|
//extern progfuncs_t *progfuncs;
|
||||||
|
|
||||||
|
#define prinst progfuncs->prinst
|
||||||
|
#define externs progfuncs->parms
|
||||||
|
|
||||||
|
#include "pr_comp.h"
|
||||||
|
|
||||||
|
#include "qcd.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int targetflags; //weather we need to mark the progs as a newer version
|
||||||
|
char *name;
|
||||||
|
char *opname;
|
||||||
|
int priority;
|
||||||
|
enum {ASSOC_LEFT, ASSOC_RIGHT, ASSOC_RIGHT_RESULT} associative;
|
||||||
|
struct QCC_type_s **type_a, **type_b, **type_c;
|
||||||
|
} QCC_opcode_t;
|
||||||
|
extern QCC_opcode_t pr_opcodes[]; // sized by initialization
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define Q_vsnprintf _vsnprintf
|
||||||
|
#else
|
||||||
|
#define Q_vsnprintf vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define sv_num_edicts (*externs->sv_num_edicts)
|
||||||
|
#define sv_edicts (*externs->sv_edicts)
|
||||||
|
|
||||||
|
#define printf externs->printf
|
||||||
|
#define Sys_Error externs->Sys_Error
|
||||||
|
#define Abort externs->Abort
|
||||||
|
|
||||||
|
#define memalloc externs->memalloc
|
||||||
|
#define memfree externs->memfree
|
||||||
|
|
||||||
|
int PRHunkMark(progfuncs_t *progfuncs);
|
||||||
|
void PRHunkFree(progfuncs_t *progfuncs, int mark);
|
||||||
|
void *PRHunkAlloc(progfuncs_t *progfuncs, int size);
|
||||||
|
|
||||||
|
//void *HunkAlloc (int size);
|
||||||
|
char *VARGS qcva (char *text, ...);
|
||||||
|
void QC_InitShares(progfuncs_t *progfuncs);
|
||||||
|
void QC_StartShares(progfuncs_t *progfuncs);
|
||||||
|
void QC_AddSharedVar(progfuncs_t *progfuncs, int num, int type);
|
||||||
|
void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num);
|
||||||
|
int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, int requestedpos, int origionalofs);
|
||||||
|
pbool Decompile(progfuncs_t *progfuncs, char *fname);
|
||||||
|
int PR_ToggleBreakpoint(progfuncs_t *progfuncs, char *filename, int linenum, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
#define edvars(ed) (((char *)ed)+externs->edictsize) //pointer to the field vars, given an edict
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern short (*BigShort) (short l);
|
||||||
|
extern short (*LittleShort) (short l);
|
||||||
|
extern long (*BigLong) (long l);
|
||||||
|
extern long (*LittleLong) (long l);
|
||||||
|
extern float (*BigFloat) (float l);
|
||||||
|
extern float (*LittleFloat) (float l);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef union eval_s
|
||||||
|
{
|
||||||
|
string_t string;
|
||||||
|
float _float;
|
||||||
|
float vector[3];
|
||||||
|
func_t function;
|
||||||
|
int _int;
|
||||||
|
int edict;
|
||||||
|
progsnum_t prog; //so it can easily be changed
|
||||||
|
} eval_t;
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_ENT_LEAFS 16
|
||||||
|
typedef struct edictrun_s
|
||||||
|
{
|
||||||
|
pbool isfree;
|
||||||
|
|
||||||
|
float freetime; // realtime when the object was freed
|
||||||
|
int entnum;
|
||||||
|
pbool readonly; //causes error when QC tries writing to it. (quake's world entity)
|
||||||
|
|
||||||
|
// other fields from progs come immediately after
|
||||||
|
} edictrun_t;
|
||||||
|
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edictrun_t,area)
|
||||||
|
|
||||||
|
|
||||||
|
int Comp_Begin(progfuncs_t *progfuncs, int nump, char **parms);
|
||||||
|
int Comp_Continue(progfuncs_t *progfuncs);
|
||||||
|
|
||||||
|
char *EvaluateDebugString(progfuncs_t *progfuncs, char *key);
|
||||||
|
char *SaveEnts(progfuncs_t *progfuncs, char *mem, int *size, int mode);
|
||||||
|
int LoadEnts(progfuncs_t *progfuncs, char *file, float killonspawnflags);
|
||||||
|
char *SaveEnt (progfuncs_t *progfuncs, char *buf, int *size, struct edict_s *ed);
|
||||||
|
struct edict_s *RestoreEnt (progfuncs_t *progfuncs, char *buf, int *size, struct edict_s *ed);
|
||||||
|
char *PF_VarString (int first);
|
||||||
|
void PR_StackTrace (progfuncs_t *progfuncs);
|
||||||
|
|
||||||
|
extern int outputversion;
|
||||||
|
extern int noextensions;
|
||||||
|
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef struct progstate_s
|
||||||
|
{
|
||||||
|
dprograms_t *progs;
|
||||||
|
dfunction_t *functions;
|
||||||
|
char *strings;
|
||||||
|
union {
|
||||||
|
ddefXX_t *globaldefs;
|
||||||
|
ddef16_t *globaldefs16;
|
||||||
|
ddef32_t *globaldefs32;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
ddefXX_t *fielddefs;
|
||||||
|
ddef16_t *fielddefs16;
|
||||||
|
ddef32_t *fielddefs32;
|
||||||
|
};
|
||||||
|
void *statements;
|
||||||
|
// void *global_struct;
|
||||||
|
float *globals; // same as pr_global_struct
|
||||||
|
|
||||||
|
typeinfo_t *types;
|
||||||
|
|
||||||
|
int edict_size; // in bytes
|
||||||
|
|
||||||
|
char filename[128];
|
||||||
|
|
||||||
|
builtin_t *builtins;
|
||||||
|
int numbuiltins;
|
||||||
|
|
||||||
|
int *linenums; //debug versions only
|
||||||
|
|
||||||
|
int intsize; //16 for standard (more limiting) versions
|
||||||
|
} progstate_t;
|
||||||
|
|
||||||
|
typedef struct extensionbuiltin_s {
|
||||||
|
char *name;
|
||||||
|
builtin_t func;
|
||||||
|
struct extensionbuiltin_s *prev;
|
||||||
|
} extensionbuiltin_t;
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
#define pr_progs current_progstate->progs
|
||||||
|
#define pr_functions current_progstate->functions
|
||||||
|
#define pr_strings current_progstate->strings
|
||||||
|
#define pr_globaldefs16 ((ddef16_t*)current_progstate->globaldefs)
|
||||||
|
#define pr_globaldefs32 ((ddef32_t*)current_progstate->globaldefs)
|
||||||
|
#define pr_fielddefs16 ((ddef16_t*)current_progstate->fielddefs)
|
||||||
|
#define pr_fielddefs32 ((ddef32_t*)current_progstate->fielddefs)
|
||||||
|
#define pr_statements16 ((dstatement16_t*)current_progstate->statements)
|
||||||
|
#define pr_statements32 ((dstatement32_t*)current_progstate->statements)
|
||||||
|
//#define pr_global_struct current_progstate->global_struct
|
||||||
|
#define pr_globals current_progstate->globals
|
||||||
|
#define pr_linenums current_progstate->linenums
|
||||||
|
#define pr_types current_progstate->types
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void PR_Init (void);
|
||||||
|
|
||||||
|
void PR_ExecuteProgram (progfuncs_t *progfuncs, func_t fnum);
|
||||||
|
int PR_LoadProgs(progfuncs_t *progfncs, char *s, int headercrc, builtin_t *builtins, int numbuiltins);
|
||||||
|
int PR_ReallyLoadProgs (progfuncs_t *progfuncs, char *filename, int headercrc, progstate_t *progstate, pbool complain);
|
||||||
|
|
||||||
|
void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount);
|
||||||
|
|
||||||
|
void PR_Profile_f (void);
|
||||||
|
|
||||||
|
struct edict_s *ED_Alloc (progfuncs_t *progfuncs);
|
||||||
|
void ED_Free (progfuncs_t *progfuncs, struct edict_s *ed);
|
||||||
|
|
||||||
|
char *ED_NewString (progfuncs_t *progfuncs, char *string);
|
||||||
|
// returns a copy of the string allocated from the server's string heap
|
||||||
|
|
||||||
|
void ED_Print (progfuncs_t *progfuncs, struct edict_s *ed);
|
||||||
|
//void ED_Write (FILE *f, edictrun_t *ed);
|
||||||
|
char *ED_ParseEdict (progfuncs_t *progfuncs, char *data, edictrun_t *ent);
|
||||||
|
|
||||||
|
//void ED_WriteGlobals (FILE *f);
|
||||||
|
void ED_ParseGlobals (char *data);
|
||||||
|
|
||||||
|
//void ED_LoadFromFile (char *data);
|
||||||
|
|
||||||
|
//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))
|
||||||
|
//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)
|
||||||
|
|
||||||
|
struct edict_s *EDICT_NUM(progfuncs_t *progfuncs, int n);
|
||||||
|
int NUM_FOR_EDICT(progfuncs_t *progfuncs, struct edict_s *e);
|
||||||
|
|
||||||
|
//#define NEXT_EDICT(e) ((edictrun_t *)( (byte *)e + pr_edict_size))
|
||||||
|
|
||||||
|
#define EDICT_TO_PROG(e) ((qbyte *)e - (qbyte *)sv_edicts)
|
||||||
|
#define PROG_TO_EDICT(e) ((edictrun_t *)((qbyte *)sv_edicts + e))
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#define G_FLOAT(o) (pr_globals[o])
|
||||||
|
#define G_FLOAT2(o) (pr_globals[OFS_PARM0 + o*3])
|
||||||
|
#define G_INT(o) (*(int *)&pr_globals[o])
|
||||||
|
#define G_EDICT(o) ((edict_t *)((qbyte *)sv_edicts+ *(int *)&pr_globals[o]))
|
||||||
|
#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))
|
||||||
|
#define G_VECTOR(o) (&pr_globals[o])
|
||||||
|
#define G_STRING(o) (*(string_t *)&pr_globals[o])
|
||||||
|
#define G_STRING2(o) ((char*)*(string_t *)&pr_globals[o])
|
||||||
|
#define GQ_STRING(o) (*(QCC_string_t *)&pr_globals[o])
|
||||||
|
#define GQ_STRING2(o) ((char*)*(QCC_string_t *)&pr_globals[o])
|
||||||
|
#define G_FUNCTION(o) (*(func_t *)&pr_globals[o])
|
||||||
|
#define G_PROG(o) (*(progsnum_t *)&pr_globals[o]) //simply so it's nice and easy to change...
|
||||||
|
|
||||||
|
#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))
|
||||||
|
|
||||||
|
#define E_FLOAT(e,o) (((float*)&e->v)[o])
|
||||||
|
#define E_INT(e,o) (*(int *)&((float*)&e->v)[o])
|
||||||
|
#define E_VECTOR(e,o) (&((float*)&e->v)[o])
|
||||||
|
#define E_STRING(e,o) (*(string_t *)&((float*)(e+1))[o])
|
||||||
|
|
||||||
|
extern int type_size[9];
|
||||||
|
|
||||||
|
|
||||||
|
extern unsigned short pr_crc;
|
||||||
|
|
||||||
|
void VARGS PR_RunError (progfuncs_t *progfuncs, char *error, ...);
|
||||||
|
|
||||||
|
void ED_PrintEdicts (progfuncs_t *progfuncs);
|
||||||
|
void ED_PrintNum (progfuncs_t *progfuncs, int ent);
|
||||||
|
|
||||||
|
|
||||||
|
pbool PR_SwitchProgs(progfuncs_t *progfuncs, progsnum_t type);
|
||||||
|
void PR_MoveParms(progfuncs_t *progfuncs, progsnum_t progs1, progsnum_t progs2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
eval_t *GetEdictFieldValue(progfuncs_t *progfuncs, struct edict_s *ed, char *name, evalc_t *cache);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COMPILER
|
||||||
|
|
||||||
|
//this is windows - all files are written with this endian standard
|
||||||
|
//optimisation
|
||||||
|
//leave undefined if in doubt over os.
|
||||||
|
#ifndef WIN32
|
||||||
|
#define NOENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int varofs;
|
||||||
|
int size;
|
||||||
|
} sharedvar_t;
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
dfunction_t *f;
|
||||||
|
int progsnum;
|
||||||
|
} prstack_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//pr_multi.c
|
||||||
|
void PR_SetBuiltins(int type);
|
||||||
|
|
||||||
|
#define var(type, name) type name
|
||||||
|
#define vars(type, name, size) type name[size]
|
||||||
|
|
||||||
|
typedef struct prinst_s {
|
||||||
|
var(progstate_t *, pr_progstate);
|
||||||
|
#define pr_progstate prinst->pr_progstate
|
||||||
|
|
||||||
|
var(progsnum_t, pr_typecurrent);
|
||||||
|
#define pr_typecurrent prinst->pr_typecurrent
|
||||||
|
var(int, maxprogs);
|
||||||
|
#define maxprogs prinst->maxprogs
|
||||||
|
|
||||||
|
var(progstate_t *,current_progstate);
|
||||||
|
#define current_progstate prinst->current_progstate
|
||||||
|
|
||||||
|
var(unsigned int, numshares);
|
||||||
|
#define numshares prinst->numshares
|
||||||
|
var(sharedvar_t *,shares); //shared globals, not including parms
|
||||||
|
#define shares prinst->shares
|
||||||
|
var(unsigned int, maxshares);
|
||||||
|
#define maxshares prinst->maxshares
|
||||||
|
|
||||||
|
var(struct prmemb_s *, memblocks);
|
||||||
|
#define memb prinst->memblocks
|
||||||
|
|
||||||
|
var(unsigned int, maxfields);
|
||||||
|
#define maxfields prinst->maxfields
|
||||||
|
var(unsigned int, numfields);
|
||||||
|
#define numfields prinst->numfields
|
||||||
|
var(fdef_t*, field); //biggest size
|
||||||
|
#define field prinst->field
|
||||||
|
|
||||||
|
int reorganisefields;
|
||||||
|
|
||||||
|
|
||||||
|
//pr_exec.c
|
||||||
|
#define MAX_STACK_DEPTH 64
|
||||||
|
vars(prstack_t, pr_stack, MAX_STACK_DEPTH);
|
||||||
|
#define pr_stack prinst->pr_stack
|
||||||
|
var(int, pr_depth);
|
||||||
|
#define pr_depth prinst->pr_depth
|
||||||
|
|
||||||
|
#define LOCALSTACK_SIZE 16384
|
||||||
|
vars(int, localstack, LOCALSTACK_SIZE);
|
||||||
|
#define localstack prinst->localstack
|
||||||
|
var(int, localstack_used);
|
||||||
|
#define localstack_used prinst->localstack_used
|
||||||
|
|
||||||
|
var(int, continuestatement);
|
||||||
|
var(int, exitdepth);
|
||||||
|
|
||||||
|
var(int, pr_trace);
|
||||||
|
#define pr_trace prinst->pr_trace
|
||||||
|
var(dfunction_t *, pr_xfunction);
|
||||||
|
#define pr_xfunction prinst->pr_xfunction
|
||||||
|
var(int, pr_xstatement);
|
||||||
|
#define pr_xstatement prinst->pr_xstatement
|
||||||
|
|
||||||
|
var(int, pr_argc);
|
||||||
|
#define pr_argc prinst->pr_argc
|
||||||
|
|
||||||
|
//pr_edict.c
|
||||||
|
|
||||||
|
var(int, maxedicts);
|
||||||
|
#define maxedicts prinst->maxedicts
|
||||||
|
|
||||||
|
var(evalc_t, spawnflagscache);
|
||||||
|
#define spawnflagscache prinst->spawnflagscache
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var(int, pr_edict_size); // in bytes
|
||||||
|
#define pr_edict_size prinst->pr_edict_size
|
||||||
|
var(int, pr_max_edict_size);
|
||||||
|
#define pr_max_edict_size prinst->pr_max_edict_size
|
||||||
|
|
||||||
|
|
||||||
|
//initlib.c
|
||||||
|
var(char *, progshunk);
|
||||||
|
#define progshunk prinst->progshunk
|
||||||
|
var(int, hunkused);
|
||||||
|
#define hunkused prinst->hunkused
|
||||||
|
var(int, hunksize);
|
||||||
|
#define hunksize prinst->hunksize
|
||||||
|
|
||||||
|
|
||||||
|
var(extensionbuiltin_t *, extensionbuiltin);
|
||||||
|
#define extensionbuiltin prinst->extensionbuiltin
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
struct edict_s **edicttable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} prinst_t;
|
||||||
|
extern vec3_t vec3_origin;
|
||||||
|
|
||||||
|
eval_t *PR_FindGlobal(progfuncs_t *prfuncs, char *globname, progsnum_t pnum);
|
||||||
|
ddef16_t *ED_FindTypeGlobalFromProgs16 (progfuncs_t *progfuncs, char *name, progsnum_t prnum, int type);
|
||||||
|
ddef32_t *ED_FindTypeGlobalFromProgs32 (progfuncs_t *progfuncs, char *name, progsnum_t prnum, int type);
|
||||||
|
ddef16_t *ED_FindGlobalFromProgs16 (progfuncs_t *progfuncs, char *name, progsnum_t prnum);
|
||||||
|
ddef32_t *ED_FindGlobalFromProgs32 (progfuncs_t *progfuncs, char *name, progsnum_t prnum);
|
||||||
|
fdef_t *ED_FindField (progfuncs_t *progfuncs, char *name);
|
||||||
|
dfunction_t *ED_FindFunction (progfuncs_t *progfuncs, char *name, int *pnum, int fromprogs);
|
||||||
|
func_t PR_FindFunc(progfuncs_t *progfncs, char *funcname, progsnum_t pnum);
|
||||||
|
void PR_Configure (progfuncs_t *progfncs, void *mem, int mem_size, int max_progs);
|
||||||
|
int PR_InitEnts(progfuncs_t *progfncs, int maxents);
|
||||||
|
char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val);
|
||||||
|
|
||||||
|
ddef16_t *ED_GlobalAtOfs16 (progfuncs_t *progfuncs, int ofs);
|
||||||
|
ddef16_t *ED_FindGlobal16 (progfuncs_t *progfuncs, char *name);
|
||||||
|
ddef32_t *ED_FindGlobal32 (progfuncs_t *progfuncs, char *name);
|
||||||
|
ddef32_t *ED_GlobalAtOfs32 (progfuncs_t *progfuncs, unsigned int ofs);
|
||||||
|
|
||||||
|
char *PR_GlobalString (progfuncs_t *progfuncs, int ofs);
|
||||||
|
char *PR_GlobalStringNoContents (progfuncs_t *progfuncs, int ofs);
|
||||||
|
|
||||||
|
pbool CompileFile(progfuncs_t *progfuncs, char *filename);
|
||||||
|
|
||||||
|
char *QCC_COM_Parse (char *data);
|
||||||
|
extern char qcc_token[1024];
|
||||||
|
#endif
|
278
engine/qclib/Progslib.h
Normal file
278
engine/qclib/Progslib.h
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
/*#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
#define PITCH 0
|
||||||
|
#define YAW 1
|
||||||
|
#define ROLL 2
|
||||||
|
|
||||||
|
typedef char bool;
|
||||||
|
//typedef float vec3_t[3];
|
||||||
|
typedef int progsnum_t;
|
||||||
|
typedef int func_t;
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef char *string_t;
|
||||||
|
#endif
|
||||||
|
//typedef struct globalvars_s globalvars_t;
|
||||||
|
//typedef struct edict_s edict_t;
|
||||||
|
#define globalvars_t void
|
||||||
|
#define edict_t void
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define VARGS __cdecl
|
||||||
|
#endif
|
||||||
|
#ifndef VARGS
|
||||||
|
#define VARGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct edict_s;
|
||||||
|
struct globalvars_s;
|
||||||
|
typedef struct progfuncs_s progfuncs_t;
|
||||||
|
typedef void (*builtin_t) (progfuncs_t *prinst, struct globalvars_s *gvars);
|
||||||
|
|
||||||
|
//used by progs engine. All nulls is reset.
|
||||||
|
typedef struct {
|
||||||
|
char *varname;
|
||||||
|
struct fdef_s *ofs32;
|
||||||
|
|
||||||
|
int spare[2];
|
||||||
|
} evalc_t;
|
||||||
|
#define sizeofevalc sizeof(evalc_t)
|
||||||
|
typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_struct, ev_union} etype_t;
|
||||||
|
|
||||||
|
struct progfuncs_s {
|
||||||
|
int progsversion; //PROGSTRUCT_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
void (*PR_Configure) (progfuncs_t *prinst, void *mem, int memsize, int max_progs); //configure buffers and memory. Used to reset and must be called first.
|
||||||
|
progsnum_t (*PR_LoadProgs) (progfuncs_t *prinst, char *s, int headercrc, builtin_t *builtins, int numbuiltins); //load a progs
|
||||||
|
int (*PR_InitEnts) (progfuncs_t *prinst, int max_ents); //returns size of edicts for use with nextedict macro
|
||||||
|
void (*PR_ExecuteProgram) (progfuncs_t *prinst, func_t fnum); //start execution
|
||||||
|
pbool (*PR_SwitchProgs) (progfuncs_t *prinst, progsnum_t num); //switch to a different progs - my aim is to make this obsolete
|
||||||
|
struct globalvars_s *(*globals) (progfuncs_t *prinst, progsnum_t num); //get the globals of a progs
|
||||||
|
struct entvars_s *(*entvars) (progfuncs_t *prinst, struct edict_s *ent); //return a pointer to the entvars of an ent
|
||||||
|
|
||||||
|
void (VARGS *PR_RunError) (progfuncs_t *prinst, char *msg, ...); //builtins call this to say there was a problem
|
||||||
|
void (*PR_PrintEdict) (progfuncs_t *prinst, struct edict_s *ed); //get a listing of all vars on an edict (sent back via 'print')
|
||||||
|
|
||||||
|
struct edict_s *(*ED_Alloc) (progfuncs_t *prinst);
|
||||||
|
void (*ED_Free) (progfuncs_t *prinst, struct edict_s *ed);
|
||||||
|
|
||||||
|
struct edict_s *(*EDICT_NUM) (progfuncs_t *prinst, int n); //get the nth edict
|
||||||
|
int (*NUM_FOR_EDICT) (progfuncs_t *prinst, struct edict_s *e); //so you can find out what that 'n' will be
|
||||||
|
|
||||||
|
void (*SetGlobalEdict) (progfuncs_t *prinst, struct edict_s *ed, int ofs); //set a global to an edict (partially obsolete)
|
||||||
|
|
||||||
|
char *(*PR_VarString) (progfuncs_t *prinst, int first); //returns a string made up of multiple arguments
|
||||||
|
|
||||||
|
struct progstate_s **progstate; //these are so the macros work properly
|
||||||
|
// struct edict_s **sv_edicts;
|
||||||
|
|
||||||
|
// int *sv_num_edicts;
|
||||||
|
|
||||||
|
func_t (*PR_FindFunction) (progfuncs_t *prinst, char *funcname, progsnum_t num);
|
||||||
|
|
||||||
|
int (*PR_StartCompile) (progfuncs_t *prinst, int argv, char **argc); //1 if can compile, 0 if failed to compile
|
||||||
|
int (*PR_ContinueCompile) (progfuncs_t *prinst); //2 if finished, 1 if more to go, 0 if failed
|
||||||
|
|
||||||
|
char *(*filefromprogs) (progfuncs_t *prinst, progsnum_t prnum, char *fname, int *size, char *buffer); //reveals encoded/added files from already loaded progs
|
||||||
|
char *(*filefromnewprogs) (progfuncs_t *prinst, char *prname, char *fname, int *size, char *buffer); //reveals encoded/added files from a progs on the disk somewhere
|
||||||
|
|
||||||
|
char *(*save_ents) (progfuncs_t *prinst, char *buf, int *size, int mode); //dump the entire progs info into one big self allocated string
|
||||||
|
int (*load_ents) (progfuncs_t *prinst, char *s, float killonspawnflags); //restore the entire progs state (or just add some more ents) (returns edicts ize)
|
||||||
|
|
||||||
|
char *(*saveent) (progfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will save just one entities vars
|
||||||
|
struct edict_s *(*restoreent) (progfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will restore the entity that had it's values saved (can use NULL for ed)
|
||||||
|
|
||||||
|
union eval_s *(*FindGlobal) (progfuncs_t *prinst, char *name, progsnum_t num); //find a pointer to the globals value
|
||||||
|
char *(*AddString) (progfuncs_t *prinst, char *val); //dump a string into the progs memory (for setting globals and whatnot)
|
||||||
|
void *(*Tempmem) (progfuncs_t *prinst, int ammount, char *whatfor); //grab some mem for as long as the progs stays loaded (for strings)
|
||||||
|
|
||||||
|
union eval_s *(*GetEdictFieldValue) (progfuncs_t *prinst, struct edict_s *ent, char *name, evalc_t *s); //get an entityvar (cache it) and return the possible values
|
||||||
|
struct edict_s *(*ProgsToEdict) (progfuncs_t *prinst, int progs); //edicts are stored as ints and need to be adjusted
|
||||||
|
int (*EdictToProgs) (progfuncs_t *prinst, struct edict_s *ed); //edicts are stored as ints and need to be adjusted
|
||||||
|
|
||||||
|
char *(*EvaluateDebugString) (progfuncs_t *prinst, char *key); //evaluate a string and return it's value (according to current progs) (expands edict vars)
|
||||||
|
|
||||||
|
int *pr_trace; //start calling the editor for each line executed
|
||||||
|
|
||||||
|
void (*PR_StackTrace) (progfuncs_t *prinst);
|
||||||
|
|
||||||
|
int (*ToggleBreak) (progfuncs_t *prinst, char *filename, int linenum, int mode);
|
||||||
|
|
||||||
|
int numprogs;
|
||||||
|
|
||||||
|
struct progexterns_s *parms; //these are the initial parms, they may be changed
|
||||||
|
|
||||||
|
pbool (*Decompile) (progfuncs_t *prinst, char *fname);
|
||||||
|
|
||||||
|
|
||||||
|
struct prinst_s *prinst; //internal variables. Leave alone.
|
||||||
|
|
||||||
|
int *callargc; //number of args of built-in call
|
||||||
|
void (*RegisterBuiltin) (progfuncs_t *prinst, char *, builtin_t);
|
||||||
|
|
||||||
|
int stringtable; //qc strings are all relative. add to a qc string. this is required for support of frikqcc progs that strip string immediates.
|
||||||
|
int fieldadjust; //FrikQCC style arrays can cause problems due to field remapping. This causes us to leave gaps but offsets identical.
|
||||||
|
|
||||||
|
struct qcthread_s *(*Fork) (progfuncs_t *prinst);
|
||||||
|
void (*RunThread) (progfuncs_t *prinst, struct qcthread_s *thread);
|
||||||
|
void (*AbortStack) (progfuncs_t *prinst);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct progexterns_s {
|
||||||
|
int progsversion; //PROGSTRUCT_VERSION
|
||||||
|
|
||||||
|
unsigned char *(*ReadFile) (char *fname, void *buffer, int len);
|
||||||
|
int (*FileSize) (char *fname); //-1 if file does not exist
|
||||||
|
pbool (*WriteFile) (char *name, void *data, int len);
|
||||||
|
int (VARGS *printf) (const char *, ...);
|
||||||
|
void (VARGS *Sys_Error) (const char *, ...);
|
||||||
|
void (VARGS *Abort) (char *, ...);
|
||||||
|
int edictsize; //size of edict_t
|
||||||
|
|
||||||
|
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
|
||||||
|
pbool (*entcanfree) (struct edict_s *ent); //return true to stop ent from being freed
|
||||||
|
void (*stateop) (progfuncs_t *prinst, float var, func_t func);
|
||||||
|
void (*cstateop) (progfuncs_t *prinst, float vara, float varb, func_t currentfunc);
|
||||||
|
void (*cwstateop) (progfuncs_t *prinst, float vara, float varb, func_t currentfunc);
|
||||||
|
void (*thinktimeop) (progfuncs_t *prinst, struct edict_s *ent, float varb);
|
||||||
|
|
||||||
|
|
||||||
|
//used when loading a game
|
||||||
|
builtin_t *(*builtinsfor) (int num, int headercrc); //must return a pointer to the builtins that were used before the state was saved.
|
||||||
|
void (*loadcompleate) (int edictsize); //notification to reset any pointers.
|
||||||
|
|
||||||
|
void *(VARGS *memalloc) (int size); //small string allocation malloced and freed randomly by the executor. (use malloc if you want)
|
||||||
|
void (VARGS *memfree) (void * mem);
|
||||||
|
|
||||||
|
|
||||||
|
builtin_t *globalbuiltins; //these are available to all progs
|
||||||
|
int numglobalbuiltins;
|
||||||
|
|
||||||
|
enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS, PR_COMPILEIGNORE} autocompile;
|
||||||
|
|
||||||
|
double *gametime;
|
||||||
|
|
||||||
|
struct edict_s **sv_edicts;
|
||||||
|
int *sv_num_edicts;
|
||||||
|
|
||||||
|
int (*useeditor) (char *filename, int line, int nump, char **parms);
|
||||||
|
} progparms_t, progexterns_t;
|
||||||
|
|
||||||
|
void QC_AddSharedVar(progfuncs_t *progfuncs, int start, int size);
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(QCLIBDLL_EXPORTS)
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
progfuncs_t * InitProgs(progparms_t *ext);
|
||||||
|
#if defined(QCLIBDLL_EXPORTS)
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
void CloseProgs(progfuncs_t *inst);
|
||||||
|
|
||||||
|
#ifndef COMPILER
|
||||||
|
typedef union eval_s
|
||||||
|
{
|
||||||
|
string_t string;
|
||||||
|
float _float;
|
||||||
|
float vector[3];
|
||||||
|
func_t function;
|
||||||
|
int _int;
|
||||||
|
int edict;
|
||||||
|
progsnum_t prog; //so it can easily be changed
|
||||||
|
} eval_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PR_CURRENT -1
|
||||||
|
#define PR_ANY -2 //not always valid. Use for finding funcs
|
||||||
|
#define PROGSTRUCT_VERSION 1
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DLL_PROG
|
||||||
|
#define PR_Configure(pf, mem, memsize, max_progs) (*pf->PR_Configure) (pf, mem, memsize, max_progs)
|
||||||
|
#define PR_LoadProgs(pf, s, headercrc, builtins, numb) (*pf->PR_LoadProgs) (pf, s, headercrc, builtins, numb)
|
||||||
|
#define PR_InitEnts(pf, maxents) (*pf->PR_InitEnts) (pf, maxents)
|
||||||
|
#define PR_ExecuteProgram(pf, fnum) (*pf->PR_ExecuteProgram) (pf, fnum)
|
||||||
|
#define PR_SwitchProgs(pf, num) (*pf->PR_SwitchProgs) (pf, num);
|
||||||
|
#define PR_globals(pf, num) (*pf->globals) (pf, num)
|
||||||
|
#define PR_entvars(pf, ent) (*pf->entvars) (pf, ent)
|
||||||
|
|
||||||
|
#define ED_Alloc(pf) (*pf->ED_Alloc) (pf)
|
||||||
|
#define ED_Free(pf, ed) (*pf->ED_Free) (pf, ed)
|
||||||
|
|
||||||
|
#define PR_LoadEnts(pf, s, kf) (*pf->load_ents) (pf, s, kf)
|
||||||
|
#define PR_SaveEnts(pf, buf, size, mode) (*pf->save_ents) (pf, buf, size, mode)
|
||||||
|
|
||||||
|
#define EDICT_NUM(pf, num) (*pf->EDICT_NUM) (pf, num)
|
||||||
|
#define NUM_FOR_EDICT(pf, e) (*pf->NUM_FOR_EDICT) (pf, e)
|
||||||
|
#define SetGlobalEdict(pf, ed, ofs) (*pf->SetGlobalEdict) (pf, ed, ofs)
|
||||||
|
#define PR_VarString (*progfuncs->PR_VarString)
|
||||||
|
|
||||||
|
//#define sv_edicts (*progfuncs->sv_edicts)
|
||||||
|
#define current_progstate (*progfuncs->progstate)
|
||||||
|
|
||||||
|
//#define pr_num_edicts (*progfuncs->sv_num_edicts)
|
||||||
|
|
||||||
|
#define PR_FindFunction(pf, name, num) (*pf->PR_FindFunction) (pf, name, num)
|
||||||
|
#define PR_FindGlobal(pf, name, progs) (*pf->FindGlobal) (pf, name, progs)
|
||||||
|
#define PR_AddString(pf, ed) (*pf->AddString) (pf, ed)
|
||||||
|
#define PR_Alloc (*progfuncs->Tempmem)
|
||||||
|
|
||||||
|
#define PROG_TO_EDICT(pf, ed) (*pf->ProgsToEdict) (pf, ed)
|
||||||
|
#define EDICT_TO_PROG(pf, ed) (*pf->EdictToProgs) (pf, ed)
|
||||||
|
|
||||||
|
#define PR_RunError (*progfuncs->PR_RunError)
|
||||||
|
#define PR_PrintEdict (*progfuncs->PR_PrintEdict)
|
||||||
|
|
||||||
|
#define PR_RegisterBuiltin(pf, name, func) (*pf->RegisterBuiltin) (pf, name, func)
|
||||||
|
|
||||||
|
//#ifdef DYNAMIC_ENTS
|
||||||
|
#define NEXT_EDICT(pf,o) EDICT_NUM(pf, NUM_FOR_EDICT(pf, o)+1)
|
||||||
|
/*#else
|
||||||
|
#define NEXT_EDICT(pf, o) (edict_t *)(((char *)o)+ pr_edict_size)
|
||||||
|
#endif*/
|
||||||
|
#define RETURN_EDICT(pf, e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(pf, e))
|
||||||
|
|
||||||
|
|
||||||
|
//builtin funcs (which operate on globals)
|
||||||
|
#define G_FLOAT(o) (((float *)pr_globals)[o])
|
||||||
|
#define G_FLOAT2(o) (((float *)pr_globals)[OFS_PARM0 + o*3])
|
||||||
|
#define G_INT(o) (((int *)pr_globals)[o])
|
||||||
|
#define G_EDICT(pf, o) PROG_TO_EDICT(pf, G_INT(o)) //((edict_t *)((char *) sv.edicts+ *(int *)&((float *)pr_globals)[o]))
|
||||||
|
#define G_EDICTNUM(pf, o) NUM_FOR_EDICT(pf, G_EDICT(pf, o))
|
||||||
|
#define G_VECTOR(o) (&((float *)pr_globals)[o])
|
||||||
|
#define G_FUNCTION(o) (*(func_t *)&((float *)pr_globals)[o])
|
||||||
|
#define G_PROG(o) (*(progsnum_t *)&((float *)pr_globals)[o]) //simply so it's nice and easy to change...
|
||||||
|
|
||||||
|
#define PR_GetString(p,s) (s?s + p->stringtable:"")
|
||||||
|
#define PR_GetStringOfs(p,o) (G_INT(o)?(char *)G_INT(o) + p->stringtable:"")
|
||||||
|
#define PR_SetString(p, s) ((s&&*s)?(s - p->stringtable):0)
|
||||||
|
#define PR_NewString(p, s) (PR_AddString(p, s) - p->stringtable)
|
||||||
|
|
||||||
|
#define ev_prog ev_integer
|
||||||
|
|
||||||
|
#define E_STRING(o) (char *)(((int *)((char *)ed) + progparms.edictsize)[o])
|
||||||
|
|
||||||
|
//#define pr_global_struct pr_globals
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define OFS_NULL 0
|
||||||
|
#define OFS_RETURN 1
|
||||||
|
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
|
||||||
|
#define OFS_PARM1 7
|
||||||
|
#define OFS_PARM2 10
|
||||||
|
#define OFS_PARM3 13
|
||||||
|
#define OFS_PARM4 16
|
||||||
|
#define OFS_PARM5 19
|
||||||
|
#define OFS_PARM6 22
|
||||||
|
#define OFS_PARM7 25
|
||||||
|
#define RESERVED_OFS 28
|
||||||
|
|
||||||
|
|
||||||
|
#undef edict_t
|
||||||
|
#undef globalvars_t
|
3198
engine/qclib/QccMain.c
Normal file
3198
engine/qclib/QccMain.c
Normal file
File diff suppressed because it is too large
Load diff
83
engine/qclib/cmdlib.h
Normal file
83
engine/qclib/cmdlib.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// cmdlib.h
|
||||||
|
|
||||||
|
#ifndef __CMDLIB__
|
||||||
|
#define __CMDLIB__
|
||||||
|
|
||||||
|
#include "progsint.h"
|
||||||
|
|
||||||
|
/*#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#ifdef NeXT
|
||||||
|
#include <libc.h>
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
// the dec offsetof macro doesn't work very well...
|
||||||
|
#define myoffsetof(type,identifier) ((size_t)&((type *)NULL)->identifier)
|
||||||
|
|
||||||
|
|
||||||
|
// set these before calling CheckParm
|
||||||
|
extern int myargc;
|
||||||
|
extern char **myargv;
|
||||||
|
|
||||||
|
//char *strupr (char *in);
|
||||||
|
//char *strlower (char *in);
|
||||||
|
int QCC_filelength (int handle);
|
||||||
|
int QCC_tell (int handle);
|
||||||
|
|
||||||
|
int QC_strcasecmp (const char *s1, const char *s2);
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define QC_vsnprintf _vsnprintf
|
||||||
|
#else
|
||||||
|
#define QC_vsnprintf vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double I_FloatTime (void);
|
||||||
|
|
||||||
|
void VARGS QCC_Error (int errortype, const char *error, ...);
|
||||||
|
int CheckParm (char *check);
|
||||||
|
|
||||||
|
|
||||||
|
int SafeOpenWrite (char *filename, int maxsize);
|
||||||
|
int SafeOpenRead (char *filename);
|
||||||
|
void SafeRead (int handle, void *buffer, long count);
|
||||||
|
void SafeWrite (int handle, void *buffer, long count);
|
||||||
|
void SafeClose(int handle);
|
||||||
|
int SafeSeek(int hand, int ofs, int mode);
|
||||||
|
void *SafeMalloc (long size);
|
||||||
|
|
||||||
|
|
||||||
|
long QCC_LoadFile (char *filename, void **bufferptr);
|
||||||
|
void QCC_SaveFile (char *filename, void *buffer, long count);
|
||||||
|
|
||||||
|
void DefaultExtension (char *path, char *extension);
|
||||||
|
void DefaultPath (char *path, char *basepath);
|
||||||
|
void StripFilename (char *path);
|
||||||
|
void StripExtension (char *path);
|
||||||
|
|
||||||
|
void ExtractFilePath (char *path, char *dest);
|
||||||
|
void ExtractFileBase (char *path, char *dest);
|
||||||
|
void ExtractFileExtension (char *path, char *dest);
|
||||||
|
|
||||||
|
long ParseNum (char *str);
|
||||||
|
|
||||||
|
|
||||||
|
char *QCC_COM_Parse (char *data);
|
||||||
|
|
||||||
|
extern char qcc_token[1024];
|
||||||
|
extern int qcc_eof;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
973
engine/qclib/execloop.h
Normal file
973
engine/qclib/execloop.h
Normal file
|
@ -0,0 +1,973 @@
|
||||||
|
//qc execution code.
|
||||||
|
//we have two conditions.
|
||||||
|
//one allows us to debug and trace through our code, the other doesn't.
|
||||||
|
|
||||||
|
//hopefully, the compiler will do a great job at optimising this code for us, where required.
|
||||||
|
//if it dosn't, then bum.
|
||||||
|
|
||||||
|
//the general overhead should be reduced significantly, and I would be supprised if it did run slower.
|
||||||
|
|
||||||
|
//run away loops are checked for ONLY on gotos and function calls. This might give a poorer check, but it will run faster overall.
|
||||||
|
|
||||||
|
//Appears to work fine.
|
||||||
|
|
||||||
|
#if INTSIZE == 16
|
||||||
|
#define cont cont16
|
||||||
|
#define reeval reeval16
|
||||||
|
#define st st16
|
||||||
|
#define pr_statements pr_statements16
|
||||||
|
#define fakeop fakeop16
|
||||||
|
#define dstatement_t dstatement16_t
|
||||||
|
#define sofs signed short
|
||||||
|
#define uofs unsigned short
|
||||||
|
#elif INTSIZE == 32
|
||||||
|
#define cont cont32
|
||||||
|
#define reeval reeval32
|
||||||
|
#define st st32
|
||||||
|
#define pr_statements pr_statements32
|
||||||
|
#define fakeop fakeop32
|
||||||
|
#define dstatement_t dstatement32_t
|
||||||
|
#define sofs signed int
|
||||||
|
#define uofs unsigned int
|
||||||
|
#elif INTSIZE == 24
|
||||||
|
#error INTSIZE should be set to 32.
|
||||||
|
#else
|
||||||
|
#error Bad cont size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//rely upon just st
|
||||||
|
{
|
||||||
|
#ifdef DEBUGABLE
|
||||||
|
cont: //last statement may have been a breakpoint
|
||||||
|
s = st-pr_statements;
|
||||||
|
s+=1;
|
||||||
|
s=ShowStep(progfuncs, s);
|
||||||
|
st = pr_statements + s;
|
||||||
|
|
||||||
|
reeval:
|
||||||
|
#else
|
||||||
|
st++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (st->op)
|
||||||
|
{
|
||||||
|
case OP_ADD_F:
|
||||||
|
OPC->_float = OPA->_float + OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADD_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_F:
|
||||||
|
OPC->_float = OPA->_float - OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_F:
|
||||||
|
OPC->_float = OPA->_float * OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_MUL_V:
|
||||||
|
OPC->_float = OPA->vector[0]*OPB->vector[0]
|
||||||
|
+ OPA->vector[1]*OPB->vector[1]
|
||||||
|
+ OPA->vector[2]*OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_FV:
|
||||||
|
OPC->vector[0] = OPA->_float * OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->_float * OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->_float * OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_VF:
|
||||||
|
OPC->vector[0] = OPB->_float * OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float * OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float * OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV_F:
|
||||||
|
OPC->_float = OPA->_float / OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIV_VF:
|
||||||
|
OPC->vector[0] = OPB->_float / OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float / OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float / OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND:
|
||||||
|
OPC->_float = (float)((int)OPA->_float & (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR:
|
||||||
|
OPC->_float = (float)((int)OPA->_float | (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_GE:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int >= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LE:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int <= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GT:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int > OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LT:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int < OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_NOT_F:
|
||||||
|
OPC->_float = (float)(!OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_NOT_V:
|
||||||
|
OPC->_float = (float)(!OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
case OP_NOT_S:
|
||||||
|
OPC->_float = (float)(!(OPA->string) || !*(OPA->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NOT_FNC:
|
||||||
|
OPC->_float = (float)(!(OPA->function & ~0xff000000));
|
||||||
|
break;
|
||||||
|
case OP_NOT_ENT:
|
||||||
|
OPC->_float = (float)(PROG_TO_EDICT(OPA->edict) == (edictrun_t *)sv_edicts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EQ_F:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_EQ_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] == OPB->vector[0]) &&
|
||||||
|
(OPA->vector[1] == OPB->vector[1]) &&
|
||||||
|
(OPA->vector[2] == OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_EQ_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = true;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(!strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_EQ_E:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function == OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_NE_F:
|
||||||
|
OPC->_float = (float)(OPA->_float != OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_NE_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] != OPB->vector[0]) ||
|
||||||
|
(OPA->vector[1] != OPB->vector[1]) ||
|
||||||
|
(OPA->vector[2] != OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_NE_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = false;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NE_E:
|
||||||
|
OPC->_float = (float)(OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function != OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
case OP_STORE_IF:
|
||||||
|
OPB->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_FI:
|
||||||
|
OPB->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STORE_I:
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_F:
|
||||||
|
case OP_STORE_ENT:
|
||||||
|
case OP_STORE_FLD: // integers
|
||||||
|
case OP_STORE_S:
|
||||||
|
case OP_STORE_FNC: // pointers
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_V:
|
||||||
|
OPB->vector[0] = OPA->vector[0];
|
||||||
|
OPB->vector[1] = OPA->vector[1];
|
||||||
|
OPB->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//store a value to a pointer
|
||||||
|
case OP_STOREP_IF:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_FI:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_I:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_F:
|
||||||
|
case OP_STOREP_ENT:
|
||||||
|
case OP_STOREP_FLD: // integers
|
||||||
|
case OP_STOREP_S:
|
||||||
|
case OP_STOREP_FNC: // pointers
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_V:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->vector[0] = OPA->vector[0];
|
||||||
|
ptr->vector[1] = OPA->vector[1];
|
||||||
|
ptr->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_STOREP_C: //store character in a string
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
*(unsigned char *)ptr = (char)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULSTORE_F: // f *= f
|
||||||
|
OPB->_float *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTORE_V: // v *= f
|
||||||
|
OPB->vector[0] *= OPA->_float;
|
||||||
|
OPB->vector[1] *= OPA->_float;
|
||||||
|
OPB->vector[2] *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_F: // e.f *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float *= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_V: // e.v *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[1] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[2] *= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIVSTORE_F: // f /= f
|
||||||
|
OPB->_float /= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIVSTOREP_F: // e.f /= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float /= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADDSTORE_F: // f += f
|
||||||
|
OPB->_float += OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADDSTORE_V: // v += v
|
||||||
|
OPB->vector[0] += OPA->vector[0];
|
||||||
|
OPB->vector[1] += OPA->vector[1];
|
||||||
|
OPB->vector[2] += OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_F: // e.f += f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float += OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_V: // e.v += v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUBSTORE_F: // f -= f
|
||||||
|
OPB->_float -= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUBSTORE_V: // v -= v
|
||||||
|
OPB->vector[0] -= OPA->vector[0];
|
||||||
|
OPB->vector[1] -= OPA->vector[1];
|
||||||
|
OPB->vector[2] -= OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_F: // e.f -= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float -= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_V: // e.v -= v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//get a pointer to a field var
|
||||||
|
case OP_ADDRESS:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
if (ed->readonly)
|
||||||
|
PR_RunError (progfuncs, "assignment to read-only entity");
|
||||||
|
OPC->_int = (int)(((int *)edvars(ed)) + OPB->_int + progfuncs->fieldadjust);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//load a field to a value
|
||||||
|
case OP_LOAD_I:
|
||||||
|
case OP_LOAD_F:
|
||||||
|
case OP_LOAD_FLD:
|
||||||
|
case OP_LOAD_ENT:
|
||||||
|
case OP_LOAD_S:
|
||||||
|
case OP_LOAD_FNC:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int + progfuncs->fieldadjust);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOAD_V:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int + progfuncs->fieldadjust);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case OP_IFNOTS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->string || !*OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFNOT:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->string && *OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IF:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GOTO:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->a - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CALL8H:
|
||||||
|
case OP_CALL7H:
|
||||||
|
case OP_CALL6H:
|
||||||
|
case OP_CALL5H:
|
||||||
|
case OP_CALL4H:
|
||||||
|
case OP_CALL3H:
|
||||||
|
case OP_CALL2H:
|
||||||
|
G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
|
||||||
|
case OP_CALL1H:
|
||||||
|
G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
|
||||||
|
|
||||||
|
case OP_CALL8:
|
||||||
|
case OP_CALL7:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL0:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
|
||||||
|
|
||||||
|
if (st->op > OP_CALL8)
|
||||||
|
pr_argc = st->op - (OP_CALL1H-1);
|
||||||
|
else
|
||||||
|
pr_argc = st->op - OP_CALL0;
|
||||||
|
fnum = OPA->function;
|
||||||
|
if ((fnum & ~0xff000000)<=0)
|
||||||
|
{
|
||||||
|
pr_trace++;
|
||||||
|
printf("NULL function from qc.\n");
|
||||||
|
#ifndef DEBUGABLE
|
||||||
|
goto cont;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
static char buffer[1024*1024*8];
|
||||||
|
int size = sizeof buffer;
|
||||||
|
progfuncs->save_ents(progfuncs, buffer, &size, 0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
p=pr_typecurrent;
|
||||||
|
//about to switch. needs caching.
|
||||||
|
|
||||||
|
//if it's an external call, switch now (before any function pointers are used)
|
||||||
|
PR_MoveParms(progfuncs, (fnum & 0xff000000)>>24, p);
|
||||||
|
PR_SwitchProgs(progfuncs, (fnum & 0xff000000)>>24);
|
||||||
|
|
||||||
|
newf = &pr_functions[fnum & ~0xff000000];
|
||||||
|
|
||||||
|
if (newf->first_statement < 0)
|
||||||
|
{ // negative statements are built in functions
|
||||||
|
i = -newf->first_statement;
|
||||||
|
// p = pr_typecurrent;
|
||||||
|
if (i < externs->numglobalbuiltins)
|
||||||
|
{
|
||||||
|
(*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
if (prinst->continuestatement!=-1)
|
||||||
|
{
|
||||||
|
st=&pr_statements[prinst->continuestatement];
|
||||||
|
prinst->continuestatement=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i -= externs->numglobalbuiltins;
|
||||||
|
if (i > current_progstate->numbuiltins)
|
||||||
|
{
|
||||||
|
if (newf->first_statement == -0x7fffffff)
|
||||||
|
((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
else
|
||||||
|
PR_RunError (progfuncs, "Bad builtin call number - %i", -newf->first_statement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
}
|
||||||
|
PR_MoveParms(progfuncs, p, pr_typecurrent);
|
||||||
|
// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t));
|
||||||
|
PR_SwitchProgs(progfuncs, (progsnum_t)p);
|
||||||
|
|
||||||
|
//#ifndef DEBUGABLE //decide weather non debugger wants to start debugging.
|
||||||
|
s = st-pr_statements;
|
||||||
|
goto restart;
|
||||||
|
//#endif
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// PR_MoveParms((OPA->function & 0xff000000)>>24, pr_typecurrent);
|
||||||
|
// PR_SwitchProgs((OPA->function & 0xff000000)>>24);
|
||||||
|
s = PR_EnterFunction (progfuncs, newf, p);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_DONE:
|
||||||
|
case OP_RETURN:
|
||||||
|
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
|
||||||
|
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||||
|
pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
|
||||||
|
pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
static char buffer[1024*1024*8];
|
||||||
|
int size = sizeof buffer;
|
||||||
|
progfuncs->save_ents(progfuncs, buffer, &size, 0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
s = PR_LeaveFunction (progfuncs);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
if (pr_depth == prinst->exitdepth)
|
||||||
|
{
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_STATE:
|
||||||
|
externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_I:
|
||||||
|
OPC->_int = OPA->_int + OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_FI:
|
||||||
|
OPC->_float = OPA->_float + (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_IF:
|
||||||
|
OPC->_float = (float)OPA->_int + OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_I:
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_FI:
|
||||||
|
OPC->_float = OPA->_float - (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_IF:
|
||||||
|
OPC->_float = (float)OPA->_int - OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CONV_ITOF:
|
||||||
|
OPC->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_CONV_FTOI:
|
||||||
|
OPC->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_ITOF:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_float = (float)ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_FTOI:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_int = (int)ptr->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND_I:
|
||||||
|
OPC->_int = (OPA->_int & OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR_I:
|
||||||
|
OPC->_int = (OPA->_int | OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_I:
|
||||||
|
OPC->_int = OPA->_int * OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_DIV_I:
|
||||||
|
if (OPB->_int == 0) //no division by zero allowed...
|
||||||
|
OPC->_int = 0;
|
||||||
|
else
|
||||||
|
OPC->_int = OPA->_int / OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_EQ_I:
|
||||||
|
OPC->_int = (OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_I:
|
||||||
|
OPC->_int = (OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//array/structure reading/riting.
|
||||||
|
case OP_GLOBALADDRESS:
|
||||||
|
OPC->_int = (int)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
|
||||||
|
OPC->_int = OPA->_int + OPB->_int*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_I:
|
||||||
|
case OP_LOADA_F:
|
||||||
|
case OP_LOADA_FLD:
|
||||||
|
case OP_LOADA_ENT:
|
||||||
|
case OP_LOADA_S:
|
||||||
|
case OP_LOADA_FNC:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_V:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case OP_ADD_SF: //(char*)c = (char*)a + (float)b
|
||||||
|
OPC->_int = OPA->_int + (int)OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_S: //(float)c = (char*)a - (char*)b
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_C: //load character from a string
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + (int)OPB->_float);
|
||||||
|
OPC->_float = *(unsigned char *)ptr;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_I:
|
||||||
|
case OP_LOADP_F:
|
||||||
|
case OP_LOADP_FLD:
|
||||||
|
case OP_LOADP_ENT:
|
||||||
|
case OP_LOADP_S:
|
||||||
|
case OP_LOADP_FNC:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADP_V:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int + 2 >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_POWER_I:
|
||||||
|
OPC->_int = OPA->_int ^ OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_RSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int >> OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int << OPB->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_FETCH_GBL_F:
|
||||||
|
case OP_FETCH_GBL_S:
|
||||||
|
case OP_FETCH_GBL_E:
|
||||||
|
case OP_FETCH_GBL_FNC:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a + i];
|
||||||
|
OPC->_int = t->_int;
|
||||||
|
break;
|
||||||
|
case OP_FETCH_GBL_V:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a
|
||||||
|
+((int)OPB->_float)*3];
|
||||||
|
OPC->vector[0] = t->vector[0];
|
||||||
|
OPC->vector[1] = t->vector[1];
|
||||||
|
OPC->vector[2] = t->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CSTATE:
|
||||||
|
externs->cstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CWSTATE:
|
||||||
|
externs->cwstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_THINKTIME:
|
||||||
|
externs->thinktimeop(progfuncs, (struct edict_s *)PROG_TO_EDICT(OPA->edict), OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_BITSET: // b (+) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITSETP: // .b (+) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITCLR: // b (-) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
case OP_BITCLRP: // .b (-) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_RAND0:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RAND1:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff)*OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_RAND2:
|
||||||
|
if(OPA->_float < OPB->_float)
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPA->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->_float-OPA->_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPB->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPA->_float-OPB->_float));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_RANDV0:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RANDV1:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[0];
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[1];
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_RANDV2:
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if(OPA->vector[i] < OPB->vector[i])
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPA->vector[i]+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->vector[i]-OPA->vector[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPB->vector[i]+(rand()*(1.0f/RAND_MAX)
|
||||||
|
*(OPA->vector[i]-OPB->vector[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
swtch = OPA;
|
||||||
|
swtchtype = st->op;
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b - 1; // offset the st++
|
||||||
|
break;
|
||||||
|
case OP_CASE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float == OPA->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
if ((!swtch->_int && progfuncs->stringtable[OPA->string]) || (!OPA->_int && progfuncs->stringtable[swtch->string])) //one is null (cannot be not both).
|
||||||
|
break;
|
||||||
|
if (!strcmp(progfuncs->stringtable+swtch->string, progfuncs->stringtable+OPA->string))
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
if (swtch->vector[0] == OPA->vector[0] && swtch->vector[1] == OPA->vector[1] && swtch->vector[2] == OPA->vector[2])
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_CASERANGE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->c-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case OP_MUL_IF:
|
||||||
|
case OP_MUL_FI:
|
||||||
|
case OP_MUL_VI:
|
||||||
|
case OP_DIV_IF:
|
||||||
|
case OP_DIV_FI:
|
||||||
|
case OP_BITAND_IF:
|
||||||
|
case OP_BITOR_IF:
|
||||||
|
case OP_BITAND_FI:
|
||||||
|
case OP_BITOR_FI:
|
||||||
|
case OP_AND_I:
|
||||||
|
case OP_OR_I:
|
||||||
|
case OP_AND_IF:
|
||||||
|
case OP_OR_IF:
|
||||||
|
case OP_AND_FI:
|
||||||
|
case OP_OR_FI:
|
||||||
|
case OP_NOT_I:
|
||||||
|
case OP_NE_IF:
|
||||||
|
case OP_NE_FI:
|
||||||
|
case OP_GSTOREP_I:
|
||||||
|
case OP_GSTOREP_F:
|
||||||
|
case OP_GSTOREP_ENT:
|
||||||
|
case OP_GSTOREP_FLD: // integers
|
||||||
|
case OP_GSTOREP_S:
|
||||||
|
case OP_GSTOREP_FNC: // pointers
|
||||||
|
case OP_GSTOREP_V:
|
||||||
|
case OP_GADDRESS:
|
||||||
|
case OP_GLOAD_I:
|
||||||
|
case OP_GLOAD_F:
|
||||||
|
case OP_GLOAD_FLD:
|
||||||
|
case OP_GLOAD_ENT:
|
||||||
|
case OP_GLOAD_S:
|
||||||
|
case OP_GLOAD_FNC:
|
||||||
|
case OP_BOUNDCHECK:
|
||||||
|
PR_RunError(progfuncs, "Extra opcode not implemented\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (st->op & 0x8000) //break point!
|
||||||
|
{
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
printf("Break point hit.\n");
|
||||||
|
if (pr_trace<1)
|
||||||
|
pr_trace=1; //this is what it's for
|
||||||
|
|
||||||
|
s = ShowStep(progfuncs, s);
|
||||||
|
st = &pr_statements[s]; //let the user move execution
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one.
|
||||||
|
fakeop.op &= ~0x8000;
|
||||||
|
st = &fakeop; //a little remapping...
|
||||||
|
|
||||||
|
goto reeval; //reexecute
|
||||||
|
}
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
PR_RunError (progfuncs, "Bad opcode %i", st->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef cont
|
||||||
|
#undef reeval
|
||||||
|
#undef st
|
||||||
|
#undef pr_statements
|
||||||
|
#undef fakeop
|
||||||
|
#undef dstatement_t
|
||||||
|
#undef sofs
|
||||||
|
#undef uofs
|
914
engine/qclib/execloop16.h
Normal file
914
engine/qclib/execloop16.h
Normal file
|
@ -0,0 +1,914 @@
|
||||||
|
//qc execution code.
|
||||||
|
//we have two conditions.
|
||||||
|
//one allows us to debug and trace through our code, the other doesn't.
|
||||||
|
|
||||||
|
//hopefully, the compiler will do a great job at optimising this code for us, where required.
|
||||||
|
//if it dosn't, then bum.
|
||||||
|
|
||||||
|
//the general overhead should be reduced significantly, and I would be supprised if it did run slower.
|
||||||
|
|
||||||
|
//run away loops are checked for ONLY on gotos and function calls. This might give a poorer check, but it will run faster overall.
|
||||||
|
|
||||||
|
//Appears to work fine.
|
||||||
|
|
||||||
|
#if INTSIZE == 16
|
||||||
|
#define cont cont16
|
||||||
|
#define reeval reeval16
|
||||||
|
#define st st16
|
||||||
|
#define pr_statements pr_statements16
|
||||||
|
#define fakeop fakeop16
|
||||||
|
#define dstatement_t dstatement16_t
|
||||||
|
#define sofs signed short
|
||||||
|
#define uofs unsigned short
|
||||||
|
#elif INTSIZE == 32
|
||||||
|
#define cont cont32
|
||||||
|
#define reeval reeval32
|
||||||
|
#define st st32
|
||||||
|
#define pr_statements pr_statements32
|
||||||
|
#define fakeop fakeop32
|
||||||
|
#define dstatement_t dstatement32_t
|
||||||
|
#define sofs signed int
|
||||||
|
#define uofs unsigned int
|
||||||
|
#elif INTSIZE == 24
|
||||||
|
#error INTSIZE should be set to 32.
|
||||||
|
#else
|
||||||
|
#error Bad cont size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//rely upon just st
|
||||||
|
{
|
||||||
|
#ifdef DEBUGABLE
|
||||||
|
cont: //last statement may have been a breakpoint
|
||||||
|
s = st-pr_statements;
|
||||||
|
s+=1;
|
||||||
|
s=ShowStep(progfuncs, s);
|
||||||
|
st = pr_statements + s;
|
||||||
|
|
||||||
|
reeval:
|
||||||
|
#else
|
||||||
|
st++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (st->op)
|
||||||
|
{
|
||||||
|
case OP_ADD_F:
|
||||||
|
OPC->_float = OPA->_float + OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADD_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_F:
|
||||||
|
OPC->_float = OPA->_float - OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_F:
|
||||||
|
OPC->_float = OPA->_float * OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_MUL_V:
|
||||||
|
OPC->_float = OPA->vector[0]*OPB->vector[0]
|
||||||
|
+ OPA->vector[1]*OPB->vector[1]
|
||||||
|
+ OPA->vector[2]*OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_FV:
|
||||||
|
OPC->vector[0] = OPA->_float * OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->_float * OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->_float * OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_VF:
|
||||||
|
OPC->vector[0] = OPB->_float * OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float * OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float * OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV_F:
|
||||||
|
OPC->_float = OPA->_float / OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIV_VF:
|
||||||
|
OPC->vector[0] = OPB->_float / OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float / OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float / OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND:
|
||||||
|
OPC->_float = (float)((int)OPA->_float & (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR:
|
||||||
|
OPC->_float = (float)((int)OPA->_float | (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_GE:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int >= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LE:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int <= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GT:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int > OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LT:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int < OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_NOT_F:
|
||||||
|
OPC->_float = (float)(!OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_NOT_V:
|
||||||
|
OPC->_float = (float)(!OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
case OP_NOT_S:
|
||||||
|
OPC->_float = (float)(!(OPA->string) || !*(OPA->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NOT_FNC:
|
||||||
|
OPC->_float = (float)(!(OPA->function & ~0xff000000));
|
||||||
|
break;
|
||||||
|
case OP_NOT_ENT:
|
||||||
|
OPC->_float = (float)(PROG_TO_EDICT(OPA->edict) == (edictrun_t *)sv_edicts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EQ_F:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_EQ_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] == OPB->vector[0]) &&
|
||||||
|
(OPA->vector[1] == OPB->vector[1]) &&
|
||||||
|
(OPA->vector[2] == OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_EQ_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = true;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(!strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_EQ_E:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function == OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_NE_F:
|
||||||
|
OPC->_float = (float)(OPA->_float != OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_NE_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] != OPB->vector[0]) ||
|
||||||
|
(OPA->vector[1] != OPB->vector[1]) ||
|
||||||
|
(OPA->vector[2] != OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_NE_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = false;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NE_E:
|
||||||
|
OPC->_float = (float)(OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function != OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
case OP_STORE_IF:
|
||||||
|
OPB->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_FI:
|
||||||
|
OPB->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STORE_I:
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_F:
|
||||||
|
case OP_STORE_ENT:
|
||||||
|
case OP_STORE_FLD: // integers
|
||||||
|
case OP_STORE_S:
|
||||||
|
case OP_STORE_FNC: // pointers
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_V:
|
||||||
|
OPB->vector[0] = OPA->vector[0];
|
||||||
|
OPB->vector[1] = OPA->vector[1];
|
||||||
|
OPB->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//store a value to a pointer
|
||||||
|
case OP_STOREP_IF:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_FI:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_I:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_F:
|
||||||
|
case OP_STOREP_ENT:
|
||||||
|
case OP_STOREP_FLD: // integers
|
||||||
|
case OP_STOREP_S:
|
||||||
|
case OP_STOREP_FNC: // pointers
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_V:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->vector[0] = OPA->vector[0];
|
||||||
|
ptr->vector[1] = OPA->vector[1];
|
||||||
|
ptr->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_STOREP_C: //store character in a string
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
*(unsigned char *)ptr = (char)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULSTORE_F: // f *= f
|
||||||
|
OPB->_float *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTORE_V: // v *= f
|
||||||
|
OPB->vector[0] *= OPA->_float;
|
||||||
|
OPB->vector[1] *= OPA->_float;
|
||||||
|
OPB->vector[2] *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_F: // e.f *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float *= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_V: // e.v *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[1] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[2] *= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIVSTORE_F: // f /= f
|
||||||
|
OPB->_float /= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIVSTOREP_F: // e.f /= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float /= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADDSTORE_F: // f += f
|
||||||
|
OPB->_float += OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADDSTORE_V: // v += v
|
||||||
|
OPB->vector[0] += OPA->vector[0];
|
||||||
|
OPB->vector[1] += OPA->vector[1];
|
||||||
|
OPB->vector[2] += OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_F: // e.f += f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float += OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_V: // e.v += v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUBSTORE_F: // f -= f
|
||||||
|
OPB->_float -= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUBSTORE_V: // v -= v
|
||||||
|
OPB->vector[0] -= OPA->vector[0];
|
||||||
|
OPB->vector[1] -= OPA->vector[1];
|
||||||
|
OPB->vector[2] -= OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_F: // e.f -= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float -= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_V: // e.v -= v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//get a pointer to a field var
|
||||||
|
case OP_ADDRESS:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
if (ed->readonly)
|
||||||
|
PR_RunError (progfuncs, "assignment to read-only entity");
|
||||||
|
OPC->_int = (int)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//load a field to a value
|
||||||
|
case OP_LOAD_I:
|
||||||
|
case OP_LOAD_F:
|
||||||
|
case OP_LOAD_FLD:
|
||||||
|
case OP_LOAD_ENT:
|
||||||
|
case OP_LOAD_S:
|
||||||
|
case OP_LOAD_FNC:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOAD_V:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case OP_IFNOTS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->string || !*OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFNOT:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->string && *OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IF:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GOTO:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->a - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CALL8H:
|
||||||
|
case OP_CALL7H:
|
||||||
|
case OP_CALL6H:
|
||||||
|
case OP_CALL5H:
|
||||||
|
case OP_CALL4H:
|
||||||
|
case OP_CALL3H:
|
||||||
|
case OP_CALL2H:
|
||||||
|
G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
|
||||||
|
case OP_CALL1H:
|
||||||
|
G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
|
||||||
|
|
||||||
|
case OP_CALL8:
|
||||||
|
case OP_CALL7:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL0:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
|
||||||
|
|
||||||
|
if (st->op > OP_CALL8)
|
||||||
|
pr_argc = st->op - (OP_CALL1H-1);
|
||||||
|
else
|
||||||
|
pr_argc = st->op - OP_CALL0;
|
||||||
|
fnum = OPA->function;
|
||||||
|
if ((fnum & ~0xff000000)<=0)
|
||||||
|
{
|
||||||
|
pr_trace++;
|
||||||
|
printf("NULL function from qc.\n");
|
||||||
|
#ifndef DEBUGABLE
|
||||||
|
goto cont;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p=pr_typecurrent;
|
||||||
|
//about to switch. needs caching.
|
||||||
|
|
||||||
|
//if it's an external call, switch now (before any function pointers are used)
|
||||||
|
PR_MoveParms(progfuncs, (fnum & 0xff000000)>>24, p);
|
||||||
|
PR_SwitchProgs(progfuncs, (fnum & 0xff000000)>>24);
|
||||||
|
|
||||||
|
newf = &pr_functions[fnum & ~0xff000000];
|
||||||
|
|
||||||
|
if (newf->first_statement < 0)
|
||||||
|
{ // negative statements are built in functions
|
||||||
|
i = -newf->first_statement;
|
||||||
|
// p = pr_typecurrent;
|
||||||
|
if (i < externs->numglobalbuiltins)
|
||||||
|
{
|
||||||
|
(*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
if (prinst->continuestatement!=-1)
|
||||||
|
{
|
||||||
|
st=&pr_statements[prinst->continuestatement];
|
||||||
|
prinst->continuestatement=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i -= externs->numglobalbuiltins;
|
||||||
|
if (i > current_progstate->numbuiltins)
|
||||||
|
{
|
||||||
|
if (newf->first_statement == -0x7fffffff)
|
||||||
|
((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
else
|
||||||
|
PR_RunError (progfuncs, "Bad builtin call number");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
}
|
||||||
|
PR_MoveParms(progfuncs, p, pr_typecurrent);
|
||||||
|
// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t));
|
||||||
|
PR_SwitchProgs(progfuncs, (progsnum_t)p);
|
||||||
|
|
||||||
|
//#ifndef DEBUGABLE //decide weather non debugger wants to start debugging.
|
||||||
|
s = st-pr_statements;
|
||||||
|
goto restart;
|
||||||
|
//#endif
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// PR_MoveParms((OPA->function & 0xff000000)>>24, pr_typecurrent);
|
||||||
|
// PR_SwitchProgs((OPA->function & 0xff000000)>>24);
|
||||||
|
s = PR_EnterFunction (progfuncs, newf, p);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_DONE:
|
||||||
|
case OP_RETURN:
|
||||||
|
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
|
||||||
|
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||||
|
pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
|
||||||
|
pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
|
||||||
|
|
||||||
|
s = PR_LeaveFunction (progfuncs);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
if (pr_depth == exitdepth)
|
||||||
|
{
|
||||||
|
PR_MoveParms(progfuncs, initial_progs, pr_typecurrent);
|
||||||
|
PR_SwitchProgs(progfuncs, initial_progs);
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_STATE:
|
||||||
|
externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_I:
|
||||||
|
OPC->_int = OPA->_int + OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_FI:
|
||||||
|
OPC->_float = OPA->_float + (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_IF:
|
||||||
|
OPC->_float = (float)OPA->_int + OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_I:
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_FI:
|
||||||
|
OPC->_float = OPA->_float - (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_IF:
|
||||||
|
OPC->_float = (float)OPA->_int - OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_C_ITOF:
|
||||||
|
OPC->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_C_FTOI:
|
||||||
|
OPC->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_ITOF:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_float = (float)ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_FTOI:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_int = (int)ptr->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND_I:
|
||||||
|
OPC->_int = (OPA->_int & OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR_I:
|
||||||
|
OPC->_int = (OPA->_int | OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_I:
|
||||||
|
OPC->_int = OPA->_int * OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_DIV_I:
|
||||||
|
if (OPB->_int == 0) //no division by zero allowed...
|
||||||
|
OPC->_int = 0;
|
||||||
|
else
|
||||||
|
OPC->_int = OPA->_int / OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_EQ_I:
|
||||||
|
OPC->_int = (OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_I:
|
||||||
|
OPC->_int = (OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//array/structure reading/riting.
|
||||||
|
case OP_GLOBALADDRESS:
|
||||||
|
OPC->_int = (int)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
|
||||||
|
OPC->_int = OPA->_int + OPB->_int*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_I:
|
||||||
|
case OP_LOADA_F:
|
||||||
|
case OP_LOADA_FLD:
|
||||||
|
case OP_LOADA_ENT:
|
||||||
|
case OP_LOADA_S:
|
||||||
|
case OP_LOADA_FNC:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_V:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_SF: //(char*)c = (char*)a + (float)b
|
||||||
|
OPC->_int = OPA->_int + (int)OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_S: //(float)c = (char*)a - (char*)b
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_C: //load character from a string
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + (int)OPB->_float);
|
||||||
|
OPC->_float = *(unsigned char *)ptr;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_I:
|
||||||
|
case OP_LOADP_F:
|
||||||
|
case OP_LOADP_FLD:
|
||||||
|
case OP_LOADP_ENT:
|
||||||
|
case OP_LOADP_S:
|
||||||
|
case OP_LOADP_FNC:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADP_V:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int + 2 >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_POWER_I:
|
||||||
|
OPC->_int = OPA->_int ^ OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_RSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int >> OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int << OPB->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_FETCH_GBL_F:
|
||||||
|
case OP_FETCH_GBL_S:
|
||||||
|
case OP_FETCH_GBL_E:
|
||||||
|
case OP_FETCH_GBL_FNC:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a + i];
|
||||||
|
OPC->_int = t->_int;
|
||||||
|
break;
|
||||||
|
case OP_FETCH_GBL_V:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a
|
||||||
|
+((int)OPB->_float)*3];
|
||||||
|
OPC->vector[0] = t->vector[0];
|
||||||
|
OPC->vector[1] = t->vector[1];
|
||||||
|
OPC->vector[2] = t->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CSTATE:
|
||||||
|
externs->cstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CWSTATE:
|
||||||
|
externs->cwstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_THINKTIME:
|
||||||
|
externs->thinktimeop(progfuncs, (struct edict_s *)PROG_TO_EDICT(OPA->edict), OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_BITSET: // b (+) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITSETP: // .b (+) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITCLR: // b (-) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
case OP_BITCLRP: // .b (-) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_RAND0:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RAND1:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff)*OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_RAND2:
|
||||||
|
if(OPA->_float < OPB->_float)
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPA->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->_float-OPA->_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPB->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPA->_float-OPB->_float));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_RANDV0:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RANDV1:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[0];
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[1];
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_RANDV2:
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if(OPA->vector[i] < OPB->vector[i])
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPA->vector[i]+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->vector[i]-OPA->vector[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPB->vector[i]+(rand()*(1.0f/RAND_MAX)
|
||||||
|
*(OPA->vector[i]-OPB->vector[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
swtch = OPA;
|
||||||
|
swtchtype = st->op;
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b - 1; // offset the st++
|
||||||
|
break;
|
||||||
|
case OP_CASE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float == OPA->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
if ((!swtch->_int && progfuncs->stringtable[OPA->string]) || (!OPA->_int && progfuncs->stringtable[swtch->string])) //one is null (cannot be not both).
|
||||||
|
break;
|
||||||
|
if (!strcmp(progfuncs->stringtable+swtch->string, progfuncs->stringtable+OPA->string))
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
if (swtch->vector[0] == OPA->vector[0] && swtch->vector[1] == OPA->vector[1] && swtch->vector[2] == OPA->vector[2])
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_CASERANGE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->c-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (st->op & 0x8000) //break point!
|
||||||
|
{
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
printf("Break point hit.\n");
|
||||||
|
if (pr_trace<1)
|
||||||
|
pr_trace=1; //this is what it's for
|
||||||
|
|
||||||
|
s = ShowStep(progfuncs, s);
|
||||||
|
st = &pr_statements[s]; //let the user move execution
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one.
|
||||||
|
fakeop.op &= ~0x8000;
|
||||||
|
st = &fakeop; //a little remapping...
|
||||||
|
|
||||||
|
goto reeval; //reexecute
|
||||||
|
}
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
PR_RunError (progfuncs, "Bad opcode %i", st->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef cont
|
||||||
|
#undef reeval
|
||||||
|
#undef st
|
||||||
|
#undef pr_statements
|
||||||
|
#undef fakeop
|
||||||
|
#undef dstatement_t
|
||||||
|
#undef sofs
|
||||||
|
#undef uofs
|
912
engine/qclib/execloop16d.h
Normal file
912
engine/qclib/execloop16d.h
Normal file
|
@ -0,0 +1,912 @@
|
||||||
|
//qc execution code.
|
||||||
|
//we have two conditions.
|
||||||
|
//one allows us to debug and trace through our code, the other doesn't.
|
||||||
|
|
||||||
|
//hopefully, the compiler will do a great job at optimising this code for us, where required.
|
||||||
|
//if it dosn't, then bum.
|
||||||
|
|
||||||
|
//the general overhead should be reduced significantly, and I would be supprised if it did run slower.
|
||||||
|
|
||||||
|
//run away loops are checked for ONLY on gotos and function calls. This might give a poorer check, but it will run faster overall.
|
||||||
|
|
||||||
|
//Appears to work fine.
|
||||||
|
|
||||||
|
#if INTSIZE == 16
|
||||||
|
#define cont cont16
|
||||||
|
#define reeval reeval16
|
||||||
|
#define st st16
|
||||||
|
#define pr_statements pr_statements16
|
||||||
|
#define fakeop fakeop16
|
||||||
|
#define dstatement_t dstatement16_t
|
||||||
|
#define sofs signed short
|
||||||
|
#define uofs unsigned short
|
||||||
|
#elif INTSIZE == 32
|
||||||
|
#define cont cont32
|
||||||
|
#define reeval reeval32
|
||||||
|
#define st st32
|
||||||
|
#define pr_statements pr_statements32
|
||||||
|
#define fakeop fakeop32
|
||||||
|
#define dstatement_t dstatement32_t
|
||||||
|
#define sofs signed int
|
||||||
|
#define uofs unsigned int
|
||||||
|
#elif INTSIZE == 24
|
||||||
|
#error INTSIZE should be set to 32.
|
||||||
|
#else
|
||||||
|
#error Bad cont size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//rely upon just st
|
||||||
|
{
|
||||||
|
#ifdef DEBUGABLE
|
||||||
|
cont: //last statement may have been a breakpoint
|
||||||
|
s = st-pr_statements;
|
||||||
|
s+=1;
|
||||||
|
s=ShowStep(progfuncs, s);
|
||||||
|
st = pr_statements + s;
|
||||||
|
|
||||||
|
reeval:
|
||||||
|
#else
|
||||||
|
st++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (st->op)
|
||||||
|
{
|
||||||
|
case OP_ADD_F:
|
||||||
|
OPC->_float = OPA->_float + OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADD_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_F:
|
||||||
|
OPC->_float = OPA->_float - OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_F:
|
||||||
|
OPC->_float = OPA->_float * OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_MUL_V:
|
||||||
|
OPC->_float = OPA->vector[0]*OPB->vector[0]
|
||||||
|
+ OPA->vector[1]*OPB->vector[1]
|
||||||
|
+ OPA->vector[2]*OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_FV:
|
||||||
|
OPC->vector[0] = OPA->_float * OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->_float * OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->_float * OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_VF:
|
||||||
|
OPC->vector[0] = OPB->_float * OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float * OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float * OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV_F:
|
||||||
|
OPC->_float = OPA->_float / OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIV_VF:
|
||||||
|
OPC->vector[0] = OPB->_float / OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float / OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float / OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND:
|
||||||
|
OPC->_float = (float)((int)OPA->_float & (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR:
|
||||||
|
OPC->_float = (float)((int)OPA->_float | (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_GE:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int >= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LE:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int <= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GT:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int > OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LT:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int < OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_NOT_F:
|
||||||
|
OPC->_float = (float)(!OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_NOT_V:
|
||||||
|
OPC->_float = (float)(!OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
case OP_NOT_S:
|
||||||
|
OPC->_float = (float)(!(OPA->string) || !*(OPA->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NOT_FNC:
|
||||||
|
OPC->_float = (float)(!(OPA->function & ~0xff000000));
|
||||||
|
break;
|
||||||
|
case OP_NOT_ENT:
|
||||||
|
OPC->_float = (float)(PROG_TO_EDICT(OPA->edict) == (edictrun_t *)sv_edicts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EQ_F:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_EQ_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] == OPB->vector[0]) &&
|
||||||
|
(OPA->vector[1] == OPB->vector[1]) &&
|
||||||
|
(OPA->vector[2] == OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_EQ_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = true;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(!strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_EQ_E:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function == OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_NE_F:
|
||||||
|
OPC->_float = (float)(OPA->_float != OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_NE_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] != OPB->vector[0]) ||
|
||||||
|
(OPA->vector[1] != OPB->vector[1]) ||
|
||||||
|
(OPA->vector[2] != OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_NE_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = false;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NE_E:
|
||||||
|
OPC->_float = (float)(OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function != OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
case OP_STORE_IF:
|
||||||
|
OPB->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_FI:
|
||||||
|
OPB->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STORE_I:
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_F:
|
||||||
|
case OP_STORE_ENT:
|
||||||
|
case OP_STORE_FLD: // integers
|
||||||
|
case OP_STORE_S:
|
||||||
|
case OP_STORE_FNC: // pointers
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_V:
|
||||||
|
OPB->vector[0] = OPA->vector[0];
|
||||||
|
OPB->vector[1] = OPA->vector[1];
|
||||||
|
OPB->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//store a value to a pointer
|
||||||
|
case OP_STOREP_IF:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_FI:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_I:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_F:
|
||||||
|
case OP_STOREP_ENT:
|
||||||
|
case OP_STOREP_FLD: // integers
|
||||||
|
case OP_STOREP_S:
|
||||||
|
case OP_STOREP_FNC: // pointers
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_V:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->vector[0] = OPA->vector[0];
|
||||||
|
ptr->vector[1] = OPA->vector[1];
|
||||||
|
ptr->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_STOREP_C: //store character in a string
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
*(unsigned char *)ptr = (char)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULSTORE_F: // f *= f
|
||||||
|
OPB->_float *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTORE_V: // v *= f
|
||||||
|
OPB->vector[0] *= OPA->_float;
|
||||||
|
OPB->vector[1] *= OPA->_float;
|
||||||
|
OPB->vector[2] *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_F: // e.f *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float *= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_V: // e.v *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[1] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[2] *= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIVSTORE_F: // f /= f
|
||||||
|
OPB->_float /= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIVSTOREP_F: // e.f /= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float /= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADDSTORE_F: // f += f
|
||||||
|
OPB->_float += OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADDSTORE_V: // v += v
|
||||||
|
OPB->vector[0] += OPA->vector[0];
|
||||||
|
OPB->vector[1] += OPA->vector[1];
|
||||||
|
OPB->vector[2] += OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_F: // e.f += f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float += OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_V: // e.v += v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUBSTORE_F: // f -= f
|
||||||
|
OPB->_float -= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUBSTORE_V: // v -= v
|
||||||
|
OPB->vector[0] -= OPA->vector[0];
|
||||||
|
OPB->vector[1] -= OPA->vector[1];
|
||||||
|
OPB->vector[2] -= OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_F: // e.f -= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float -= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_V: // e.v -= v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//get a pointer to a field var
|
||||||
|
case OP_ADDRESS:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
if (ed->readonly)
|
||||||
|
PR_RunError (progfuncs, "assignment to world entity");
|
||||||
|
OPC->_int = (int)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//load a field to a value
|
||||||
|
case OP_LOAD_I:
|
||||||
|
case OP_LOAD_F:
|
||||||
|
case OP_LOAD_FLD:
|
||||||
|
case OP_LOAD_ENT:
|
||||||
|
case OP_LOAD_S:
|
||||||
|
case OP_LOAD_FNC:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOAD_V:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case OP_IFNOTS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->string || !*OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFNOT:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->string && *OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IF:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GOTO:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->a - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CALL8H:
|
||||||
|
case OP_CALL7H:
|
||||||
|
case OP_CALL6H:
|
||||||
|
case OP_CALL5H:
|
||||||
|
case OP_CALL4H:
|
||||||
|
case OP_CALL3H:
|
||||||
|
case OP_CALL2H:
|
||||||
|
G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
|
||||||
|
case OP_CALL1H:
|
||||||
|
G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
|
||||||
|
|
||||||
|
case OP_CALL8:
|
||||||
|
case OP_CALL7:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL0:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
|
||||||
|
|
||||||
|
if (st->op > OP_CALL8)
|
||||||
|
pr_argc = st->op - (OP_CALL1H-1);
|
||||||
|
else
|
||||||
|
pr_argc = st->op - OP_CALL0;
|
||||||
|
fnum = OPA->function;
|
||||||
|
if ((fnum & ~0xff000000)<=0)
|
||||||
|
{
|
||||||
|
pr_trace++;
|
||||||
|
printf("NULL function from qc.\n");
|
||||||
|
#ifndef DEBUGABLE
|
||||||
|
goto cont;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p=pr_typecurrent;
|
||||||
|
//about to switch. needs caching.
|
||||||
|
|
||||||
|
//if it's an external call, switch now (before any function pointers are used)
|
||||||
|
PR_MoveParms(progfuncs, (fnum & 0xff000000)>>24, p);
|
||||||
|
PR_SwitchProgs(progfuncs, (fnum & 0xff000000)>>24);
|
||||||
|
|
||||||
|
newf = &pr_functions[fnum & ~0xff000000];
|
||||||
|
|
||||||
|
if (newf->first_statement < 0)
|
||||||
|
{ // negative statements are built in functions
|
||||||
|
i = -newf->first_statement;
|
||||||
|
// p = pr_typecurrent;
|
||||||
|
if (i < externs->numglobalbuiltins)
|
||||||
|
{
|
||||||
|
(*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
if (prinst->continuestatement!=-1)
|
||||||
|
{
|
||||||
|
st=&pr_statements[prinst->continuestatement];
|
||||||
|
prinst->continuestatement=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i -= externs->numglobalbuiltins;
|
||||||
|
if (i > current_progstate->numbuiltins)
|
||||||
|
{
|
||||||
|
if (newf->first_statement == -0x7fffffff)
|
||||||
|
((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
else
|
||||||
|
PR_RunError (progfuncs, "Bad builtin call number");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
}
|
||||||
|
PR_MoveParms(progfuncs, p, pr_typecurrent);
|
||||||
|
// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t));
|
||||||
|
PR_SwitchProgs(progfuncs, (progsnum_t)p);
|
||||||
|
|
||||||
|
//#ifndef DEBUGABLE //decide weather non debugger wants to start debugging.
|
||||||
|
s = st-pr_statements;
|
||||||
|
goto restart;
|
||||||
|
//#endif
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// PR_MoveParms((OPA->function & 0xff000000)>>24, pr_typecurrent);
|
||||||
|
// PR_SwitchProgs((OPA->function & 0xff000000)>>24);
|
||||||
|
s = PR_EnterFunction (progfuncs, newf, p);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_DONE:
|
||||||
|
case OP_RETURN:
|
||||||
|
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
|
||||||
|
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||||
|
pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
|
||||||
|
pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
|
||||||
|
|
||||||
|
s = PR_LeaveFunction (progfuncs);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
if (pr_depth == prinst->exitdepth)
|
||||||
|
{
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_STATE:
|
||||||
|
externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_I:
|
||||||
|
OPC->_int = OPA->_int + OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_FI:
|
||||||
|
OPC->_float = OPA->_float + (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_IF:
|
||||||
|
OPC->_float = (float)OPA->_int + OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_I:
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_FI:
|
||||||
|
OPC->_float = OPA->_float - (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_IF:
|
||||||
|
OPC->_float = (float)OPA->_int - OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CONV_ITOF:
|
||||||
|
OPC->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_CONV_FTOI:
|
||||||
|
OPC->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_ITOF:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_float = (float)ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_FTOI:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_int = (int)ptr->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND_I:
|
||||||
|
OPC->_int = (OPA->_int & OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR_I:
|
||||||
|
OPC->_int = (OPA->_int | OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_I:
|
||||||
|
OPC->_int = OPA->_int * OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_DIV_I:
|
||||||
|
if (OPB->_int == 0) //no division by zero allowed...
|
||||||
|
OPC->_int = 0;
|
||||||
|
else
|
||||||
|
OPC->_int = OPA->_int / OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_EQ_I:
|
||||||
|
OPC->_int = (OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_I:
|
||||||
|
OPC->_int = (OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//array/structure reading/riting.
|
||||||
|
case OP_GLOBALADDRESS:
|
||||||
|
OPC->_int = (int)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
|
||||||
|
OPC->_int = OPA->_int + OPB->_int*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_I:
|
||||||
|
case OP_LOADA_F:
|
||||||
|
case OP_LOADA_FLD:
|
||||||
|
case OP_LOADA_ENT:
|
||||||
|
case OP_LOADA_S:
|
||||||
|
case OP_LOADA_FNC:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_V:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_SF: //(char*)c = (char*)a + (float)b
|
||||||
|
OPC->_int = OPA->_int + (int)OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_S: //(float)c = (char*)a - (char*)b
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_C: //load character from a string
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + (int)OPB->_float);
|
||||||
|
OPC->_float = *(unsigned char *)ptr;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_I:
|
||||||
|
case OP_LOADP_F:
|
||||||
|
case OP_LOADP_FLD:
|
||||||
|
case OP_LOADP_ENT:
|
||||||
|
case OP_LOADP_S:
|
||||||
|
case OP_LOADP_FNC:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADP_V:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int + 2 >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_POWER_I:
|
||||||
|
OPC->_int = OPA->_int ^ OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_RSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int >> OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int << OPB->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_FETCH_GBL_F:
|
||||||
|
case OP_FETCH_GBL_S:
|
||||||
|
case OP_FETCH_GBL_E:
|
||||||
|
case OP_FETCH_GBL_FNC:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a + i];
|
||||||
|
OPC->_int = t->_int;
|
||||||
|
break;
|
||||||
|
case OP_FETCH_GBL_V:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a
|
||||||
|
+((int)OPB->_float)*3];
|
||||||
|
OPC->vector[0] = t->vector[0];
|
||||||
|
OPC->vector[1] = t->vector[1];
|
||||||
|
OPC->vector[2] = t->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CSTATE:
|
||||||
|
externs->cstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CWSTATE:
|
||||||
|
externs->cwstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_THINKTIME:
|
||||||
|
externs->thinktimeop(progfuncs, (struct edict_s *)PROG_TO_EDICT(OPA->edict), OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_BITSET: // b (+) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITSETP: // .b (+) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITCLR: // b (-) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
case OP_BITCLRP: // .b (-) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_RAND0:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RAND1:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff)*OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_RAND2:
|
||||||
|
if(OPA->_float < OPB->_float)
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPA->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->_float-OPA->_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPB->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPA->_float-OPB->_float));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_RANDV0:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RANDV1:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[0];
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[1];
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_RANDV2:
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if(OPA->vector[i] < OPB->vector[i])
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPA->vector[i]+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->vector[i]-OPA->vector[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPB->vector[i]+(rand()*(1.0f/RAND_MAX)
|
||||||
|
*(OPA->vector[i]-OPB->vector[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
swtch = OPA;
|
||||||
|
swtchtype = st->op;
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b - 1; // offset the st++
|
||||||
|
break;
|
||||||
|
case OP_CASE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float == OPA->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
if ((!swtch->_int && progfuncs->stringtable[OPA->string]) || (!OPA->_int && progfuncs->stringtable[swtch->string])) //one is null (cannot be not both).
|
||||||
|
break;
|
||||||
|
if (!strcmp(progfuncs->stringtable+swtch->string, progfuncs->stringtable+OPA->string))
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
if (swtch->vector[0] == OPA->vector[0] && swtch->vector[1] == OPA->vector[1] && swtch->vector[2] == OPA->vector[2])
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_CASERANGE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->c-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (st->op & 0x8000) //break point!
|
||||||
|
{
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
printf("Break point hit.\n");
|
||||||
|
if (pr_trace<1)
|
||||||
|
pr_trace=1; //this is what it's for
|
||||||
|
|
||||||
|
s = ShowStep(progfuncs, s);
|
||||||
|
st = &pr_statements[s]; //let the user move execution
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one.
|
||||||
|
fakeop.op &= ~0x8000;
|
||||||
|
st = &fakeop; //a little remapping...
|
||||||
|
|
||||||
|
goto reeval; //reexecute
|
||||||
|
}
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
PR_RunError (progfuncs, "Bad opcode %i", st->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef cont
|
||||||
|
#undef reeval
|
||||||
|
#undef st
|
||||||
|
#undef pr_statements
|
||||||
|
#undef fakeop
|
||||||
|
#undef dstatement_t
|
||||||
|
#undef sofs
|
||||||
|
#undef uofs
|
912
engine/qclib/execloop32.h
Normal file
912
engine/qclib/execloop32.h
Normal file
|
@ -0,0 +1,912 @@
|
||||||
|
//qc execution code.
|
||||||
|
//we have two conditions.
|
||||||
|
//one allows us to debug and trace through our code, the other doesn't.
|
||||||
|
|
||||||
|
//hopefully, the compiler will do a great job at optimising this code for us, where required.
|
||||||
|
//if it dosn't, then bum.
|
||||||
|
|
||||||
|
//the general overhead should be reduced significantly, and I would be supprised if it did run slower.
|
||||||
|
|
||||||
|
//run away loops are checked for ONLY on gotos and function calls. This might give a poorer check, but it will run faster overall.
|
||||||
|
|
||||||
|
//Appears to work fine.
|
||||||
|
|
||||||
|
#if INTSIZE == 16
|
||||||
|
#define cont cont16
|
||||||
|
#define reeval reeval16
|
||||||
|
#define st st16
|
||||||
|
#define pr_statements pr_statements16
|
||||||
|
#define fakeop fakeop16
|
||||||
|
#define dstatement_t dstatement16_t
|
||||||
|
#define sofs signed short
|
||||||
|
#define uofs unsigned short
|
||||||
|
#elif INTSIZE == 32
|
||||||
|
#define cont cont32
|
||||||
|
#define reeval reeval32
|
||||||
|
#define st st32
|
||||||
|
#define pr_statements pr_statements32
|
||||||
|
#define fakeop fakeop32
|
||||||
|
#define dstatement_t dstatement32_t
|
||||||
|
#define sofs signed int
|
||||||
|
#define uofs unsigned int
|
||||||
|
#elif INTSIZE == 24
|
||||||
|
#error INTSIZE should be set to 32.
|
||||||
|
#else
|
||||||
|
#error Bad cont size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//rely upon just st
|
||||||
|
{
|
||||||
|
#ifdef DEBUGABLE
|
||||||
|
cont: //last statement may have been a breakpoint
|
||||||
|
s = st-pr_statements;
|
||||||
|
s+=1;
|
||||||
|
s=ShowStep(progfuncs, s);
|
||||||
|
st = pr_statements + s;
|
||||||
|
|
||||||
|
reeval:
|
||||||
|
#else
|
||||||
|
st++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (st->op)
|
||||||
|
{
|
||||||
|
case OP_ADD_F:
|
||||||
|
OPC->_float = OPA->_float + OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADD_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_F:
|
||||||
|
OPC->_float = OPA->_float - OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_F:
|
||||||
|
OPC->_float = OPA->_float * OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_MUL_V:
|
||||||
|
OPC->_float = OPA->vector[0]*OPB->vector[0]
|
||||||
|
+ OPA->vector[1]*OPB->vector[1]
|
||||||
|
+ OPA->vector[2]*OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_FV:
|
||||||
|
OPC->vector[0] = OPA->_float * OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->_float * OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->_float * OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_VF:
|
||||||
|
OPC->vector[0] = OPB->_float * OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float * OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float * OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV_F:
|
||||||
|
OPC->_float = OPA->_float / OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIV_VF:
|
||||||
|
OPC->vector[0] = OPB->_float / OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float / OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float / OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND:
|
||||||
|
OPC->_float = (float)((int)OPA->_float & (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR:
|
||||||
|
OPC->_float = (float)((int)OPA->_float | (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_GE:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int >= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LE:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int <= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GT:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int > OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LT:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int < OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_NOT_F:
|
||||||
|
OPC->_float = (float)(!OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_NOT_V:
|
||||||
|
OPC->_float = (float)(!OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
case OP_NOT_S:
|
||||||
|
OPC->_float = (float)(!(OPA->string) || !*(OPA->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NOT_FNC:
|
||||||
|
OPC->_float = (float)(!(OPA->function & ~0xff000000));
|
||||||
|
break;
|
||||||
|
case OP_NOT_ENT:
|
||||||
|
OPC->_float = (float)(PROG_TO_EDICT(OPA->edict) == (edictrun_t *)sv_edicts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EQ_F:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_EQ_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] == OPB->vector[0]) &&
|
||||||
|
(OPA->vector[1] == OPB->vector[1]) &&
|
||||||
|
(OPA->vector[2] == OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_EQ_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = true;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(!strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_EQ_E:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function == OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_NE_F:
|
||||||
|
OPC->_float = (float)(OPA->_float != OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_NE_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] != OPB->vector[0]) ||
|
||||||
|
(OPA->vector[1] != OPB->vector[1]) ||
|
||||||
|
(OPA->vector[2] != OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_NE_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = false;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NE_E:
|
||||||
|
OPC->_float = (float)(OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function != OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
case OP_STORE_IF:
|
||||||
|
OPB->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_FI:
|
||||||
|
OPB->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STORE_I:
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_F:
|
||||||
|
case OP_STORE_ENT:
|
||||||
|
case OP_STORE_FLD: // integers
|
||||||
|
case OP_STORE_S:
|
||||||
|
case OP_STORE_FNC: // pointers
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_V:
|
||||||
|
OPB->vector[0] = OPA->vector[0];
|
||||||
|
OPB->vector[1] = OPA->vector[1];
|
||||||
|
OPB->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//store a value to a pointer
|
||||||
|
case OP_STOREP_IF:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_FI:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_I:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_F:
|
||||||
|
case OP_STOREP_ENT:
|
||||||
|
case OP_STOREP_FLD: // integers
|
||||||
|
case OP_STOREP_S:
|
||||||
|
case OP_STOREP_FNC: // pointers
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_V:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->vector[0] = OPA->vector[0];
|
||||||
|
ptr->vector[1] = OPA->vector[1];
|
||||||
|
ptr->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_STOREP_C: //store character in a string
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
*(unsigned char *)ptr = (char)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULSTORE_F: // f *= f
|
||||||
|
OPB->_float *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTORE_V: // v *= f
|
||||||
|
OPB->vector[0] *= OPA->_float;
|
||||||
|
OPB->vector[1] *= OPA->_float;
|
||||||
|
OPB->vector[2] *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_F: // e.f *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float *= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_V: // e.v *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[1] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[2] *= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIVSTORE_F: // f /= f
|
||||||
|
OPB->_float /= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIVSTOREP_F: // e.f /= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float /= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADDSTORE_F: // f += f
|
||||||
|
OPB->_float += OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADDSTORE_V: // v += v
|
||||||
|
OPB->vector[0] += OPA->vector[0];
|
||||||
|
OPB->vector[1] += OPA->vector[1];
|
||||||
|
OPB->vector[2] += OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_F: // e.f += f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float += OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_V: // e.v += v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUBSTORE_F: // f -= f
|
||||||
|
OPB->_float -= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUBSTORE_V: // v -= v
|
||||||
|
OPB->vector[0] -= OPA->vector[0];
|
||||||
|
OPB->vector[1] -= OPA->vector[1];
|
||||||
|
OPB->vector[2] -= OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_F: // e.f -= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float -= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_V: // e.v -= v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//get a pointer to a field var
|
||||||
|
case OP_ADDRESS:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
if (ed->readonly)
|
||||||
|
PR_RunError (progfuncs, "assignment to world entity");
|
||||||
|
OPC->_int = (int)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//load a field to a value
|
||||||
|
case OP_LOAD_I:
|
||||||
|
case OP_LOAD_F:
|
||||||
|
case OP_LOAD_FLD:
|
||||||
|
case OP_LOAD_ENT:
|
||||||
|
case OP_LOAD_S:
|
||||||
|
case OP_LOAD_FNC:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOAD_V:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case OP_IFNOTS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->string || !*OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFNOT:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->string && *OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IF:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GOTO:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->a - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CALL8H:
|
||||||
|
case OP_CALL7H:
|
||||||
|
case OP_CALL6H:
|
||||||
|
case OP_CALL5H:
|
||||||
|
case OP_CALL4H:
|
||||||
|
case OP_CALL3H:
|
||||||
|
case OP_CALL2H:
|
||||||
|
G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
|
||||||
|
case OP_CALL1H:
|
||||||
|
G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
|
||||||
|
|
||||||
|
case OP_CALL8:
|
||||||
|
case OP_CALL7:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL0:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
|
||||||
|
|
||||||
|
if (st->op > OP_CALL8)
|
||||||
|
pr_argc = st->op - (OP_CALL1H-1);
|
||||||
|
else
|
||||||
|
pr_argc = st->op - OP_CALL0;
|
||||||
|
fnum = OPA->function;
|
||||||
|
if ((fnum & ~0xff000000)<=0)
|
||||||
|
{
|
||||||
|
pr_trace++;
|
||||||
|
printf("NULL function from qc.\n");
|
||||||
|
#ifndef DEBUGABLE
|
||||||
|
goto cont;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p=pr_typecurrent;
|
||||||
|
//about to switch. needs caching.
|
||||||
|
|
||||||
|
//if it's an external call, switch now (before any function pointers are used)
|
||||||
|
PR_MoveParms(progfuncs, (fnum & 0xff000000)>>24, p);
|
||||||
|
PR_SwitchProgs(progfuncs, (fnum & 0xff000000)>>24);
|
||||||
|
|
||||||
|
newf = &pr_functions[fnum & ~0xff000000];
|
||||||
|
|
||||||
|
if (newf->first_statement < 0)
|
||||||
|
{ // negative statements are built in functions
|
||||||
|
i = -newf->first_statement;
|
||||||
|
// p = pr_typecurrent;
|
||||||
|
if (i < externs->numglobalbuiltins)
|
||||||
|
{
|
||||||
|
(*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
if (prinst->continuestatement!=-1)
|
||||||
|
{
|
||||||
|
st=&pr_statements[prinst->continuestatement];
|
||||||
|
prinst->continuestatement=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i -= externs->numglobalbuiltins;
|
||||||
|
if (i > current_progstate->numbuiltins)
|
||||||
|
{
|
||||||
|
if (newf->first_statement == -0x7fffffff)
|
||||||
|
((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
else
|
||||||
|
PR_RunError (progfuncs, "Bad builtin call number");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
}
|
||||||
|
PR_MoveParms(progfuncs, p, pr_typecurrent);
|
||||||
|
// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t));
|
||||||
|
PR_SwitchProgs(progfuncs, (progsnum_t)p);
|
||||||
|
|
||||||
|
//#ifndef DEBUGABLE //decide weather non debugger wants to start debugging.
|
||||||
|
s = st-pr_statements;
|
||||||
|
goto restart;
|
||||||
|
//#endif
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// PR_MoveParms((OPA->function & 0xff000000)>>24, pr_typecurrent);
|
||||||
|
// PR_SwitchProgs((OPA->function & 0xff000000)>>24);
|
||||||
|
s = PR_EnterFunction (progfuncs, newf, p);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_DONE:
|
||||||
|
case OP_RETURN:
|
||||||
|
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
|
||||||
|
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||||
|
pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
|
||||||
|
pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
|
||||||
|
|
||||||
|
s = PR_LeaveFunction (progfuncs);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
if (pr_depth == prinst->exitdepth)
|
||||||
|
{
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_STATE:
|
||||||
|
externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_I:
|
||||||
|
OPC->_int = OPA->_int + OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_FI:
|
||||||
|
OPC->_float = OPA->_float + (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_IF:
|
||||||
|
OPC->_float = (float)OPA->_int + OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_I:
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_FI:
|
||||||
|
OPC->_float = OPA->_float - (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_IF:
|
||||||
|
OPC->_float = (float)OPA->_int - OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CONV_ITOF:
|
||||||
|
OPC->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_CONV_FTOI:
|
||||||
|
OPC->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_ITOF:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_float = (float)ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_FTOI:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_int = (int)ptr->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND_I:
|
||||||
|
OPC->_int = (OPA->_int & OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR_I:
|
||||||
|
OPC->_int = (OPA->_int | OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_I:
|
||||||
|
OPC->_int = OPA->_int * OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_DIV_I:
|
||||||
|
if (OPB->_int == 0) //no division by zero allowed...
|
||||||
|
OPC->_int = 0;
|
||||||
|
else
|
||||||
|
OPC->_int = OPA->_int / OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_EQ_I:
|
||||||
|
OPC->_int = (OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_I:
|
||||||
|
OPC->_int = (OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//array/structure reading/riting.
|
||||||
|
case OP_GLOBALADDRESS:
|
||||||
|
OPC->_int = (int)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
|
||||||
|
OPC->_int = OPA->_int + OPB->_int*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_I:
|
||||||
|
case OP_LOADA_F:
|
||||||
|
case OP_LOADA_FLD:
|
||||||
|
case OP_LOADA_ENT:
|
||||||
|
case OP_LOADA_S:
|
||||||
|
case OP_LOADA_FNC:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_V:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_SF: //(char*)c = (char*)a + (float)b
|
||||||
|
OPC->_int = OPA->_int + (int)OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_S: //(float)c = (char*)a - (char*)b
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_C: //load character from a string
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + (int)OPB->_float);
|
||||||
|
OPC->_float = *(unsigned char *)ptr;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_I:
|
||||||
|
case OP_LOADP_F:
|
||||||
|
case OP_LOADP_FLD:
|
||||||
|
case OP_LOADP_ENT:
|
||||||
|
case OP_LOADP_S:
|
||||||
|
case OP_LOADP_FNC:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADP_V:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int + 2 >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_POWER_I:
|
||||||
|
OPC->_int = OPA->_int ^ OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_RSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int >> OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int << OPB->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_FETCH_GBL_F:
|
||||||
|
case OP_FETCH_GBL_S:
|
||||||
|
case OP_FETCH_GBL_E:
|
||||||
|
case OP_FETCH_GBL_FNC:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a + i];
|
||||||
|
OPC->_int = t->_int;
|
||||||
|
break;
|
||||||
|
case OP_FETCH_GBL_V:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a
|
||||||
|
+((int)OPB->_float)*3];
|
||||||
|
OPC->vector[0] = t->vector[0];
|
||||||
|
OPC->vector[1] = t->vector[1];
|
||||||
|
OPC->vector[2] = t->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CSTATE:
|
||||||
|
externs->cstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CWSTATE:
|
||||||
|
externs->cwstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_THINKTIME:
|
||||||
|
externs->thinktimeop(progfuncs, (struct edict_s *)PROG_TO_EDICT(OPA->edict), OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_BITSET: // b (+) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITSETP: // .b (+) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITCLR: // b (-) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
case OP_BITCLRP: // .b (-) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_RAND0:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RAND1:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff)*OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_RAND2:
|
||||||
|
if(OPA->_float < OPB->_float)
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPA->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->_float-OPA->_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPB->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPA->_float-OPB->_float));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_RANDV0:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RANDV1:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[0];
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[1];
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_RANDV2:
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if(OPA->vector[i] < OPB->vector[i])
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPA->vector[i]+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->vector[i]-OPA->vector[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPB->vector[i]+(rand()*(1.0f/RAND_MAX)
|
||||||
|
*(OPA->vector[i]-OPB->vector[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
swtch = OPA;
|
||||||
|
swtchtype = st->op;
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b - 1; // offset the st++
|
||||||
|
break;
|
||||||
|
case OP_CASE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float == OPA->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
if ((!swtch->_int && progfuncs->stringtable[OPA->string]) || (!OPA->_int && progfuncs->stringtable[swtch->string])) //one is null (cannot be not both).
|
||||||
|
break;
|
||||||
|
if (!strcmp(progfuncs->stringtable+swtch->string, progfuncs->stringtable+OPA->string))
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
if (swtch->vector[0] == OPA->vector[0] && swtch->vector[1] == OPA->vector[1] && swtch->vector[2] == OPA->vector[2])
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_CASERANGE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->c-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (st->op & 0x8000) //break point!
|
||||||
|
{
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
printf("Break point hit.\n");
|
||||||
|
if (pr_trace<1)
|
||||||
|
pr_trace=1; //this is what it's for
|
||||||
|
|
||||||
|
s = ShowStep(progfuncs, s);
|
||||||
|
st = &pr_statements[s]; //let the user move execution
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one.
|
||||||
|
fakeop.op &= ~0x8000;
|
||||||
|
st = &fakeop; //a little remapping...
|
||||||
|
|
||||||
|
goto reeval; //reexecute
|
||||||
|
}
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
PR_RunError (progfuncs, "Bad opcode %i", st->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef cont
|
||||||
|
#undef reeval
|
||||||
|
#undef st
|
||||||
|
#undef pr_statements
|
||||||
|
#undef fakeop
|
||||||
|
#undef dstatement_t
|
||||||
|
#undef sofs
|
||||||
|
#undef uofs
|
912
engine/qclib/execloop32d.h
Normal file
912
engine/qclib/execloop32d.h
Normal file
|
@ -0,0 +1,912 @@
|
||||||
|
//qc execution code.
|
||||||
|
//we have two conditions.
|
||||||
|
//one allows us to debug and trace through our code, the other doesn't.
|
||||||
|
|
||||||
|
//hopefully, the compiler will do a great job at optimising this code for us, where required.
|
||||||
|
//if it dosn't, then bum.
|
||||||
|
|
||||||
|
//the general overhead should be reduced significantly, and I would be supprised if it did run slower.
|
||||||
|
|
||||||
|
//run away loops are checked for ONLY on gotos and function calls. This might give a poorer check, but it will run faster overall.
|
||||||
|
|
||||||
|
//Appears to work fine.
|
||||||
|
|
||||||
|
#if INTSIZE == 16
|
||||||
|
#define cont cont16
|
||||||
|
#define reeval reeval16
|
||||||
|
#define st st16
|
||||||
|
#define pr_statements pr_statements16
|
||||||
|
#define fakeop fakeop16
|
||||||
|
#define dstatement_t dstatement16_t
|
||||||
|
#define sofs signed short
|
||||||
|
#define uofs unsigned short
|
||||||
|
#elif INTSIZE == 32
|
||||||
|
#define cont cont32
|
||||||
|
#define reeval reeval32
|
||||||
|
#define st st32
|
||||||
|
#define pr_statements pr_statements32
|
||||||
|
#define fakeop fakeop32
|
||||||
|
#define dstatement_t dstatement32_t
|
||||||
|
#define sofs signed int
|
||||||
|
#define uofs unsigned int
|
||||||
|
#elif INTSIZE == 24
|
||||||
|
#error INTSIZE should be set to 32.
|
||||||
|
#else
|
||||||
|
#error Bad cont size
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//rely upon just st
|
||||||
|
{
|
||||||
|
#ifdef DEBUGABLE
|
||||||
|
cont: //last statement may have been a breakpoint
|
||||||
|
s = st-pr_statements;
|
||||||
|
s+=1;
|
||||||
|
s=ShowStep(progfuncs, s);
|
||||||
|
st = pr_statements + s;
|
||||||
|
|
||||||
|
reeval:
|
||||||
|
#else
|
||||||
|
st++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (st->op)
|
||||||
|
{
|
||||||
|
case OP_ADD_F:
|
||||||
|
OPC->_float = OPA->_float + OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADD_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] + OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] + OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] + OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_F:
|
||||||
|
OPC->_float = OPA->_float - OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_V:
|
||||||
|
OPC->vector[0] = OPA->vector[0] - OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->vector[1] - OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->vector[2] - OPB->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_F:
|
||||||
|
OPC->_float = OPA->_float * OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_MUL_V:
|
||||||
|
OPC->_float = OPA->vector[0]*OPB->vector[0]
|
||||||
|
+ OPA->vector[1]*OPB->vector[1]
|
||||||
|
+ OPA->vector[2]*OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_FV:
|
||||||
|
OPC->vector[0] = OPA->_float * OPB->vector[0];
|
||||||
|
OPC->vector[1] = OPA->_float * OPB->vector[1];
|
||||||
|
OPC->vector[2] = OPA->_float * OPB->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_MUL_VF:
|
||||||
|
OPC->vector[0] = OPB->_float * OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float * OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float * OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIV_F:
|
||||||
|
OPC->_float = OPA->_float / OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIV_VF:
|
||||||
|
OPC->vector[0] = OPB->_float / OPA->vector[0];
|
||||||
|
OPC->vector[1] = OPB->_float / OPA->vector[1];
|
||||||
|
OPC->vector[2] = OPB->_float / OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND:
|
||||||
|
OPC->_float = (float)((int)OPA->_float & (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR:
|
||||||
|
OPC->_float = (float)((int)OPA->_float | (int)OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_GE:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int >= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int >= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float >= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LE:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_I:
|
||||||
|
OPC->_int = (int)(OPA->_int <= OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LE_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int <= OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LE_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float <= OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GT:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int > OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_GT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int > OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_GT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float > OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LT:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_I:
|
||||||
|
OPC->_int = (int)(OPA->_int < OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_LT_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int < OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_LT_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float < OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_AND:
|
||||||
|
OPC->_float = (float)(OPA->_float && OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_OR:
|
||||||
|
OPC->_float = (float)(OPA->_float || OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_NOT_F:
|
||||||
|
OPC->_float = (float)(!OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_NOT_V:
|
||||||
|
OPC->_float = (float)(!OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
case OP_NOT_S:
|
||||||
|
OPC->_float = (float)(!(OPA->string) || !*(OPA->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NOT_FNC:
|
||||||
|
OPC->_float = (float)(!(OPA->function & ~0xff000000));
|
||||||
|
break;
|
||||||
|
case OP_NOT_ENT:
|
||||||
|
OPC->_float = (float)(PROG_TO_EDICT(OPA->edict) == (edictrun_t *)sv_edicts);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_EQ_F:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_IF:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FI:
|
||||||
|
OPC->_float = (float)(OPA->_float == OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_EQ_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] == OPB->vector[0]) &&
|
||||||
|
(OPA->vector[1] == OPB->vector[1]) &&
|
||||||
|
(OPA->vector[2] == OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_EQ_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = true;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = true;
|
||||||
|
else
|
||||||
|
OPC->_float = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(!strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_EQ_E:
|
||||||
|
OPC->_float = (float)(OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_EQ_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function == OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_NE_F:
|
||||||
|
OPC->_float = (float)(OPA->_float != OPB->_float);
|
||||||
|
break;
|
||||||
|
case OP_NE_V:
|
||||||
|
OPC->_float = (float)((OPA->vector[0] != OPB->vector[0]) ||
|
||||||
|
(OPA->vector[1] != OPB->vector[1]) ||
|
||||||
|
(OPA->vector[2] != OPB->vector[2]));
|
||||||
|
break;
|
||||||
|
case OP_NE_S:
|
||||||
|
if (OPA->string==OPB->string)
|
||||||
|
OPC->_float = false;
|
||||||
|
else if (!OPA->string)
|
||||||
|
{
|
||||||
|
if (!OPB->string || !*(OPB->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else if (!OPB->string)
|
||||||
|
{
|
||||||
|
if (!OPA->string || !*(OPA->string+progfuncs->stringtable))
|
||||||
|
OPC->_float = false;
|
||||||
|
else
|
||||||
|
OPC->_float = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
OPC->_float = (float)(strcmp(OPA->string+progfuncs->stringtable,OPB->string+progfuncs->stringtable));
|
||||||
|
break;
|
||||||
|
case OP_NE_E:
|
||||||
|
OPC->_float = (float)(OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_FNC:
|
||||||
|
OPC->_float = (float)(OPA->function != OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
case OP_STORE_IF:
|
||||||
|
OPB->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_FI:
|
||||||
|
OPB->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STORE_I:
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_F:
|
||||||
|
case OP_STORE_ENT:
|
||||||
|
case OP_STORE_FLD: // integers
|
||||||
|
case OP_STORE_S:
|
||||||
|
case OP_STORE_FNC: // pointers
|
||||||
|
OPB->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STORE_V:
|
||||||
|
OPB->vector[0] = OPA->vector[0];
|
||||||
|
OPB->vector[1] = OPA->vector[1];
|
||||||
|
OPB->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//store a value to a pointer
|
||||||
|
case OP_STOREP_IF:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_FI:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_I:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_F:
|
||||||
|
case OP_STOREP_ENT:
|
||||||
|
case OP_STOREP_FLD: // integers
|
||||||
|
case OP_STOREP_S:
|
||||||
|
case OP_STOREP_FNC: // pointers
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_int = OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_STOREP_V:
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->vector[0] = OPA->vector[0];
|
||||||
|
ptr->vector[1] = OPA->vector[1];
|
||||||
|
ptr->vector[2] = OPA->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_STOREP_C: //store character in a string
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
*(unsigned char *)ptr = (char)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MULSTORE_F: // f *= f
|
||||||
|
OPB->_float *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTORE_V: // v *= f
|
||||||
|
OPB->vector[0] *= OPA->_float;
|
||||||
|
OPB->vector[1] *= OPA->_float;
|
||||||
|
OPB->vector[2] *= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_F: // e.f *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float *= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_MULSTOREP_V: // e.v *= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[1] *= OPA->_float);
|
||||||
|
OPC->vector[0] = (ptr->vector[2] *= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_DIVSTORE_F: // f /= f
|
||||||
|
OPB->_float /= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_DIVSTOREP_F: // e.f /= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float /= OPA->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADDSTORE_F: // f += f
|
||||||
|
OPB->_float += OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_ADDSTORE_V: // v += v
|
||||||
|
OPB->vector[0] += OPA->vector[0];
|
||||||
|
OPB->vector[1] += OPA->vector[1];
|
||||||
|
OPB->vector[2] += OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_F: // e.f += f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float += OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_ADDSTOREP_V: // e.v += v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] += OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] += OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] += OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUBSTORE_F: // f -= f
|
||||||
|
OPB->_float -= OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUBSTORE_V: // v -= v
|
||||||
|
OPB->vector[0] -= OPA->vector[0];
|
||||||
|
OPB->vector[1] -= OPA->vector[1];
|
||||||
|
OPB->vector[2] -= OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_F: // e.f -= f
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->_float = (ptr->_float -= OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_SUBSTOREP_V: // e.v -= v
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
OPC->vector[0] = (ptr->vector[0] -= OPA->vector[0]);
|
||||||
|
OPC->vector[1] = (ptr->vector[1] -= OPA->vector[1]);
|
||||||
|
OPC->vector[2] = (ptr->vector[2] -= OPA->vector[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//get a pointer to a field var
|
||||||
|
case OP_ADDRESS:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
if (ed->readonly)
|
||||||
|
PR_RunError (progfuncs, "assignment to world entity");
|
||||||
|
OPC->_int = (int)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//load a field to a value
|
||||||
|
case OP_LOAD_I:
|
||||||
|
case OP_LOAD_F:
|
||||||
|
case OP_LOAD_FLD:
|
||||||
|
case OP_LOAD_ENT:
|
||||||
|
case OP_LOAD_S:
|
||||||
|
case OP_LOAD_FNC:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOAD_V:
|
||||||
|
ed = PROG_TO_EDICT(OPA->edict);
|
||||||
|
#ifdef PARANOID
|
||||||
|
NUM_FOR_EDICT(ed); // make sure it's in range
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int *)edvars(ed)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
//==================
|
||||||
|
|
||||||
|
case OP_IFNOTS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->string || !*OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFNOT:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (!OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IFS:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->string && *OPA->string)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_IF:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
if (OPA->_int)
|
||||||
|
st += (sofs)st->b - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_GOTO:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->a - 1; // offset the s++
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CALL8H:
|
||||||
|
case OP_CALL7H:
|
||||||
|
case OP_CALL6H:
|
||||||
|
case OP_CALL5H:
|
||||||
|
case OP_CALL4H:
|
||||||
|
case OP_CALL3H:
|
||||||
|
case OP_CALL2H:
|
||||||
|
G_VECTOR(OFS_PARM1)[0] = OPC->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM1)[1] = OPC->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM1)[2] = OPC->vector[2];
|
||||||
|
case OP_CALL1H:
|
||||||
|
G_VECTOR(OFS_PARM0)[0] = OPB->vector[0];
|
||||||
|
G_VECTOR(OFS_PARM0)[1] = OPB->vector[1];
|
||||||
|
G_VECTOR(OFS_PARM0)[2] = OPB->vector[2];
|
||||||
|
|
||||||
|
case OP_CALL8:
|
||||||
|
case OP_CALL7:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL0:
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
|
||||||
|
|
||||||
|
if (st->op > OP_CALL8)
|
||||||
|
pr_argc = st->op - (OP_CALL1H-1);
|
||||||
|
else
|
||||||
|
pr_argc = st->op - OP_CALL0;
|
||||||
|
fnum = OPA->function;
|
||||||
|
if ((fnum & ~0xff000000)<=0)
|
||||||
|
{
|
||||||
|
pr_trace++;
|
||||||
|
printf("NULL function from qc.\n");
|
||||||
|
#ifndef DEBUGABLE
|
||||||
|
goto cont;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p=pr_typecurrent;
|
||||||
|
//about to switch. needs caching.
|
||||||
|
|
||||||
|
//if it's an external call, switch now (before any function pointers are used)
|
||||||
|
PR_MoveParms(progfuncs, (fnum & 0xff000000)>>24, p);
|
||||||
|
PR_SwitchProgs(progfuncs, (fnum & 0xff000000)>>24);
|
||||||
|
|
||||||
|
newf = &pr_functions[fnum & ~0xff000000];
|
||||||
|
|
||||||
|
if (newf->first_statement < 0)
|
||||||
|
{ // negative statements are built in functions
|
||||||
|
i = -newf->first_statement;
|
||||||
|
// p = pr_typecurrent;
|
||||||
|
if (i < externs->numglobalbuiltins)
|
||||||
|
{
|
||||||
|
(*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
if (prinst->continuestatement!=-1)
|
||||||
|
{
|
||||||
|
st=&pr_statements[prinst->continuestatement];
|
||||||
|
prinst->continuestatement=-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i -= externs->numglobalbuiltins;
|
||||||
|
if (i > current_progstate->numbuiltins)
|
||||||
|
{
|
||||||
|
if (newf->first_statement == -0x7fffffff)
|
||||||
|
((builtin_t)newf->profile) (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
else
|
||||||
|
PR_RunError (progfuncs, "Bad builtin call number");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals);
|
||||||
|
}
|
||||||
|
PR_MoveParms(progfuncs, p, pr_typecurrent);
|
||||||
|
// memcpy(&pr_progstate[p].globals[OFS_RETURN], ¤t_progstate->globals[OFS_RETURN], sizeof(vec3_t));
|
||||||
|
PR_SwitchProgs(progfuncs, (progsnum_t)p);
|
||||||
|
|
||||||
|
//#ifndef DEBUGABLE //decide weather non debugger wants to start debugging.
|
||||||
|
s = st-pr_statements;
|
||||||
|
goto restart;
|
||||||
|
//#endif
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
// PR_MoveParms((OPA->function & 0xff000000)>>24, pr_typecurrent);
|
||||||
|
// PR_SwitchProgs((OPA->function & 0xff000000)>>24);
|
||||||
|
s = PR_EnterFunction (progfuncs, newf, p);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_DONE:
|
||||||
|
case OP_RETURN:
|
||||||
|
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
|
||||||
|
pr_globals[OFS_RETURN] = pr_globals[st->a];
|
||||||
|
pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
|
||||||
|
pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
|
||||||
|
|
||||||
|
s = PR_LeaveFunction (progfuncs);
|
||||||
|
st = &pr_statements[s];
|
||||||
|
if (pr_depth == prinst->exitdepth)
|
||||||
|
{
|
||||||
|
return; // all done
|
||||||
|
}
|
||||||
|
goto restart;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case OP_STATE:
|
||||||
|
externs->stateop(progfuncs, OPA->_float, OPB->function);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_I:
|
||||||
|
OPC->_int = OPA->_int + OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_FI:
|
||||||
|
OPC->_float = OPA->_float + (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_ADD_IF:
|
||||||
|
OPC->_float = (float)OPA->_int + OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_SUB_I:
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_FI:
|
||||||
|
OPC->_float = OPA->_float - (float)OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_SUB_IF:
|
||||||
|
OPC->_float = (float)OPA->_int - OPB->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CONV_ITOF:
|
||||||
|
OPC->_float = (float)OPA->_int;
|
||||||
|
break;
|
||||||
|
case OP_CONV_FTOI:
|
||||||
|
OPC->_int = (int)OPA->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_ITOF:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_float = (float)ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CP_FTOI:
|
||||||
|
ptr = (eval_t *)(((qbyte *)sv_edicts) + OPA->_int);
|
||||||
|
OPC->_int = (int)ptr->_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITAND_I:
|
||||||
|
OPC->_int = (OPA->_int & OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_BITOR_I:
|
||||||
|
OPC->_int = (OPA->_int | OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_MUL_I:
|
||||||
|
OPC->_int = OPA->_int * OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_DIV_I:
|
||||||
|
if (OPB->_int == 0) //no division by zero allowed...
|
||||||
|
OPC->_int = 0;
|
||||||
|
else
|
||||||
|
OPC->_int = OPA->_int / OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_EQ_I:
|
||||||
|
OPC->_int = (OPA->_int == OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_NE_I:
|
||||||
|
OPC->_int = (OPA->_int != OPB->_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
//array/structure reading/riting.
|
||||||
|
case OP_GLOBALADDRESS:
|
||||||
|
OPC->_int = (int)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
break;
|
||||||
|
case OP_POINTER_ADD: //pointer to 32 bit (remember to *3 for vectors)
|
||||||
|
OPC->_int = OPA->_int + OPB->_int*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_I:
|
||||||
|
case OP_LOADA_F:
|
||||||
|
case OP_LOADA_FLD:
|
||||||
|
case OP_LOADA_ENT:
|
||||||
|
case OP_LOADA_S:
|
||||||
|
case OP_LOADA_FNC:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADA_V:
|
||||||
|
ptr = (eval_t *)(&((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_ADD_SF: //(char*)c = (char*)a + (float)b
|
||||||
|
OPC->_int = OPA->_int + (int)OPB->_float;
|
||||||
|
break;
|
||||||
|
case OP_SUB_S: //(float)c = (char*)a - (char*)b
|
||||||
|
OPC->_int = OPA->_int - OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_C: //load character from a string
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + (int)OPB->_float);
|
||||||
|
OPC->_float = *(unsigned char *)ptr;
|
||||||
|
break;
|
||||||
|
case OP_LOADP_I:
|
||||||
|
case OP_LOADP_F:
|
||||||
|
case OP_LOADP_FLD:
|
||||||
|
case OP_LOADP_ENT:
|
||||||
|
case OP_LOADP_S:
|
||||||
|
case OP_LOADP_FNC:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->_int = ptr->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_LOADP_V:
|
||||||
|
#ifdef PRBOUNDSCHECK
|
||||||
|
if (OPB->_int < 0 || OPB->_int + 2 >= pr_edict_size/4)
|
||||||
|
{
|
||||||
|
Host_Error("Progs attempted to read an invalid field in an edict (%i)\n", OPB->_int);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ptr = (eval_t *)(((int)(OPA->_int)) + OPB->_int);
|
||||||
|
OPC->vector[0] = ptr->vector[0];
|
||||||
|
OPC->vector[1] = ptr->vector[1];
|
||||||
|
OPC->vector[2] = ptr->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_POWER_I:
|
||||||
|
OPC->_int = OPA->_int ^ OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_RSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int >> OPB->_int;
|
||||||
|
break;
|
||||||
|
case OP_LSHIFT_I:
|
||||||
|
OPC->_int = OPA->_int << OPB->_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_FETCH_GBL_F:
|
||||||
|
case OP_FETCH_GBL_S:
|
||||||
|
case OP_FETCH_GBL_E:
|
||||||
|
case OP_FETCH_GBL_FNC:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a + i];
|
||||||
|
OPC->_int = t->_int;
|
||||||
|
break;
|
||||||
|
case OP_FETCH_GBL_V:
|
||||||
|
i = (int)OPB->_float;
|
||||||
|
if(i < 0 || i > G_INT((uofs)st->a - 1))
|
||||||
|
{
|
||||||
|
PR_RunError(progfuncs, "array index out of bounds: %s[%d]", PR_GlobalStringNoContents(progfuncs, st->a), i);
|
||||||
|
}
|
||||||
|
t = (eval_t *)&pr_globals[(uofs)st->a
|
||||||
|
+((int)OPB->_float)*3];
|
||||||
|
OPC->vector[0] = t->vector[0];
|
||||||
|
OPC->vector[1] = t->vector[1];
|
||||||
|
OPC->vector[2] = t->vector[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CSTATE:
|
||||||
|
externs->cstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_CWSTATE:
|
||||||
|
externs->cwstateop(progfuncs, OPA->_float, OPB->_float, fnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_THINKTIME:
|
||||||
|
externs->thinktimeop(progfuncs, (struct edict_s *)PROG_TO_EDICT(OPA->edict), OPB->_float);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_BITSET: // b (+) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITSETP: // .b (+) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float | (int)OPA->_float);
|
||||||
|
break;
|
||||||
|
case OP_BITCLR: // b (-) a
|
||||||
|
OPB->_float = (float)((int)OPB->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
case OP_BITCLRP: // .b (-) a
|
||||||
|
ptr = (eval_t *)(OPB->_int);
|
||||||
|
ptr->_float = (float)((int)ptr->_float & ~((int)OPA->_float));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OP_RAND0:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RAND1:
|
||||||
|
G_FLOAT(OFS_RETURN) = (rand()&0x7fff)/((float)0x7fff)*OPA->_float;
|
||||||
|
break;
|
||||||
|
case OP_RAND2:
|
||||||
|
if(OPA->_float < OPB->_float)
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPA->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->_float-OPA->_float));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN) = OPB->_float+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPA->_float-OPB->_float));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_RANDV0:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff);
|
||||||
|
break;
|
||||||
|
case OP_RANDV1:
|
||||||
|
G_FLOAT(OFS_RETURN+0) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[0];
|
||||||
|
G_FLOAT(OFS_RETURN+1) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[1];
|
||||||
|
G_FLOAT(OFS_RETURN+2) = (rand()&0x7fff)/((float)0x7fff)*OPA->vector[2];
|
||||||
|
break;
|
||||||
|
case OP_RANDV2:
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
if(OPA->vector[i] < OPB->vector[i])
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPA->vector[i]+((rand()&0x7fff)/((float)0x7fff)
|
||||||
|
*(OPB->vector[i]-OPA->vector[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
G_FLOAT(OFS_RETURN+i) = OPB->vector[i]+(rand()*(1.0f/RAND_MAX)
|
||||||
|
*(OPA->vector[i]-OPB->vector[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
swtch = OPA;
|
||||||
|
swtchtype = st->op;
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b - 1; // offset the st++
|
||||||
|
break;
|
||||||
|
case OP_CASE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float == OPA->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_E:
|
||||||
|
case OP_SWITCH_FNC:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_S:
|
||||||
|
if (swtch->_int == OPA->_int)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
if ((!swtch->_int && progfuncs->stringtable[OPA->string]) || (!OPA->_int && progfuncs->stringtable[swtch->string])) //one is null (cannot be not both).
|
||||||
|
break;
|
||||||
|
if (!strcmp(progfuncs->stringtable+swtch->string, progfuncs->stringtable+OPA->string))
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_SWITCH_V:
|
||||||
|
if (swtch->vector[0] == OPA->vector[0] && swtch->vector[1] == OPA->vector[1] && swtch->vector[2] == OPA->vector[2])
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->b-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_CASERANGE:
|
||||||
|
switch(swtchtype)
|
||||||
|
{
|
||||||
|
case OP_SWITCH_F:
|
||||||
|
if (swtch->_float >= OPA->_float && swtch->_float <= OPB->_float)
|
||||||
|
{
|
||||||
|
RUNAWAYCHECK();
|
||||||
|
st += (sofs)st->c-1; // -1 to offset the s++
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PR_RunError (progfuncs, "OP_CASERANGE with bad/missing OP_SWITCH %i", swtchtype);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (st->op & 0x8000) //break point!
|
||||||
|
{
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
printf("Break point hit.\n");
|
||||||
|
if (pr_trace<1)
|
||||||
|
pr_trace=1; //this is what it's for
|
||||||
|
|
||||||
|
s = ShowStep(progfuncs, s);
|
||||||
|
st = &pr_statements[s]; //let the user move execution
|
||||||
|
pr_xstatement = s = st-pr_statements;
|
||||||
|
|
||||||
|
memcpy(&fakeop, st, sizeof(dstatement_t)); //don't hit the new statement as a break point, cos it's probably the same one.
|
||||||
|
fakeop.op &= ~0x8000;
|
||||||
|
st = &fakeop; //a little remapping...
|
||||||
|
|
||||||
|
goto reeval; //reexecute
|
||||||
|
}
|
||||||
|
pr_xstatement = st-pr_statements;
|
||||||
|
PR_RunError (progfuncs, "Bad opcode %i", st->op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef cont
|
||||||
|
#undef reeval
|
||||||
|
#undef st
|
||||||
|
#undef pr_statements
|
||||||
|
#undef fakeop
|
||||||
|
#undef dstatement_t
|
||||||
|
#undef sofs
|
||||||
|
#undef uofs
|
217
engine/qclib/hash.c
Normal file
217
engine/qclib/hash.c
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#include "qcc.h"
|
||||||
|
void Hash_InitTable(hashtable_t *table, int numbucks, void *mem)
|
||||||
|
{
|
||||||
|
table->numbuckets = numbucks;
|
||||||
|
table->bucket = (bucket_t **)mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Hash_Key(char *name, int modulus)
|
||||||
|
{ //fixme: optimize.
|
||||||
|
unsigned int key;
|
||||||
|
for (key=0;*name; name++)
|
||||||
|
key += ((key<<3) + (key>>28) + *name);
|
||||||
|
|
||||||
|
return (int)(key%modulus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Hash_Get(hashtable_t *table, char *name)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
while(buck)
|
||||||
|
{
|
||||||
|
if (!STRCMP(name, buck->keystring))
|
||||||
|
return buck->data;
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *Hash_GetKey(hashtable_t *table, int key)
|
||||||
|
{
|
||||||
|
int bucknum = key%table->numbuckets;
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
while(buck)
|
||||||
|
{
|
||||||
|
if ((int)buck->keystring == key)
|
||||||
|
return buck->data;
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void *Hash_GetNext(hashtable_t *table, char *name, void *old)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
while(buck)
|
||||||
|
{
|
||||||
|
if (!STRCMP(name, buck->keystring))
|
||||||
|
{
|
||||||
|
if (buck->data == old) //found the old one
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
if (!buck)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buck = buck->next;//don't return old
|
||||||
|
while(buck)
|
||||||
|
{
|
||||||
|
if (!STRCMP(name, buck->keystring))
|
||||||
|
return buck->data;
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MINIMAL
|
||||||
|
void *Hash_Add(hashtable_t *table, char *name, void *data)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = qccHunkAlloc(sizeof(bucket_t));
|
||||||
|
|
||||||
|
buck->data = data;
|
||||||
|
buck->keystring = name;
|
||||||
|
buck->next = table->bucket[bucknum];
|
||||||
|
table->bucket[bucknum] = buck;
|
||||||
|
|
||||||
|
return buck;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void *Hash_Add2(hashtable_t *table, char *name, void *data, bucket_t *buck)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
|
||||||
|
buck->data = data;
|
||||||
|
buck->keystring = name;
|
||||||
|
buck->next = table->bucket[bucknum];
|
||||||
|
table->bucket[bucknum] = buck;
|
||||||
|
|
||||||
|
return buck;
|
||||||
|
}
|
||||||
|
#ifndef MINIMAL
|
||||||
|
void *Hash_AddKey(hashtable_t *table, int key, void *data)
|
||||||
|
{
|
||||||
|
int bucknum = key%table->numbuckets;
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = qccHunkAlloc(sizeof(bucket_t));
|
||||||
|
|
||||||
|
buck->data = data;
|
||||||
|
(int)buck->keystring = key;
|
||||||
|
buck->next = table->bucket[bucknum];
|
||||||
|
table->bucket[bucknum] = buck;
|
||||||
|
|
||||||
|
return buck;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void *Hash_AddKey2(hashtable_t *table, int key, void *data, bucket_t *buck)
|
||||||
|
{
|
||||||
|
int bucknum = key%table->numbuckets;
|
||||||
|
|
||||||
|
buck->data = data;
|
||||||
|
(int)buck->keystring = key;
|
||||||
|
buck->next = table->bucket[bucknum];
|
||||||
|
table->bucket[bucknum] = buck;
|
||||||
|
|
||||||
|
return buck;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hash_Remove(hashtable_t *table, char *name)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
if (!STRCMP(name, buck->keystring))
|
||||||
|
{
|
||||||
|
table->bucket[bucknum] = buck->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while(buck->next)
|
||||||
|
{
|
||||||
|
if (!STRCMP(name, buck->next->keystring))
|
||||||
|
{
|
||||||
|
buck->next = buck->next->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hash_RemoveData(hashtable_t *table, char *name, void *data)
|
||||||
|
{
|
||||||
|
int bucknum = Hash_Key(name, table->numbuckets);
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
if (buck->data == data)
|
||||||
|
if (!STRCMP(name, buck->keystring))
|
||||||
|
{
|
||||||
|
table->bucket[bucknum] = buck->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while(buck->next)
|
||||||
|
{
|
||||||
|
if (buck->next->data == data)
|
||||||
|
if (!STRCMP(name, buck->next->keystring))
|
||||||
|
{
|
||||||
|
buck->next = buck->next->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Hash_RemoveKey(hashtable_t *table, int key)
|
||||||
|
{
|
||||||
|
int bucknum = key%table->numbuckets;
|
||||||
|
bucket_t *buck;
|
||||||
|
|
||||||
|
buck = table->bucket[bucknum];
|
||||||
|
|
||||||
|
if ((int)buck->keystring == key)
|
||||||
|
{
|
||||||
|
table->bucket[bucknum] = buck->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while(buck->next)
|
||||||
|
{
|
||||||
|
if ((int)buck->next->keystring == key)
|
||||||
|
{
|
||||||
|
buck->next = buck->next->next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buck = buck->next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
27
engine/qclib/hash.h
Normal file
27
engine/qclib/hash.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//=============================
|
||||||
|
//David's hash tables
|
||||||
|
//string based.
|
||||||
|
|
||||||
|
#define Hash_BytesForBuckets(b) (sizeof(bucket_t)*b)
|
||||||
|
|
||||||
|
#define STRCMP(s1,s2) (((*s1)!=(*s2)) || strcmp(s1+1,s2+1)) //saves about 2-6 out of 120 - expansion of idea from fastqcc
|
||||||
|
typedef struct bucket_s {
|
||||||
|
void *data;
|
||||||
|
char *keystring;
|
||||||
|
struct bucket_s *next;
|
||||||
|
} bucket_t;
|
||||||
|
typedef struct hashtable_s {
|
||||||
|
int numbuckets;
|
||||||
|
bucket_t **bucket;
|
||||||
|
} hashtable_t;
|
||||||
|
|
||||||
|
void Hash_InitTable(hashtable_t *table, int numbucks, void *mem); //mem must be 0 filled. (memset(mem, 0, size))
|
||||||
|
int Hash_Key(char *name, int modulus);
|
||||||
|
void *Hash_Get(hashtable_t *table, char *name);
|
||||||
|
void *Hash_GetKey(hashtable_t *table, int key);
|
||||||
|
void *Hash_GetNext(hashtable_t *table, char *name, void *old);
|
||||||
|
void *Hash_Add(hashtable_t *table, char *name, void *data);
|
||||||
|
void *Hash_Add2(hashtable_t *table, char *name, void *data, bucket_t *buck);
|
||||||
|
void *Hash_AddKey(hashtable_t *table, int key, void *data);
|
||||||
|
void Hash_Remove(hashtable_t *table, char *name);
|
||||||
|
void Hash_RemoveData(hashtable_t *table, char *name, void *data);
|
564
engine/qclib/initlib.c
Normal file
564
engine/qclib/initlib.c
Normal file
|
@ -0,0 +1,564 @@
|
||||||
|
#define PROGSUSED
|
||||||
|
#include "progsint.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
typedef struct prmemb_s {
|
||||||
|
struct prmemb_s *prev;
|
||||||
|
int level;
|
||||||
|
} prmemb_t;
|
||||||
|
void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount)
|
||||||
|
{
|
||||||
|
if (!progshunk)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
return ((char *)mem)+sizeof(prmemb_t);
|
||||||
|
}
|
||||||
|
hunkused+=ammount;
|
||||||
|
if (hunkused > hunksize)
|
||||||
|
Sys_Error("QCLIB: Out of hunk");
|
||||||
|
|
||||||
|
memset(progshunk + hunkused-ammount, 0, ammount);
|
||||||
|
return progshunk + hunkused-ammount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PRHunkMark(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
if (!progshunk)
|
||||||
|
{
|
||||||
|
return ((prmemb_t *)memb)->level;
|
||||||
|
}
|
||||||
|
return hunkused;
|
||||||
|
}
|
||||||
|
void PRHunkFree(progfuncs_t *progfuncs, int mark)
|
||||||
|
{
|
||||||
|
if (!progshunk)
|
||||||
|
{
|
||||||
|
prmemb_t *omem;
|
||||||
|
while(memb)
|
||||||
|
{
|
||||||
|
if (memb->level <= mark)
|
||||||
|
return;
|
||||||
|
|
||||||
|
omem = memb;
|
||||||
|
memb = memb->prev;
|
||||||
|
memfree(omem);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hunkused = mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PR_InitEnts(progfuncs_t *progfuncs, int max_ents)
|
||||||
|
{
|
||||||
|
maxedicts = max_ents;
|
||||||
|
|
||||||
|
sv_num_edicts = 0;
|
||||||
|
|
||||||
|
pr_edict_size += externs->edictsize;
|
||||||
|
|
||||||
|
pr_max_edict_size = pr_edict_size;
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
prinst->edicttable = PRHunkAlloc(progfuncs, maxedicts*sizeof(struct edicts_s *));
|
||||||
|
sv_edicts = PRHunkAlloc(progfuncs, pr_edict_size);
|
||||||
|
prinst->edicttable[0] = sv_edicts;
|
||||||
|
sv_num_edicts = 1;
|
||||||
|
#else
|
||||||
|
sv_edicts = PRHunkAlloc(progfuncs, (pr_edict_size) * maxedicts);
|
||||||
|
|
||||||
|
{int a;
|
||||||
|
for (a = 1; a < maxedicts; a++)
|
||||||
|
{
|
||||||
|
((edictrun_t*)EDICT_NUM(progfuncs, a))->isfree = true;
|
||||||
|
((edictrun_t*)EDICT_NUM(progfuncs, a))->freetime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
sv_num_edicts = 1;
|
||||||
|
|
||||||
|
return pr_edict_size;
|
||||||
|
}
|
||||||
|
char tempedicts[2048]; //used as a safty buffer
|
||||||
|
void PR_Configure (progfuncs_t *progfuncs, void *mem, int mem_size, int max_progs) //can be used to wipe all memory
|
||||||
|
{
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
int i;
|
||||||
|
edictrun_t *e;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// int a;
|
||||||
|
pr_max_edict_size=0;
|
||||||
|
pr_edict_size = 0;
|
||||||
|
progfuncs->stringtable = 0;
|
||||||
|
QC_StartShares(progfuncs);
|
||||||
|
QC_InitShares(progfuncs);
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
for ( i=1 ; i<maxedicts; i++)
|
||||||
|
{
|
||||||
|
(struct edict_s *)e = prinst->edicttable[i];
|
||||||
|
prinst->edicttable[i] = NULL;
|
||||||
|
// e->entnum = i;
|
||||||
|
if (e)
|
||||||
|
memfree(e);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PRHunkFree(progfuncs, 0); //clear mem - our hunk may not be a real hunk.
|
||||||
|
|
||||||
|
//three conditions.
|
||||||
|
//mem + size uses new hunk space
|
||||||
|
//size>=0 uses previous hunk space
|
||||||
|
//size < 0 uses memalloc for mem, then 'emulates' a hunk.
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
|
if (mem_size < 0)
|
||||||
|
{
|
||||||
|
progshunk = NULL;
|
||||||
|
hunksize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progshunk = mem;
|
||||||
|
hunksize = mem_size;
|
||||||
|
}
|
||||||
|
hunkused = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct globalvars_s *PR_globals (progfuncs_t *progfuncs, progsnum_t pnum)
|
||||||
|
{
|
||||||
|
if (pnum < 0)
|
||||||
|
return (struct globalvars_s *)current_progstate->globals;
|
||||||
|
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;
|
||||||
|
if (pnum == -2)
|
||||||
|
{
|
||||||
|
for (pnum = 0; pnum < maxprogs; pnum ++)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
return (f - pr_progstate[pnum].functions) | (pnum << 24);;
|
||||||
|
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;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
((int*)pr_globals)[ofs] = EDICT_TO_PROG(ed);
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
s=G_STRING((OFS_PARM0+i*3));
|
||||||
|
strcat (out, G_STRING((OFS_PARM0+i*3)));
|
||||||
|
|
||||||
|
//#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;
|
||||||
|
return (eval_t *)&(
|
||||||
|
((int*)((char *)ed + externs->edictsize))
|
||||||
|
[var->ofs]);
|
||||||
|
}
|
||||||
|
if (!cache->varname)
|
||||||
|
{
|
||||||
|
cache->varname = name;
|
||||||
|
var = ED_FindField(progfuncs, name);
|
||||||
|
if (!var)
|
||||||
|
{
|
||||||
|
cache->ofs32 = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
cache->ofs32 = var;
|
||||||
|
return (eval_t *)
|
||||||
|
&((int*)((char *)ed + externs->edictsize))
|
||||||
|
[var->ofs];
|
||||||
|
}
|
||||||
|
if (cache->ofs32 == NULL)
|
||||||
|
return NULL;
|
||||||
|
return (eval_t *)
|
||||||
|
&((int*)((char *)ed + externs->edictsize))
|
||||||
|
[cache->ofs32->ofs];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct edict_s *ProgsToEdict (progfuncs_t *progfuncs, int progs)
|
||||||
|
{
|
||||||
|
return (struct edict_s *)PROG_TO_EDICT(progs);
|
||||||
|
}
|
||||||
|
int EdictToProgs (progfuncs_t *progfuncs, struct edict_s *ed)
|
||||||
|
{
|
||||||
|
return EDICT_TO_PROG(ed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
PR_AbortStack
|
||||||
|
};
|
||||||
|
#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;
|
||||||
|
|
||||||
|
PR_COMPILENEXIST,
|
||||||
|
|
||||||
|
&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)
|
||||||
|
{
|
||||||
|
extensionbuiltin_t *eb;
|
||||||
|
void (VARGS *f) (void *);
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
int i;
|
||||||
|
edictrun_t *e;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
f = inst->parms->memfree;
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_ENTS
|
||||||
|
for ( i=1 ; i<inst->maxedicts; i++)
|
||||||
|
{
|
||||||
|
(struct edict_s *)e = inst->prinst->edicttable[i];
|
||||||
|
inst->prinst->edicttable[i] = NULL;
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
// e->entnum = i;
|
||||||
|
f(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PRHunkFree(inst, 0);
|
||||||
|
while(inst->prinst->extensionbuiltin)
|
||||||
|
{
|
||||||
|
eb = inst->prinst->extensionbuiltin->prev;
|
||||||
|
f(inst->prinst->extensionbuiltin);
|
||||||
|
inst->prinst->extensionbuiltin = eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
extensionbuiltin_t *eb;
|
||||||
|
eb = memalloc(sizeof(extensionbuiltin_t));
|
||||||
|
eb->prev = progfuncs->prinst->extensionbuiltin;
|
||||||
|
progfuncs->prinst->extensionbuiltin = eb;
|
||||||
|
eb->name = name;
|
||||||
|
eb->func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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));
|
||||||
|
memcpy(funcs, &deffuncs, sizeof(progfuncs_t));
|
||||||
|
|
||||||
|
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
|
2803
engine/qclib/pr_edict.c
Normal file
2803
engine/qclib/pr_edict.c
Normal file
File diff suppressed because it is too large
Load diff
528
engine/qclib/pr_multi.c
Normal file
528
engine/qclib/pr_multi.c
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
#define PROGSUSED
|
||||||
|
#include "progsint.h"
|
||||||
|
|
||||||
|
#define HunkAlloc BADGDFG sdfhhsf FHS
|
||||||
|
|
||||||
|
void PR_SetBuiltins(int type);
|
||||||
|
/*
|
||||||
|
progstate_t *pr_progstate;
|
||||||
|
progsnum_t pr_typecurrent;
|
||||||
|
int maxprogs;
|
||||||
|
|
||||||
|
progstate_t *current_progstate;
|
||||||
|
int numshares;
|
||||||
|
|
||||||
|
sharedvar_t *shares; //shared globals, not including parms
|
||||||
|
int maxshares;
|
||||||
|
*/
|
||||||
|
|
||||||
|
pbool PR_SwitchProgs(progfuncs_t *progfuncs, progsnum_t type)
|
||||||
|
{
|
||||||
|
if (type >= maxprogs || type < 0)
|
||||||
|
PR_RunError(progfuncs, "QCLIB: Bad prog type - %i", type);
|
||||||
|
// Sys_Error("Bad prog type - %i", type);
|
||||||
|
|
||||||
|
if (pr_progstate[(int)type].progs == NULL) //we havn't loaded it yet, for some reason
|
||||||
|
return false;
|
||||||
|
|
||||||
|
current_progstate = &pr_progstate[(int)type];
|
||||||
|
|
||||||
|
pr_typecurrent = type;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_MoveParms(progfuncs_t *progfuncs, progsnum_t progs1, progsnum_t progs2) //from 2 to 1
|
||||||
|
{
|
||||||
|
unsigned int a;
|
||||||
|
progstate_t *p1;
|
||||||
|
progstate_t *p2;
|
||||||
|
|
||||||
|
if (progs1 == progs2)
|
||||||
|
return; //don't bother coping variables to themselves...
|
||||||
|
|
||||||
|
p1 = &pr_progstate[(int)progs1];
|
||||||
|
p2 = &pr_progstate[(int)progs2];
|
||||||
|
|
||||||
|
if (progs1 >= maxprogs || progs1 < 0 || !p1->globals)
|
||||||
|
Sys_Error("QCLIB: Bad prog type - %i", progs1);
|
||||||
|
if (progs2 >= maxprogs || progs2 < 0 || !p2->globals)
|
||||||
|
Sys_Error("QCLIB: Bad prog type - %i", progs2);
|
||||||
|
|
||||||
|
//copy parms.
|
||||||
|
for (a = 0; a < MAX_PARMS;a++)
|
||||||
|
{
|
||||||
|
*(int *)&p1->globals[OFS_PARM0+3*a ] = *(int *)&p2->globals[OFS_PARM0+3*a ];
|
||||||
|
*(int *)&p1->globals[OFS_PARM0+3*a+1] = *(int *)&p2->globals[OFS_PARM0+3*a+1];
|
||||||
|
*(int *)&p1->globals[OFS_PARM0+3*a+2] = *(int *)&p2->globals[OFS_PARM0+3*a+2];
|
||||||
|
}
|
||||||
|
p1->globals[OFS_RETURN] = p2->globals[OFS_RETURN];
|
||||||
|
p1->globals[OFS_RETURN+1] = p2->globals[OFS_RETURN+1];
|
||||||
|
p1->globals[OFS_RETURN+2] = p2->globals[OFS_RETURN+2];
|
||||||
|
|
||||||
|
//move the vars defined as shared.
|
||||||
|
for (a = 0; a < numshares; a++)//fixme: make offset per progs
|
||||||
|
{
|
||||||
|
memmove(&((int *)p1->globals)[shares[a].varofs], &((int *)p2->globals)[shares[a].varofs], shares[a].size*4);
|
||||||
|
/* ((int *)p1->globals)[shares[a].varofs] = ((int *)p2->globals)[shares[a].varofs];
|
||||||
|
if (shares[a].size > 1)
|
||||||
|
{
|
||||||
|
((int *)p1->globals)[shares[a].varofs+1] = ((int *)p2->globals)[shares[a].varofs+1];
|
||||||
|
if (shares[a].size > 2)
|
||||||
|
((int *)p1->globals)[shares[a].varofs+2] = ((int *)p2->globals)[shares[a].varofs+2];
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progsnum_t PR_LoadProgs(progfuncs_t *progfuncs, char *s, int headercrc, builtin_t *builtins, int numbuiltins)
|
||||||
|
{
|
||||||
|
progsnum_t a;
|
||||||
|
progsnum_t oldtype;
|
||||||
|
oldtype = pr_typecurrent;
|
||||||
|
for (a = 0; a < maxprogs; a++)
|
||||||
|
{
|
||||||
|
if (pr_progstate[(int)a].progs == NULL)
|
||||||
|
{
|
||||||
|
pr_typecurrent = a;
|
||||||
|
current_progstate = &pr_progstate[(int)a];
|
||||||
|
if (PR_ReallyLoadProgs(progfuncs, s, headercrc, &pr_progstate[a], false)) //try and load it
|
||||||
|
{
|
||||||
|
current_progstate->builtins = builtins;
|
||||||
|
current_progstate->numbuiltins = numbuiltins;
|
||||||
|
if (oldtype>=0)
|
||||||
|
PR_SwitchProgs(progfuncs, oldtype);
|
||||||
|
return a; //we could load it. Yay!
|
||||||
|
}
|
||||||
|
if (oldtype!=-1)
|
||||||
|
PR_SwitchProgs(progfuncs, oldtype);
|
||||||
|
return -1; // loading failed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PR_SwitchProgs(progfuncs, oldtype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PR_ShiftParms(progfuncs_t *progfuncs, int amount)
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
for (a = 0; a < MAX_PARMS - amount;a++)
|
||||||
|
*(int *)&pr_globals[OFS_PARM0+3*a] = *(int *)&pr_globals[OFS_PARM0+3*(amount+a)];
|
||||||
|
}
|
||||||
|
|
||||||
|
//forget a progs
|
||||||
|
void PR_Clear(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
for (a = 0; a < maxprogs; a++)
|
||||||
|
{
|
||||||
|
pr_progstate[a].progs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void QC_StartShares(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
numshares = 0;
|
||||||
|
maxshares = 32;
|
||||||
|
if (shares)
|
||||||
|
memfree(shares);
|
||||||
|
shares = memalloc(sizeof(sharedvar_t)*maxshares);
|
||||||
|
}
|
||||||
|
void QC_AddSharedVar(progfuncs_t *progfuncs, int start, int size) //fixme: make offset per progs and optional
|
||||||
|
{
|
||||||
|
int ofs;
|
||||||
|
unsigned int a;
|
||||||
|
|
||||||
|
if (numshares >= maxshares)
|
||||||
|
{
|
||||||
|
void *buf;
|
||||||
|
buf = shares;
|
||||||
|
maxshares += 16;
|
||||||
|
shares = memalloc(sizeof(sharedvar_t)*maxshares);
|
||||||
|
|
||||||
|
memcpy(shares, buf, sizeof(sharedvar_t)*numshares);
|
||||||
|
|
||||||
|
memfree(buf);
|
||||||
|
}
|
||||||
|
ofs = start;
|
||||||
|
for (a = 0; a < numshares; a++)
|
||||||
|
{
|
||||||
|
if (shares[a].varofs+shares[a].size == ofs)
|
||||||
|
{
|
||||||
|
shares[a].size += size; //expand size.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (shares[a].varofs == start)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shares[numshares].varofs = start;
|
||||||
|
shares[numshares].size = size;
|
||||||
|
numshares++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//void ShowWatch(void);
|
||||||
|
|
||||||
|
void QC_InitShares(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
// ShowWatch();
|
||||||
|
if (!field) //don't make it so we will just need to remalloc everything
|
||||||
|
{
|
||||||
|
maxfields = 64;
|
||||||
|
field = memalloc(sizeof(fdef_t) * maxfields);
|
||||||
|
}
|
||||||
|
|
||||||
|
numfields = 0;
|
||||||
|
progfuncs->fieldadjust = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//called if a global is defined as a field
|
||||||
|
//returns offset.
|
||||||
|
|
||||||
|
//vectors must be added before any of thier corresponding _x/y/z vars
|
||||||
|
//in this way, even screwed up progs work.
|
||||||
|
int QC_RegisterFieldVar(progfuncs_t *progfuncs, unsigned int type, char *name, int requestedpos, int origionalofs)
|
||||||
|
{
|
||||||
|
// progstate_t *p;
|
||||||
|
// int pnum;
|
||||||
|
unsigned int i;
|
||||||
|
int namelen;
|
||||||
|
int ofs;
|
||||||
|
|
||||||
|
int fnum;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
progfuncs->fieldadjust = pr_edict_size/4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
prinst->reorganisefields = true;
|
||||||
|
|
||||||
|
//look for an existing match
|
||||||
|
for (i = 0; i < numfields; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, field[i].s_name))
|
||||||
|
{
|
||||||
|
if (field[i].type != type)
|
||||||
|
{
|
||||||
|
printf("Field type mismatch on %s\n", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!progfuncs->fieldadjust && requestedpos>=0)
|
||||||
|
if ((unsigned)requestedpos != field[i].ofs)
|
||||||
|
Sys_Error("Field %s at wrong offset", name);
|
||||||
|
|
||||||
|
if (field[i].requestedofs == -1)
|
||||||
|
field[i].requestedofs = origionalofs;
|
||||||
|
return field[i].ofs; //got a match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numfields+1>maxfields)
|
||||||
|
{
|
||||||
|
fdef_t *nf;
|
||||||
|
i = maxfields;
|
||||||
|
maxfields += 32;
|
||||||
|
nf = memalloc(sizeof(fdef_t) * maxfields);
|
||||||
|
memcpy(nf, field, sizeof(fdef_t) * i);
|
||||||
|
memfree(field);
|
||||||
|
field = nf;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to add a new one
|
||||||
|
fnum = numfields;
|
||||||
|
numfields++;
|
||||||
|
field[fnum].s_name = name;
|
||||||
|
if (type == ev_vector) //resize with the following floats (this is where I think I went wrong)
|
||||||
|
{
|
||||||
|
char *n;
|
||||||
|
namelen = strlen(name)+5;
|
||||||
|
|
||||||
|
n=PRHunkAlloc(progfuncs, namelen);
|
||||||
|
sprintf(n, "%s_x", name);
|
||||||
|
field[fnum].ofs = ofs = QC_RegisterFieldVar(progfuncs, ev_float, n, requestedpos, -1);
|
||||||
|
|
||||||
|
n=PRHunkAlloc(progfuncs, namelen);
|
||||||
|
sprintf(n, "%s_y", name);
|
||||||
|
QC_RegisterFieldVar(progfuncs, ev_float, n, (requestedpos==-1)?-1:(requestedpos+4), -1);
|
||||||
|
|
||||||
|
n=PRHunkAlloc(progfuncs, namelen);
|
||||||
|
sprintf(n, "%s_z", name);
|
||||||
|
QC_RegisterFieldVar(progfuncs, ev_float, n, (requestedpos==-1)?-1:(requestedpos+8), -1);
|
||||||
|
}
|
||||||
|
else if (requestedpos >= 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < numfields-1; i++)
|
||||||
|
{
|
||||||
|
if (field[i].ofs == (unsigned)requestedpos)
|
||||||
|
{
|
||||||
|
if (type == ev_float && field[i].type == ev_vector) //check names
|
||||||
|
{
|
||||||
|
if (strncmp(field[i].s_name, name, strlen(field[i].s_name)))
|
||||||
|
Sys_Error("Duplicated offset");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Sys_Error("Duplicated offset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requestedpos&3)
|
||||||
|
Sys_Error("field %s is %i&3", name, requestedpos);
|
||||||
|
field[fnum].ofs = ofs = requestedpos/4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
field[fnum].ofs = ofs = pr_edict_size/4;
|
||||||
|
// if (type != ev_vector)
|
||||||
|
if (pr_edict_size < (ofs+type_size[type])*4)
|
||||||
|
pr_edict_size = (ofs+type_size[type])*4;
|
||||||
|
|
||||||
|
if (pr_max_edict_size && pr_edict_size > pr_max_edict_size)
|
||||||
|
Sys_Error("Allocated too many additional fields after ents were inited.");
|
||||||
|
field[fnum].type = type;
|
||||||
|
|
||||||
|
field[fnum].requestedofs = origionalofs;
|
||||||
|
|
||||||
|
//we've finished setting the structure
|
||||||
|
return ofs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//called if a global is defined as a field
|
||||||
|
void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num)
|
||||||
|
{
|
||||||
|
// progstate_t *p;
|
||||||
|
// int pnum;
|
||||||
|
unsigned int i, o;
|
||||||
|
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
//look for an existing match not needed, cos we look a little later too.
|
||||||
|
/*
|
||||||
|
for (i = 0; i < numfields; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(pr_globaldefs[num].s_name, field[i].s_name))
|
||||||
|
{
|
||||||
|
//really we should look for a field def
|
||||||
|
|
||||||
|
*(int *)&pr_globals[pr_globaldefs[num].ofs] = field[i].ofs; //got a match
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch(current_progstate->intsize)
|
||||||
|
{
|
||||||
|
case 24:
|
||||||
|
case 16:
|
||||||
|
for (i=1 ; i<pr_progs->numfielddefs; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(pr_fielddefs16[i].s_name, pr_globaldefs16[num].s_name))
|
||||||
|
{
|
||||||
|
*(int *)&pr_globals[pr_globaldefs16[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs16[i].type, pr_globaldefs16[num].s_name, -1, *(int *)&pr_globals[pr_globaldefs16[num].ofs])-progfuncs->fieldadjust;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = pr_globaldefs16[num].s_name;
|
||||||
|
|
||||||
|
for (i = 0; i < numfields; i++)
|
||||||
|
{
|
||||||
|
o = field[i].requestedofs;
|
||||||
|
if (o == *(unsigned int *)&pr_globals[pr_globaldefs16[num].ofs])
|
||||||
|
{
|
||||||
|
*(int *)&pr_globals[pr_globaldefs16[num].ofs] = field[i].ofs-progfuncs->fieldadjust;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//oh well, must be a parameter.
|
||||||
|
if (*(int *)&pr_globals[pr_globaldefs16[num].ofs])
|
||||||
|
Sys_Error("QCLIB: Global field var with no matching field \"%s\", from offset %i", pr_globaldefs16[num].s_name, *(int *)&pr_globals[pr_globaldefs16[num].ofs]);
|
||||||
|
return;
|
||||||
|
case 32:
|
||||||
|
for (i=1 ; i<pr_progs->numfielddefs; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(pr_fielddefs32[i].s_name, pr_globaldefs32[num].s_name))
|
||||||
|
{
|
||||||
|
*(int *)&pr_globals[pr_globaldefs32[num].ofs] = QC_RegisterFieldVar(progfuncs, pr_fielddefs32[i].type, pr_globaldefs32[num].s_name, -1, *(int *)&pr_globals[pr_globaldefs32[num].ofs])-progfuncs->fieldadjust;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = pr_globaldefs32[num].s_name;
|
||||||
|
|
||||||
|
for (i = 0; i < numfields; i++)
|
||||||
|
{
|
||||||
|
o = field[i].requestedofs;
|
||||||
|
if (o == *(unsigned int *)&pr_globals[pr_globaldefs32[num].ofs])
|
||||||
|
{
|
||||||
|
*(int *)&pr_globals[pr_globaldefs32[num].ofs] = field[i].ofs-progfuncs->fieldadjust;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//oh well, must be a parameter.
|
||||||
|
if (*(int *)&pr_globals[pr_globaldefs32[num].ofs])
|
||||||
|
Sys_Error("QCLIB: Global field var with no matching field \"%s\", from offset %i", pr_globaldefs32[num].s_name, *(int *)&pr_globals[pr_globaldefs32[num].ofs]);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
Sys_Error("Bad bits");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Sys_Error("Should be unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
//Just a bit of code that makes a window appear with lots of variables listed.
|
||||||
|
//A little useless really.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void WatchDraw(window_t *wnd);
|
||||||
|
static void WatchDead(window_t *wnd);
|
||||||
|
static bool WatchKeyDown(window_t *wnd, int k);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int progs;
|
||||||
|
int globofs;
|
||||||
|
} watchinfo_t;
|
||||||
|
|
||||||
|
static window_t watchtemplate = {
|
||||||
|
sizeof(window_t), //int size; //for possible later expansion
|
||||||
|
"Watch", //char *title;
|
||||||
|
BORDER_RESIZE, //void (*DrawBorder) (struct window_s *wnd); //the border drawing func (use a borde type)
|
||||||
|
WatchDraw, //void (*DrawWindow) (struct window_s *); //the drawing func
|
||||||
|
NULL, //void (*Draw3dWindow) (struct window_s *); //the function to draw 3d stuff
|
||||||
|
WatchDead, //void (*CloseWindow) (struct window_s *); //when it is closed
|
||||||
|
WatchKeyDown, //bool (*KeyDown) (struct window_s *, int key); //return true to stop the main game from recieving the call
|
||||||
|
NULL, //void (*KeyUp) (struct window_s *, int key); //sent to all
|
||||||
|
NULL, //void (*Think) (struct window_s *);
|
||||||
|
NULL, //void (*ReloadTex) (struct window_s *);
|
||||||
|
|
||||||
|
{320, 0, 640, 240},//float viewarea[4]; //l, t, r, b
|
||||||
|
{1, 10, 1, 1},//float bordersize[4]; //l,t,r,b
|
||||||
|
{0, 0, 0},//float vieworigin[3]; //3d view origin
|
||||||
|
{0, 0, 0},//float viewangles[3]; //3d angles
|
||||||
|
|
||||||
|
TRUE,//bool clear; //should it be cleared first (for 3d rendering and default border routine)
|
||||||
|
|
||||||
|
NULL,//void *data; //use this to get unique windows of the same type
|
||||||
|
0,//int classid; //a randomly chosen number that is the same for each of this window's type
|
||||||
|
0,//int subclass; //a number if an app needs to identify between windows of the same class
|
||||||
|
|
||||||
|
NULL//void *(*comunicate) (int type, void *info, void *moreinfo); //later development for chatting between windows (like the 'SendMessage' function in the OS)
|
||||||
|
|
||||||
|
//for multiple windows
|
||||||
|
//struct window_s *next;
|
||||||
|
//struct window_s *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ShowWatch(void)
|
||||||
|
{
|
||||||
|
watchinfo_t *inf;
|
||||||
|
window_t *wnd;
|
||||||
|
wnd = memalloc(sizeof(window_t)+sizeof(watchinfo_t), "watch window");
|
||||||
|
memcpy(wnd, &watchtemplate, sizeof(window_t));
|
||||||
|
wnd->data = inf = (watchinfo_t *)(wnd+1);
|
||||||
|
inf->globofs = 1;
|
||||||
|
inf->progs = 0;
|
||||||
|
AddWindow(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WatchDead(window_t *wnd)
|
||||||
|
{
|
||||||
|
RemoveWindow(wnd);
|
||||||
|
memfree(wnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WatchKeyDown(window_t *wnd, int k)
|
||||||
|
{
|
||||||
|
watchinfo_t *inf = wnd->data;
|
||||||
|
int progs = inf->progs;
|
||||||
|
if (progs < 0)
|
||||||
|
progs = pr_typecurrent;
|
||||||
|
|
||||||
|
switch(k)
|
||||||
|
{
|
||||||
|
case K_MOUSEWUP:
|
||||||
|
inf->globofs-=8;
|
||||||
|
if (inf->globofs < 1)
|
||||||
|
inf->globofs = 1;
|
||||||
|
break;
|
||||||
|
case K_MOUSEWDOWN:
|
||||||
|
inf->globofs+=8;
|
||||||
|
if (inf->globofs > pr_progstate[progs].progs->numglobaldefs-1)
|
||||||
|
inf->globofs = pr_progstate[progs].progs->numglobaldefs-1;
|
||||||
|
break;
|
||||||
|
case K_ESCAPE:
|
||||||
|
RemoveWindow(wnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *PR_ValueString (etype_t type, eval_t *val);
|
||||||
|
static void WatchDraw(window_t *wnd)
|
||||||
|
{
|
||||||
|
float yofs;
|
||||||
|
int def=0;
|
||||||
|
int progs = ((watchinfo_t *)wnd->data)->progs;
|
||||||
|
|
||||||
|
if (progs < 0)
|
||||||
|
progs = pr_typecurrent;
|
||||||
|
|
||||||
|
if (!pr_progstate[progs].progs)
|
||||||
|
{
|
||||||
|
Draw_String(wnd->viewarea[0], wnd->viewarea[1]+8+def*8, "Progs not loaded", 1, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (sv_edicts==NULL)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
yofs=wnd->viewarea[1];
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, pr_progstate[progs].filename, 1, 0);yofs+=8;
|
||||||
|
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_RETURN, "RETURN", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_RETURN])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM0, "PARM0", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM0])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM1, "PARM1", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM1])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM2, "PARM2", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM2])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM3, "PARM3", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM3])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM4, "PARM4", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM4])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM5, "PARM5", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM5])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM6, "PARM6", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM6])), 1, 0);yofs+=8;
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", OFS_PARM7, "PARM7", PR_ValueString(ev_vector, (eval_t *)&pr_progstate[progs].globals[OFS_PARM7])), 1, 0);yofs+=8;
|
||||||
|
for (def = ((watchinfo_t *)wnd->data)->globofs; def < pr_progstate[progs].progs->numglobaldefs; def++)
|
||||||
|
{
|
||||||
|
if ((pr_progstate[progs].globaldefs[def].type &~DEF_SAVEGLOBAL)== ev_entity && sv_edicts==NULL)
|
||||||
|
{
|
||||||
|
grColor4f(0.5, 0.5, 0.5, 1);
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", pr_progstate[progs].globaldefs[def].ofs, pr_progstate[progs].globaldefs[def].s_name, "Entities not initialized"), 1, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pr_progstate[progs].globaldefs[def].type == ev_void || pr_progstate[progs].globaldefs[def].type == ev_field || pr_progstate[progs].globaldefs[def].type == ev_function || !(pr_progstate[progs].globaldefs[def].type & DEF_SAVEGLOBAL))
|
||||||
|
grColor4f(0.5, 0.5, 0.5, 1);
|
||||||
|
else
|
||||||
|
grColor4f(1, 1, 1, 1);
|
||||||
|
Draw_String(wnd->viewarea[0], yofs, Sva("%3i %16s %s", pr_progstate[progs].globaldefs[def].ofs, pr_progstate[progs].globaldefs[def].s_name, PR_ValueString(pr_progstate[progs].globaldefs[def].type, (eval_t *)&pr_progstate[progs].globals[pr_progstate[progs].globaldefs[def].ofs])), 1, 0);
|
||||||
|
}
|
||||||
|
yofs+=8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
17
engine/qclib/progtype.h
Normal file
17
engine/qclib/progtype.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef DLL_PROG
|
||||||
|
|
||||||
|
#else
|
||||||
|
typedef float vec3_t[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef t_bool
|
||||||
|
#define t_bool
|
||||||
|
typedef int pbool;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define t_bool
|
||||||
|
#endif
|
||||||
|
typedef int progsnum_t;
|
||||||
|
typedef int func_t;
|
||||||
|
typedef char *string_t;
|
||||||
|
|
827
engine/qclib/qcc.h
Normal file
827
engine/qclib/qcc.h
Normal file
|
@ -0,0 +1,827 @@
|
||||||
|
#define COMPILER
|
||||||
|
#define PROGSUSED
|
||||||
|
|
||||||
|
//#define COMMONINLINES
|
||||||
|
//#define inline _inline
|
||||||
|
|
||||||
|
#include "cmdlib.h"
|
||||||
|
#include <setjmp.h>
|
||||||
|
/*
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <conio.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "pr_comp.h"
|
||||||
|
*/
|
||||||
|
|
||||||
|
//this is for testing
|
||||||
|
#define WRITEASM
|
||||||
|
|
||||||
|
#ifdef __MINGW32_VERSION
|
||||||
|
#define MINGW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define progfuncs qccprogfuncs
|
||||||
|
extern progfuncs_t *qccprogfuncs;
|
||||||
|
|
||||||
|
#if _WIN32 && !defined(MINGW)
|
||||||
|
#define inline _inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *qccHunkAlloc(size_t mem);
|
||||||
|
|
||||||
|
extern short (*BigShort) (short l);
|
||||||
|
extern short (*LittleShort) (short l);
|
||||||
|
extern long (*BigLong) (long l);
|
||||||
|
extern long (*LittleLong) (long l);
|
||||||
|
extern float (*BigFloat) (float l);
|
||||||
|
extern float (*LittleFloat) (float l);
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_ERRORS 10
|
||||||
|
|
||||||
|
#define MAX_NAME 64 // chars long
|
||||||
|
|
||||||
|
extern unsigned int MAX_REGS;
|
||||||
|
|
||||||
|
extern int MAX_STRINGS;
|
||||||
|
extern int MAX_GLOBALS;
|
||||||
|
extern int MAX_FIELDS;
|
||||||
|
extern int MAX_STATEMENTS;
|
||||||
|
extern int MAX_FUNCTIONS;
|
||||||
|
|
||||||
|
#define MAX_SOUNDS 1024 //convert to int?
|
||||||
|
#define MAX_TEXTURES 1024 //convert to int?
|
||||||
|
#define MAX_MODELS 1024 //convert to int?
|
||||||
|
#define MAX_FILES 1024 //convert to int?
|
||||||
|
#define MAX_DATA_PATH 64
|
||||||
|
|
||||||
|
extern int MAX_CONSTANTS;
|
||||||
|
#define MAXCONSTANTLENGTH 32
|
||||||
|
#define MAXCONSTANTVALUELENGTH 256
|
||||||
|
#define MAXCONSTANTPARAMLENGTH 32
|
||||||
|
#define MAXCONSTANTPARAMS 4
|
||||||
|
|
||||||
|
typedef enum {QCF_STANDARD, QCF_HEXEN2, QCF_FTE, QCF_FTE32, QCF_FTEDEBUG, QCF_FTEDEBUG32, QCF_KK7} qcc_targetformat_t;
|
||||||
|
extern qcc_targetformat_t qcc_targetformat;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
"stopped at 10 errors"
|
||||||
|
|
||||||
|
other pointer types for models and clients?
|
||||||
|
|
||||||
|
compact string heap?
|
||||||
|
|
||||||
|
allways initialize all variables to something safe
|
||||||
|
|
||||||
|
the def->type->type arrangement is really silly.
|
||||||
|
|
||||||
|
return type checking
|
||||||
|
|
||||||
|
parm count type checking
|
||||||
|
|
||||||
|
immediate overflow checking
|
||||||
|
|
||||||
|
pass the first two parms in call->b and call->c
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
comments
|
||||||
|
--------
|
||||||
|
// comments discard text until the end of line
|
||||||
|
/ * * / comments discard all enclosed text (spaced out on this line because this documentation is in a regular C comment block, and typing them in normally causes a parse error)
|
||||||
|
|
||||||
|
code structure
|
||||||
|
--------------
|
||||||
|
A definition is:
|
||||||
|
<type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
|
||||||
|
|
||||||
|
|
||||||
|
types
|
||||||
|
-----
|
||||||
|
simple types: void, float, vector, string, or entity
|
||||||
|
float width, height;
|
||||||
|
string name;
|
||||||
|
entity self, other;
|
||||||
|
|
||||||
|
vector types:
|
||||||
|
vector org; // also creates org_x, org_y, and org_z float defs
|
||||||
|
|
||||||
|
|
||||||
|
A function type is specified as: simpletype ( type name {,type name} )
|
||||||
|
The names are ignored except when the function is initialized.
|
||||||
|
void() think;
|
||||||
|
entity() FindTarget;
|
||||||
|
void(vector destination, float speed, void() callback) SUB_CalcMove;
|
||||||
|
void(...) dprint; // variable argument builtin
|
||||||
|
|
||||||
|
A field type is specified as: .type
|
||||||
|
.vector origin;
|
||||||
|
.string netname;
|
||||||
|
.void() think, touch, use;
|
||||||
|
|
||||||
|
|
||||||
|
names
|
||||||
|
-----
|
||||||
|
Names are a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9.
|
||||||
|
|
||||||
|
There are two levels of scoping: global, and function. The parameter list of a function and any vars declared inside a function with the "local" statement are only visible within that function,
|
||||||
|
|
||||||
|
|
||||||
|
immediates
|
||||||
|
----------
|
||||||
|
Float immediates must begin with 0-9 or minus sign. .5 is illegal.
|
||||||
|
|
||||||
|
A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Seperate the - from the digits with a space "a - 5" to get the proper behavior.
|
||||||
|
12
|
||||||
|
1.6
|
||||||
|
0.5
|
||||||
|
-100
|
||||||
|
|
||||||
|
Vector immediates are three float immediates enclosed in single quotes.
|
||||||
|
'0 0 0'
|
||||||
|
'20.5 -10 0.00001'
|
||||||
|
|
||||||
|
String immediates are characters enclosed in double quotes. The string cannot contain explicit newlines, but the escape character \n can embed one. The \" escape can be used to include a quote in the string.
|
||||||
|
"maps/jrwiz1.bsp"
|
||||||
|
"sound/nin/pain.wav"
|
||||||
|
"ouch!\n"
|
||||||
|
|
||||||
|
Code immediates are statements enclosed in {} braces.
|
||||||
|
statement:
|
||||||
|
{ <multiple statements> }
|
||||||
|
<expression>;
|
||||||
|
local <type> <name> [ = <immediate>] {, <name> [ = <immediate>] };
|
||||||
|
return <expression>;
|
||||||
|
if ( <expression> ) <statement> [ else <statement> ];
|
||||||
|
while ( <expression> ) <statement>;
|
||||||
|
do <statement> while ( <expression> );
|
||||||
|
<function name> ( <function parms> );
|
||||||
|
|
||||||
|
expression:
|
||||||
|
combiations of names and these operators with standard C precedence:
|
||||||
|
"&&", "||", "<=", ">=","==", "!=", "!", "*", "/", "-", "+", "=", ".", "<", ">", "&", "|"
|
||||||
|
Parenthesis can be used to alter order of operation.
|
||||||
|
The & and | operations perform integral bit ops on floats
|
||||||
|
|
||||||
|
A built in function immediate is a number sign followed by an integer.
|
||||||
|
#1
|
||||||
|
#12
|
||||||
|
|
||||||
|
|
||||||
|
compilation
|
||||||
|
-----------
|
||||||
|
Source files are processed sequentially without dumping any state, so if a defs file is the first one processed, the definitions will be available to all other files.
|
||||||
|
|
||||||
|
The language is strongly typed and there are no casts.
|
||||||
|
|
||||||
|
Anything that is initialized is assumed to be constant, and will have immediates folded into it. If you change the value, your program will malfunction. All uninitialized globals will be saved to savegame files.
|
||||||
|
|
||||||
|
Functions cannot have more than eight parameters.
|
||||||
|
|
||||||
|
Error recovery during compilation is minimal. It will skip to the next global definition, so you will never see more than one error at a time in a given function. All compilation aborts after ten error messages.
|
||||||
|
|
||||||
|
Names can be defined multiple times until they are defined with an initialization, allowing functions to be prototyped before their definition.
|
||||||
|
|
||||||
|
void() MyFunction; // the prototype
|
||||||
|
|
||||||
|
void() MyFunction = // the initialization
|
||||||
|
{
|
||||||
|
dprint ("we're here\n");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
entities and fields
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
|
||||||
|
execution
|
||||||
|
---------
|
||||||
|
Code execution is initiated by C code in quake from two main places: the timed think routines for periodic control, and the touch function when two objects impact each other.
|
||||||
|
|
||||||
|
There are three global variables that are set before beginning code execution:
|
||||||
|
entity world; // the server's world object, which holds all global
|
||||||
|
// state for the server, like the deathmatch flags
|
||||||
|
// and the body ques.
|
||||||
|
entity self; // the entity the function is executing for
|
||||||
|
entity other; // the other object in an impact, not used for thinks
|
||||||
|
float time; // the current game time. Note that because the
|
||||||
|
// entities in the world are simulated sequentially,
|
||||||
|
// time is NOT strictly increasing. An impact late
|
||||||
|
// in one entity's time slice may set time higher
|
||||||
|
// than the think function of the next entity.
|
||||||
|
// The difference is limited to 0.1 seconds.
|
||||||
|
Execution is also caused by a few uncommon events, like the addition of a new client to an existing server.
|
||||||
|
|
||||||
|
There is a runnaway counter that stops a program if 100000 statements are executed, assuming it is in an infinite loop.
|
||||||
|
|
||||||
|
It is acceptable to change the system set global variables. This is usually done to pose as another entity by changing self and calling a function.
|
||||||
|
|
||||||
|
The interpretation is fairly efficient, but it is still over an order of magnitude slower than compiled C code. All time consuming operations should be made into built in functions.
|
||||||
|
|
||||||
|
A profile counter is kept for each function, and incremented for each interpreted instruction inside that function. The "profile" console command in Quake will dump out the top 10 functions, then clear all the counters. The "profile all" command will dump sorted stats for every function that has been executed.
|
||||||
|
|
||||||
|
|
||||||
|
afunc ( 4, bfunc(1,2,3));
|
||||||
|
will fail because there is a shared parameter marshaling area, which will cause the 1 from bfunc to overwrite the 4 allready placed in parm0. When a function is called, it copies the parms from the globals into it's privately scoped variables, so there is no collision when calling another function.
|
||||||
|
|
||||||
|
total = factorial(3) + factorial(4);
|
||||||
|
Will fail because the return value from functions is held in a single global area. If this really gets on your nerves, tell me and I can work around it at a slight performance and space penalty by allocating a new register for the function call and copying it out.
|
||||||
|
|
||||||
|
|
||||||
|
built in functions
|
||||||
|
------------------
|
||||||
|
void(string text) dprint;
|
||||||
|
Prints the string to the server console.
|
||||||
|
|
||||||
|
void(entity client, string text) cprint;
|
||||||
|
Prints a message to a specific client.
|
||||||
|
|
||||||
|
void(string text) bprint;
|
||||||
|
Broadcast prints a message to all clients on the current server.
|
||||||
|
|
||||||
|
entity() spawn;
|
||||||
|
Returns a totally empty entity. You can manually set everything up, or just set the origin and call one of the existing entity setup functions.
|
||||||
|
|
||||||
|
entity(entity start, .string field, string match) find;
|
||||||
|
Searches the server entity list beginning at start, looking for an entity that has entity.field = match. To start at the beginning of the list, pass world. World is returned when the end of the list is reached.
|
||||||
|
|
||||||
|
<FIXME: define all the other functions...>
|
||||||
|
|
||||||
|
|
||||||
|
gotchas
|
||||||
|
-------
|
||||||
|
|
||||||
|
The && and || operators DO NOT EARLY OUT like C!
|
||||||
|
|
||||||
|
Don't confuse single quoted vectors with double quoted strings
|
||||||
|
|
||||||
|
The function declaration syntax takes a little getting used to.
|
||||||
|
|
||||||
|
Don't forget the ; after the trailing brace of a function initialization.
|
||||||
|
|
||||||
|
Don't forget the "local" before defining local variables.
|
||||||
|
|
||||||
|
There are no ++ / -- operators, or operate/assign operators.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#include "hash.h"
|
||||||
|
extern hashtable_t compconstantstable;
|
||||||
|
extern hashtable_t globalstable, localstable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WRITEASM
|
||||||
|
FILE *asmfile;
|
||||||
|
#endif
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
// offsets are allways multiplied by 4 before using
|
||||||
|
typedef unsigned int gofs_t; // offset in global data block
|
||||||
|
typedef struct QCC_function_s QCC_function_t;
|
||||||
|
|
||||||
|
#define MAX_PARMS 8
|
||||||
|
|
||||||
|
typedef struct QCC_type_s
|
||||||
|
{
|
||||||
|
etype_t type;
|
||||||
|
|
||||||
|
struct QCC_type_s *parentclass; //type_entity...
|
||||||
|
struct QCC_type_s *next;
|
||||||
|
// function types are more complex
|
||||||
|
struct QCC_type_s *aux_type; // return type or field type
|
||||||
|
struct QCC_type_s *param;
|
||||||
|
int num_parms; // -1 = variable args
|
||||||
|
// struct QCC_type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated
|
||||||
|
|
||||||
|
unsigned int ofs; //inside a structure.
|
||||||
|
unsigned int size;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
} QCC_type_t;
|
||||||
|
int typecmp(QCC_type_t *a, QCC_type_t *b);
|
||||||
|
|
||||||
|
typedef struct temp_s {
|
||||||
|
gofs_t ofs;
|
||||||
|
struct QCC_def_s *scope;
|
||||||
|
#ifdef WRITEASM
|
||||||
|
struct QCC_def_s *lastfunc;
|
||||||
|
#endif
|
||||||
|
struct temp_s *next;
|
||||||
|
pbool used;
|
||||||
|
unsigned int size;
|
||||||
|
} temp_t;
|
||||||
|
|
||||||
|
//not written
|
||||||
|
typedef struct QCC_def_s
|
||||||
|
{
|
||||||
|
QCC_type_t *type;
|
||||||
|
char *name;
|
||||||
|
struct QCC_def_s *next;
|
||||||
|
struct QCC_def_s *nextlocal; //provides a chain of local variables for the opt_locals_marshalling optimisation.
|
||||||
|
gofs_t ofs;
|
||||||
|
struct QCC_def_s *scope; // function the var was defined in, or NULL
|
||||||
|
int initialized; // 1 when a declaration included "= immediate"
|
||||||
|
int constant; // 1 says we can use the value over and over again
|
||||||
|
|
||||||
|
int references;
|
||||||
|
int timescalled; //part of the opt_stripfunctions optimisation.
|
||||||
|
|
||||||
|
int s_file;
|
||||||
|
int s_line;
|
||||||
|
|
||||||
|
int arraysize;
|
||||||
|
pbool shared;
|
||||||
|
pbool saved;
|
||||||
|
|
||||||
|
temp_t *temp;
|
||||||
|
} QCC_def_t;
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
// pr_loc.h -- program local defs
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
extern char QCC_copyright[1024];
|
||||||
|
extern char QCC_Packname[5][128];
|
||||||
|
extern int QCC_packid;
|
||||||
|
|
||||||
|
typedef union QCC_eval_s
|
||||||
|
{
|
||||||
|
QCC_string_t string;
|
||||||
|
float _float;
|
||||||
|
float vector[3];
|
||||||
|
func_t function;
|
||||||
|
int _int;
|
||||||
|
union QCC_eval_s *ptr;
|
||||||
|
} QCC_eval_t;
|
||||||
|
|
||||||
|
const extern int type_size[9];
|
||||||
|
//extern QCC_def_t *def_for_type[9];
|
||||||
|
|
||||||
|
extern QCC_type_t *type_void, *type_string, *type_float, *type_vector, *type_entity, *type_field, *type_function, *type_pointer, *type_integer, *type_floatfield;
|
||||||
|
|
||||||
|
struct QCC_function_s
|
||||||
|
{
|
||||||
|
int builtin; // if non 0, call an internal function
|
||||||
|
int code; // first statement
|
||||||
|
char *file; // source file with definition
|
||||||
|
int file_line;
|
||||||
|
struct QCC_def_s *def;
|
||||||
|
unsigned int parm_ofs[MAX_PARMS]; // allways contiguous, right?
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// output generated by prog parsing
|
||||||
|
//
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *memory;
|
||||||
|
int max_memory;
|
||||||
|
int current_memory;
|
||||||
|
QCC_type_t *types;
|
||||||
|
|
||||||
|
QCC_def_t def_head; // unused head of linked list
|
||||||
|
QCC_def_t *def_tail; // add new defs after this and move it
|
||||||
|
QCC_def_t *localvars; // chain of variables which need to be pushed and stuff.
|
||||||
|
|
||||||
|
int size_fields;
|
||||||
|
} QCC_pr_info_t;
|
||||||
|
|
||||||
|
extern QCC_pr_info_t pr;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char name[MAXCONSTANTLENGTH];
|
||||||
|
char value[MAXCONSTANTVALUELENGTH];
|
||||||
|
char params[MAXCONSTANTPARAMS][MAXCONSTANTPARAMLENGTH];
|
||||||
|
int numparams;
|
||||||
|
pbool used;
|
||||||
|
|
||||||
|
int namelen;
|
||||||
|
} CompilerConstant_t;
|
||||||
|
extern CompilerConstant_t *CompilerConstant;
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
extern pbool pr_dumpasm;
|
||||||
|
|
||||||
|
//extern QCC_def_t **pr_global_defs; // to find def for a global variable
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
tt_eof, // end of file reached
|
||||||
|
tt_name, // an alphanumeric name token
|
||||||
|
tt_punct, // code punctuation
|
||||||
|
tt_immediate, // string, float, vector
|
||||||
|
} token_type_t;
|
||||||
|
|
||||||
|
extern char pr_token[8192];
|
||||||
|
extern token_type_t pr_token_type;
|
||||||
|
extern QCC_type_t *pr_immediate_type;
|
||||||
|
extern QCC_eval_t pr_immediate;
|
||||||
|
|
||||||
|
extern pbool keyword_var;
|
||||||
|
extern pbool keyword_thinktime;
|
||||||
|
extern pbool keyword_switch;
|
||||||
|
extern pbool keyword_for;
|
||||||
|
extern pbool keyword_case;
|
||||||
|
extern pbool keyword_default;
|
||||||
|
extern pbool keyword_do;
|
||||||
|
extern pbool keyword_asm;
|
||||||
|
extern pbool keyword_goto;
|
||||||
|
extern pbool keyword_break;
|
||||||
|
extern pbool keyword_continue;
|
||||||
|
extern pbool keyword_state;
|
||||||
|
extern pbool keyword_string;
|
||||||
|
extern pbool keyword_float;
|
||||||
|
extern pbool keyword_entity;
|
||||||
|
extern pbool keyword_vector;
|
||||||
|
extern pbool keyword_integer;
|
||||||
|
extern pbool keyword_int;
|
||||||
|
extern pbool keyword_const;
|
||||||
|
extern pbool keyword_class;
|
||||||
|
|
||||||
|
extern pbool keywords_coexist;
|
||||||
|
extern pbool output_parms;
|
||||||
|
extern pbool autoprototype;
|
||||||
|
|
||||||
|
extern pbool opt_overlaptemps;
|
||||||
|
extern pbool opt_shortenifnots;
|
||||||
|
extern pbool opt_noduplicatestrings;
|
||||||
|
extern pbool opt_constantarithmatic;
|
||||||
|
extern pbool opt_nonvec_parms;
|
||||||
|
extern pbool opt_constant_names;
|
||||||
|
extern pbool opt_precache_file;
|
||||||
|
extern pbool opt_filenames;
|
||||||
|
extern pbool opt_assignments;
|
||||||
|
extern pbool opt_unreferenced;
|
||||||
|
extern pbool opt_function_names;
|
||||||
|
extern pbool opt_locals;
|
||||||
|
extern pbool opt_dupconstdefs;
|
||||||
|
extern pbool opt_constant_names_strings;
|
||||||
|
extern pbool opt_return_only;
|
||||||
|
extern pbool opt_compound_jumps;
|
||||||
|
//extern pbool opt_comexprremoval;
|
||||||
|
extern pbool opt_stripfunctions;
|
||||||
|
extern pbool opt_locals_marshalling;
|
||||||
|
extern pbool opt_logicops;
|
||||||
|
|
||||||
|
extern int optres_shortenifnots;
|
||||||
|
extern int optres_overlaptemps;
|
||||||
|
extern int optres_noduplicatestrings;
|
||||||
|
extern int optres_constantarithmatic;
|
||||||
|
extern int optres_nonvec_parms;
|
||||||
|
extern int optres_constant_names;
|
||||||
|
extern int optres_precache_file;
|
||||||
|
extern int optres_filenames;
|
||||||
|
extern int optres_assignments;
|
||||||
|
extern int optres_unreferenced;
|
||||||
|
extern int optres_function_names;
|
||||||
|
extern int optres_locals;
|
||||||
|
extern int optres_dupconstdefs;
|
||||||
|
extern int optres_constant_names_strings;
|
||||||
|
extern int optres_return_only;
|
||||||
|
extern int optres_compound_jumps;
|
||||||
|
//extern int optres_comexprremoval;
|
||||||
|
extern int optres_stripfunctions;
|
||||||
|
extern int optres_locals_marshalling;
|
||||||
|
extern int optres_logicops;
|
||||||
|
|
||||||
|
pbool CompileParams(progfuncs_t *progfuncs, int doall, int nump, char **parms);
|
||||||
|
|
||||||
|
void QCC_PR_PrintStatement (QCC_dstatement_t *s);
|
||||||
|
|
||||||
|
void QCC_PR_Lex (void);
|
||||||
|
// reads the next token into pr_token and classifies its type
|
||||||
|
|
||||||
|
QCC_type_t *QCC_PR_ParseType (int newtype);
|
||||||
|
QCC_type_t *QCC_TypeForName(char *name);
|
||||||
|
QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype);
|
||||||
|
char *QCC_PR_ParseName (void);
|
||||||
|
CompilerConstant_t *QCC_PR_DefineName(char *name);
|
||||||
|
|
||||||
|
void QCC_RemapOffsets(unsigned int firststatement, unsigned int laststatement, unsigned int min, unsigned int max, unsigned int newmin);
|
||||||
|
|
||||||
|
#ifndef COMMONINLINES
|
||||||
|
pbool QCC_PR_Check (char *string);
|
||||||
|
void QCC_PR_Expect (char *string);
|
||||||
|
#endif
|
||||||
|
void VARGS QCC_PR_ParseError (int errortype, char *error, ...);
|
||||||
|
void VARGS QCC_PR_ParseWarning (int warningtype, char *error, ...);
|
||||||
|
void VARGS QCC_PR_Warning (int type, char *file, int line, char *error, ...);
|
||||||
|
void QCC_PR_ParsePrintDef (int warningtype, QCC_def_t *def);
|
||||||
|
void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, char *error, ...);
|
||||||
|
|
||||||
|
//QccMain.c must be changed if this is changed.
|
||||||
|
enum {
|
||||||
|
WARN_DEBUGGING,
|
||||||
|
WARN_ERROR,
|
||||||
|
WARN_NOTREFERENCED,
|
||||||
|
WARN_NOTREFERENCEDCONST,
|
||||||
|
WARN_CONFLICTINGRETURNS,
|
||||||
|
WARN_TOOFEWPARAMS,
|
||||||
|
WARN_TOOMANYPARAMS,
|
||||||
|
WARN_UNEXPECTEDPUNCT,
|
||||||
|
WARN_ASSIGNMENTTOCONSTANT,
|
||||||
|
WARN_MISSINGRETURNVALUE,
|
||||||
|
WARN_WRONGRETURNTYPE,
|
||||||
|
WARN_POINTLESSSTATEMENT,
|
||||||
|
WARN_MISSINGRETURN,
|
||||||
|
WARN_DUPLICATEDEFINITION,
|
||||||
|
WARN_PRECOMPILERMESSAGE,
|
||||||
|
WARN_STRINGTOOLONG,
|
||||||
|
WARN_BADTARGET,
|
||||||
|
WARN_BADPRAGMA,
|
||||||
|
WARN_HANGINGSLASHR,
|
||||||
|
WARN_NOTDEFINED,
|
||||||
|
WARN_SWITCHTYPEMISMATCH,
|
||||||
|
WARN_CONFLICTINGUNIONMEMBER,
|
||||||
|
WARN_KEYWORDDISABLED,
|
||||||
|
WARN_ENUMFLAGS_NOTINTEGER,
|
||||||
|
WARN_ENUMFLAGS_NOTBINARY,
|
||||||
|
WARN_CASEINSENSATIVEFRAMEMACRO,
|
||||||
|
WARN_DUPLICATELABEL,
|
||||||
|
WARN_ASSIGNMENTINCONDITIONAL,
|
||||||
|
WARN_MACROINSTRING,
|
||||||
|
WARN_BADPARAMS,
|
||||||
|
WARN_IMPLICITCONVERSION,
|
||||||
|
WARN_FIXEDRETURNVALUECONFLICT,
|
||||||
|
WARN_EXTRAPRECACHE,
|
||||||
|
WARN_NOTPRECACHED,
|
||||||
|
WARN_DEADCODE,
|
||||||
|
|
||||||
|
ERR_PARSEERRORS, //caused by qcc_pr_parseerror beung called.
|
||||||
|
|
||||||
|
//these are definatly my fault...
|
||||||
|
ERR_INTERNAL,
|
||||||
|
ERR_TOOCOMPLEX,
|
||||||
|
ERR_BADOPCODE,
|
||||||
|
ERR_TOOMANYSTATEMENTS,
|
||||||
|
ERR_TOOMANYSTRINGS,
|
||||||
|
ERR_BADTARGETSWITCH,
|
||||||
|
ERR_TOOMANYTYPES,
|
||||||
|
ERR_TOOMANYPAKFILES,
|
||||||
|
ERR_PRECOMPILERCONSTANTTOOLONG,
|
||||||
|
ERR_MACROTOOMANYPARMS,
|
||||||
|
ERR_CONSTANTTOOLONG,
|
||||||
|
ERR_TOOMANYFRAMEMACROS,
|
||||||
|
|
||||||
|
//limitations, some are imposed by compiler, some arn't.
|
||||||
|
ERR_TOOMANYGLOBALS,
|
||||||
|
ERR_TOOMANYGOTOS,
|
||||||
|
ERR_TOOMANYBREAKS,
|
||||||
|
ERR_TOOMANYCONTINUES,
|
||||||
|
ERR_TOOMANYCASES,
|
||||||
|
ERR_TOOMANYLABELS,
|
||||||
|
ERR_TOOMANYOPENFILES,
|
||||||
|
ERR_TOOMANYPARAMETERSVARARGS,
|
||||||
|
ERR_TOOMANYPARAMETERSFORFUNC,
|
||||||
|
ERR_TOOMANYTOTALPARAMETERS,
|
||||||
|
|
||||||
|
//these are probably yours, or qcc being fussy.
|
||||||
|
ERR_BADEXTENSION,
|
||||||
|
ERR_BADIMMEDIATETYPE,
|
||||||
|
ERR_NOOUTPUT,
|
||||||
|
ERR_NOTAFUNCTION,
|
||||||
|
ERR_BADHEX,
|
||||||
|
ERR_UNKNOWNPUCTUATION,
|
||||||
|
ERR_EXPECTED,
|
||||||
|
ERR_NOTANAME,
|
||||||
|
ERR_NAMETOOLONG,
|
||||||
|
ERR_NOFUNC,
|
||||||
|
ERR_COULDNTOPENFILE,
|
||||||
|
ERR_NOTFUNCTIONTYPE,
|
||||||
|
ERR_TOOFEWPARAMS,
|
||||||
|
ERR_TOOMANYPARAMS,
|
||||||
|
ERR_CONSTANTNOTDEFINED,
|
||||||
|
ERR_BADFRAMEMACRO,
|
||||||
|
ERR_TYPEMISMATCH,
|
||||||
|
ERR_TYPEMISMATCHREDEC,
|
||||||
|
ERR_TYPEMISMATCHPARM,
|
||||||
|
ERR_TYPEMISMATCHARRAYSIZE,
|
||||||
|
ERR_UNEXPECTEDPUNCTUATION,
|
||||||
|
ERR_NOTACONSTANT,
|
||||||
|
ERR_REDECLARATION,
|
||||||
|
ERR_INITIALISEDLOCALFUNCTION,
|
||||||
|
ERR_NOTDEFINED,
|
||||||
|
ERR_ARRAYNEEDSSIZE,
|
||||||
|
ERR_ARRAYNEEDSBRACES,
|
||||||
|
ERR_TOOMANYINITIALISERS,
|
||||||
|
ERR_TYPEINVALIDINSTRUCT,
|
||||||
|
ERR_NOSHAREDLOCALS,
|
||||||
|
ERR_TYPEWITHNONAME,
|
||||||
|
ERR_BADARRAYSIZE,
|
||||||
|
ERR_NONAME,
|
||||||
|
ERR_SHAREDINITIALISED,
|
||||||
|
ERR_UNKNOWNVALUE,
|
||||||
|
ERR_BADARRAYINDEXTYPE,
|
||||||
|
ERR_NOVALIDOPCODES,
|
||||||
|
ERR_MEMBERNOTVALID,
|
||||||
|
ERR_BADPLUSPLUSOPERATOR,
|
||||||
|
ERR_BADNOTTYPE,
|
||||||
|
ERR_BADTYPECAST,
|
||||||
|
ERR_MULTIPLEDEFAULTS,
|
||||||
|
ERR_CASENOTIMMEDIATE,
|
||||||
|
ERR_BADSWITCHTYPE,
|
||||||
|
ERR_BADLABELNAME,
|
||||||
|
ERR_NOLABEL,
|
||||||
|
ERR_THINKTIMETYPEMISMATCH,
|
||||||
|
ERR_STATETYPEMISMATCH,
|
||||||
|
ERR_BADBUILTINIMMEDIATE,
|
||||||
|
ERR_PARAMWITHNONAME,
|
||||||
|
ERR_BADPARAMORDER,
|
||||||
|
ERR_ILLEGALCONTINUES,
|
||||||
|
ERR_ILLEGALBREAKS,
|
||||||
|
ERR_ILLEGALCASES,
|
||||||
|
ERR_NOTANUMBER,
|
||||||
|
ERR_WRONGSUBTYPE,
|
||||||
|
ERR_EOF,
|
||||||
|
ERR_NOPRECOMPILERIF,
|
||||||
|
ERR_HASHERROR,
|
||||||
|
ERR_NOTATYPE,
|
||||||
|
ERR_TOOMANYPACKFILES,
|
||||||
|
ERR_INVALIDVECTORIMMEDIATE,
|
||||||
|
ERR_INVALIDSTRINGIMMEDIATE,
|
||||||
|
ERR_BADCHARACTURECODE,
|
||||||
|
ERR_BADPARMS,
|
||||||
|
|
||||||
|
WARN_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pbool *enabled;
|
||||||
|
char *abbrev;
|
||||||
|
int optimisationlevel;
|
||||||
|
int flags; //1: kills debuggers. 2: applied as default.
|
||||||
|
char *fullname;
|
||||||
|
void *guiinfo;
|
||||||
|
} optimisations_t;
|
||||||
|
extern optimisations_t optimisations[];
|
||||||
|
|
||||||
|
extern pbool qccwarningdisabled[WARN_MAX];
|
||||||
|
|
||||||
|
extern jmp_buf pr_parse_abort; // longjump with this on parse error
|
||||||
|
extern int pr_source_line;
|
||||||
|
extern char *pr_file_p;
|
||||||
|
|
||||||
|
void *QCC_PR_Malloc (int size);
|
||||||
|
|
||||||
|
|
||||||
|
#define OFS_NULL 0
|
||||||
|
#define OFS_RETURN 1
|
||||||
|
#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors
|
||||||
|
#define OFS_PARM1 7
|
||||||
|
#define OFS_PARM2 10
|
||||||
|
#define OFS_PARM3 13
|
||||||
|
#define OFS_PARM4 16
|
||||||
|
#define RESERVED_OFS 28
|
||||||
|
|
||||||
|
|
||||||
|
extern QCC_def_t *pr_scope;
|
||||||
|
extern int pr_error_count;
|
||||||
|
|
||||||
|
void QCC_PR_NewLine (pbool incomment);
|
||||||
|
QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, char *name, QCC_def_t *scope, pbool allocate, int arraysize);
|
||||||
|
|
||||||
|
void QCC_PR_PrintDefs (void);
|
||||||
|
|
||||||
|
void QCC_PR_SkipToSemicolon (void);
|
||||||
|
|
||||||
|
#define MAX_EXTRA_PARMS 128
|
||||||
|
#ifdef MAX_EXTRA_PARMS
|
||||||
|
extern char pr_parm_names[MAX_PARMS+MAX_EXTRA_PARMS][MAX_NAME];
|
||||||
|
extern QCC_def_t *extra_parms[MAX_EXTRA_PARMS];
|
||||||
|
#else
|
||||||
|
extern char pr_parm_names[MAX_PARMS][MAX_NAME];
|
||||||
|
#endif
|
||||||
|
extern pbool pr_trace;
|
||||||
|
|
||||||
|
#define G_FLOAT(o) (qcc_pr_globals[o])
|
||||||
|
#define G_INT(o) (*(int *)&qcc_pr_globals[o])
|
||||||
|
#define G_VECTOR(o) (&qcc_pr_globals[o])
|
||||||
|
#define G_STRING(o) (strings + *(QCC_string_t *)&qcc_pr_globals[o])
|
||||||
|
#define G_FUNCTION(o) (*(func_t *)&qcc_pr_globals[o])
|
||||||
|
|
||||||
|
char *QCC_PR_ValueString (etype_t type, void *val);
|
||||||
|
|
||||||
|
void QCC_PR_ClearGrabMacros (void);
|
||||||
|
|
||||||
|
pbool QCC_PR_CompileFile (char *string, char *filename);
|
||||||
|
|
||||||
|
extern pbool pr_dumpasm;
|
||||||
|
|
||||||
|
extern QCC_string_t s_file; // filename for function definition
|
||||||
|
|
||||||
|
extern QCC_def_t def_ret, def_parms[MAX_PARMS];
|
||||||
|
|
||||||
|
func_t QCC_PR_EmitArrayGetFunction(char *arrayname);
|
||||||
|
func_t QCC_PR_EmitArraySetFunction(char *arrayname);
|
||||||
|
int QCC_PR_EmitClassFromFunction(QCC_def_t *scope, char *tname);
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
extern char pr_immediate_string[8192];
|
||||||
|
|
||||||
|
extern float *qcc_pr_globals;
|
||||||
|
extern unsigned int numpr_globals;
|
||||||
|
|
||||||
|
extern char *strings;
|
||||||
|
extern int strofs;
|
||||||
|
|
||||||
|
extern QCC_dstatement_t *statements;
|
||||||
|
extern int numstatements;
|
||||||
|
extern int *statement_linenums;
|
||||||
|
|
||||||
|
extern QCC_dfunction_t *functions;
|
||||||
|
extern int numfunctions;
|
||||||
|
|
||||||
|
extern QCC_ddef_t *qcc_globals;
|
||||||
|
extern int numglobaldefs;
|
||||||
|
|
||||||
|
extern QCC_def_t *activetemps;
|
||||||
|
|
||||||
|
extern QCC_ddef_t *fields;
|
||||||
|
extern int numfielddefs;
|
||||||
|
|
||||||
|
extern QCC_type_t *qcc_typeinfo;
|
||||||
|
extern int numtypeinfos;
|
||||||
|
extern int maxtypeinfos;
|
||||||
|
|
||||||
|
extern int *qcc_tempofs;
|
||||||
|
extern int max_temps;
|
||||||
|
//extern int qcc_functioncalled; //unuse temps if this is true - don't want to reuse the same space.
|
||||||
|
|
||||||
|
extern int tempsstart;
|
||||||
|
extern int numtemps;
|
||||||
|
|
||||||
|
typedef char PATHSTRING[MAX_DATA_PATH];
|
||||||
|
|
||||||
|
PATHSTRING *precache_sounds;
|
||||||
|
int *precache_sounds_block;
|
||||||
|
int *precache_sounds_used;
|
||||||
|
int numsounds;
|
||||||
|
|
||||||
|
PATHSTRING *precache_textures;
|
||||||
|
int *precache_textures_block;
|
||||||
|
int numtextures;
|
||||||
|
|
||||||
|
PATHSTRING *precache_models;
|
||||||
|
int *precache_models_block;
|
||||||
|
int *precache_models_used;
|
||||||
|
int nummodels;
|
||||||
|
|
||||||
|
PATHSTRING *precache_files;
|
||||||
|
int *precache_files_block;
|
||||||
|
int numfiles;
|
||||||
|
|
||||||
|
int QCC_CopyString (char *str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct qcc_cachedsourcefile_s {
|
||||||
|
char filename[128];
|
||||||
|
int size;
|
||||||
|
char *file;
|
||||||
|
enum{FT_CODE, FT_DATA} type; //quakec source file or not.
|
||||||
|
struct qcc_cachedsourcefile_s *next;
|
||||||
|
} qcc_cachedsourcefile_t;
|
||||||
|
extern qcc_cachedsourcefile_t *qcc_sourcefile;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef COMMONINLINES
|
||||||
|
bool inline QCC_PR_Check (char *string)
|
||||||
|
{
|
||||||
|
if (strcmp (string, pr_token))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QCC_PR_Lex ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline QCC_PR_Expect (char *string)
|
||||||
|
{
|
||||||
|
if (strcmp (string, pr_token))
|
||||||
|
QCC_PR_ParseError ("expected %s, found %s",string, pr_token);
|
||||||
|
QCC_PR_Lex ();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void editbadfile(char *fname, int line);
|
||||||
|
char *TypeName(QCC_type_t *type);
|
||||||
|
void QCC_PR_IncludeChunk (char *data, pbool duplicate, char *filename);
|
804
engine/qclib/qcc_cmdlib.c
Normal file
804
engine/qclib/qcc_cmdlib.c
Normal file
|
@ -0,0 +1,804 @@
|
||||||
|
// cmdlib.c
|
||||||
|
|
||||||
|
#include "qcc.h"
|
||||||
|
//#include <sys/time.h>
|
||||||
|
|
||||||
|
#define PATHSEPERATOR '/'
|
||||||
|
|
||||||
|
#ifndef QCC
|
||||||
|
extern jmp_buf qcccompileerror;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set these before calling CheckParm
|
||||||
|
int myargc;
|
||||||
|
char **myargv;
|
||||||
|
|
||||||
|
char qcc_token[1024];
|
||||||
|
int qcc_eof;
|
||||||
|
|
||||||
|
#ifndef MINIMAL
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
I_FloatTime
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
double I_FloatTime (void)
|
||||||
|
{
|
||||||
|
struct timeval tp;
|
||||||
|
struct timezone tzp;
|
||||||
|
static int secbase;
|
||||||
|
|
||||||
|
gettimeofday(&tp, &tzp);
|
||||||
|
|
||||||
|
if (!secbase)
|
||||||
|
{
|
||||||
|
secbase = tp.tv_sec;
|
||||||
|
return tp.tv_usec/1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef QCC
|
||||||
|
int QC_strncasecmp (const char *s1, const char *s2, int n)
|
||||||
|
{
|
||||||
|
int c1, c2;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
c1 = *s1++;
|
||||||
|
c2 = *s2++;
|
||||||
|
|
||||||
|
if (!n--)
|
||||||
|
return 0; // strings are equal until end point
|
||||||
|
|
||||||
|
if (c1 != c2)
|
||||||
|
{
|
||||||
|
if (c1 >= 'a' && c1 <= 'z')
|
||||||
|
c1 -= ('a' - 'A');
|
||||||
|
if (c2 >= 'a' && c2 <= 'z')
|
||||||
|
c2 -= ('a' - 'A');
|
||||||
|
if (c1 != c2)
|
||||||
|
return -1; // strings not equal
|
||||||
|
}
|
||||||
|
if (!c1)
|
||||||
|
return 0; // strings are equal
|
||||||
|
// s1++;
|
||||||
|
// s2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QC_strcasecmp (const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
return QC_strncasecmp(s1, s2, 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int QC_strncasecmp(const char *s1, const char *s2, int n);
|
||||||
|
int QC_strcasecmp (const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
return QC_strncasecmp(s1, s2, 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //minimal
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
COM_Parse
|
||||||
|
|
||||||
|
Parse a token out of a string
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
char *QCC_COM_Parse (char *data)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
qcc_token[0] = 0;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// skip whitespace
|
||||||
|
skipwhite:
|
||||||
|
while ( (c = *data) <= ' ')
|
||||||
|
{
|
||||||
|
if (c == 0)
|
||||||
|
{
|
||||||
|
qcc_eof = true;
|
||||||
|
return NULL; // end of file;
|
||||||
|
}
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip // comments
|
||||||
|
if (c=='/' && data[1] == '/')
|
||||||
|
{
|
||||||
|
while (*data && *data != '\n')
|
||||||
|
data++;
|
||||||
|
goto skipwhite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// handle quoted strings specially
|
||||||
|
if (c == '\"')
|
||||||
|
{
|
||||||
|
data++;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = *data++;
|
||||||
|
if (c=='\"'||c=='\0')
|
||||||
|
{
|
||||||
|
qcc_token[len] = 0;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
qcc_token[len] = c;
|
||||||
|
len++;
|
||||||
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse single characters
|
||||||
|
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
|
||||||
|
{
|
||||||
|
qcc_token[len] = c;
|
||||||
|
len++;
|
||||||
|
qcc_token[len] = 0;
|
||||||
|
return data+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse a regular word
|
||||||
|
do
|
||||||
|
{
|
||||||
|
qcc_token[len] = c;
|
||||||
|
data++;
|
||||||
|
len++;
|
||||||
|
c = *data;
|
||||||
|
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':' || c=='\"')
|
||||||
|
break;
|
||||||
|
} while (c>32);
|
||||||
|
|
||||||
|
qcc_token[len] = 0;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *VARGS qcva (char *text, ...)
|
||||||
|
{
|
||||||
|
va_list argptr;
|
||||||
|
static char msg[2048];
|
||||||
|
|
||||||
|
va_start (argptr,text);
|
||||||
|
QC_vsnprintf (msg,sizeof(msg)-1, text,argptr);
|
||||||
|
va_end (argptr);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MINIMAL
|
||||||
|
|
||||||
|
char *QC_strupr (char *start)
|
||||||
|
{
|
||||||
|
char *in;
|
||||||
|
in = start;
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
*in = toupper(*in);
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *QC_strlower (char *start)
|
||||||
|
{
|
||||||
|
char *in;
|
||||||
|
in = start;
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
*in = tolower(*in);
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
MISC FUNCTIONS
|
||||||
|
|
||||||
|
=============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Error
|
||||||
|
|
||||||
|
For abnormal program terminations
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void VARGS QCC_Error (int errortype, const char *error, ...)
|
||||||
|
{
|
||||||
|
va_list argptr;
|
||||||
|
char msg[2048];
|
||||||
|
|
||||||
|
va_start (argptr,error);
|
||||||
|
QC_vsnprintf (msg,sizeof(msg)-1, error,argptr);
|
||||||
|
va_end (argptr);
|
||||||
|
|
||||||
|
printf ("\n************ ERROR ************\n%s\n", msg);
|
||||||
|
|
||||||
|
|
||||||
|
editbadfile(strings+s_file, pr_source_line);
|
||||||
|
|
||||||
|
#ifndef QCC
|
||||||
|
longjmp(qcccompileerror, 1);
|
||||||
|
#else
|
||||||
|
print ("Press any key\n");
|
||||||
|
getch();
|
||||||
|
#endif
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
CheckParm
|
||||||
|
|
||||||
|
Checks for the given parameter in the program's command line arguments
|
||||||
|
Returns the argument number (1 to argc-1) or 0 if not present
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
int QCC_CheckParm (char *check)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1;i<myargc;i++)
|
||||||
|
{
|
||||||
|
if ( !QC_strcasecmp(check, myargv[i]) )
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef O_BINARY
|
||||||
|
#define O_BINARY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef QCC
|
||||||
|
int SafeOpenWrite (char *filename)
|
||||||
|
{
|
||||||
|
int handle;
|
||||||
|
|
||||||
|
umask (0);
|
||||||
|
|
||||||
|
handle = open(filename,O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
|
||||||
|
, 0666);
|
||||||
|
|
||||||
|
if (handle == -1)
|
||||||
|
QCC_Error ("Error opening %s: %s",filename,strerror(errno));
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int SafeOpenRead (char *filename)
|
||||||
|
{
|
||||||
|
int handle;
|
||||||
|
|
||||||
|
handle = open(filename,O_RDONLY | O_BINARY);
|
||||||
|
|
||||||
|
if (handle == -1)
|
||||||
|
QCC_Error ("Error opening %s: %s",filename,strerror(errno));
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SafeRead (int handle, void *buffer, long count)
|
||||||
|
{
|
||||||
|
if (read (handle,buffer,count) != count)
|
||||||
|
QCC_Error ("File read failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef QCC
|
||||||
|
void SafeWrite (int handle, void *buffer, long count)
|
||||||
|
{
|
||||||
|
if (write (handle,buffer,count) != count)
|
||||||
|
QCC_Error ("File write failure");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void *SafeMalloc (long size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = (void *)Hunk_Alloc (size);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
QCC_Error ("Malloc failure for %lu bytes",size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DefaultExtension (char *path, char *extension)
|
||||||
|
{
|
||||||
|
char *src;
|
||||||
|
//
|
||||||
|
// if path doesn't have a .EXT, append extension
|
||||||
|
// (extension should include the .)
|
||||||
|
//
|
||||||
|
src = path + strlen(path) - 1;
|
||||||
|
|
||||||
|
while (*src != PATHSEPERATOR && src != path)
|
||||||
|
{
|
||||||
|
if (*src == '.')
|
||||||
|
return; // it has an extension
|
||||||
|
src--;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat (path, extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DefaultPath (char *path, char *basepath)
|
||||||
|
{
|
||||||
|
char temp[128];
|
||||||
|
|
||||||
|
if (path[0] == PATHSEPERATOR)
|
||||||
|
return; // absolute path location
|
||||||
|
strcpy (temp,path);
|
||||||
|
strcpy (path,basepath);
|
||||||
|
strcat (path,temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StripFilename (char *path)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = strlen(path)-1;
|
||||||
|
while (length > 0 && path[length] != PATHSEPERATOR)
|
||||||
|
length--;
|
||||||
|
path[length] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StripExtension (char *path)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = strlen(path)-1;
|
||||||
|
while (length > 0 && path[length] != '.')
|
||||||
|
{
|
||||||
|
length--;
|
||||||
|
if (path[length] == '/')
|
||||||
|
return; // no extension
|
||||||
|
}
|
||||||
|
if (length)
|
||||||
|
path[length] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
Extract file parts
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
void ExtractFilePath (char *path, char *dest)
|
||||||
|
{
|
||||||
|
char *src;
|
||||||
|
|
||||||
|
src = path + strlen(path) - 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// back up until a \ or the start
|
||||||
|
//
|
||||||
|
while (src != path && *(src-1) != PATHSEPERATOR)
|
||||||
|
src--;
|
||||||
|
|
||||||
|
memcpy (dest, path, src-path);
|
||||||
|
dest[src-path] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractFileBase (char *path, char *dest)
|
||||||
|
{
|
||||||
|
char *src;
|
||||||
|
|
||||||
|
src = path + strlen(path) - 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// back up until a \ or the start
|
||||||
|
//
|
||||||
|
while (src != path && *(src-1) != PATHSEPERATOR)
|
||||||
|
src--;
|
||||||
|
|
||||||
|
while (*src && *src != '.')
|
||||||
|
{
|
||||||
|
*dest++ = *src++;
|
||||||
|
}
|
||||||
|
*dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtractFileExtension (char *path, char *dest)
|
||||||
|
{
|
||||||
|
char *src;
|
||||||
|
|
||||||
|
src = path + strlen(path) - 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// back up until a . or the start
|
||||||
|
//
|
||||||
|
while (src != path && *(src-1) != '.')
|
||||||
|
src--;
|
||||||
|
if (src == path)
|
||||||
|
{
|
||||||
|
*dest = 0; // no extension
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (dest,src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
ParseNum / ParseHex
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
long ParseHex (char *hex)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
long num;
|
||||||
|
|
||||||
|
num = 0;
|
||||||
|
str = hex;
|
||||||
|
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
num <<= 4;
|
||||||
|
if (*str >= '0' && *str <= '9')
|
||||||
|
num += *str-'0';
|
||||||
|
else if (*str >= 'a' && *str <= 'f')
|
||||||
|
num += 10 + *str-'a';
|
||||||
|
else if (*str >= 'A' && *str <= 'F')
|
||||||
|
num += 10 + *str-'A';
|
||||||
|
else
|
||||||
|
QCC_Error (ERR_BADHEX, "Bad hex number: %s",hex);
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long ParseNum (char *str)
|
||||||
|
{
|
||||||
|
if (str[0] == '$')
|
||||||
|
return ParseHex (str+1);
|
||||||
|
if (str[0] == '0' && str[1] == 'x')
|
||||||
|
return ParseHex (str+2);
|
||||||
|
return atol (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
|
||||||
|
BYTE ORDER FUNCTIONS
|
||||||
|
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN__
|
||||||
|
|
||||||
|
short QCC_LittleShort (short l)
|
||||||
|
{
|
||||||
|
qbyte b1,b2;
|
||||||
|
|
||||||
|
b1 = l&255;
|
||||||
|
b2 = (l>>8)&255;
|
||||||
|
|
||||||
|
return (b1<<8) + b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
short QCC_BigShort (short l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long QCC_LittleLong (long l)
|
||||||
|
{
|
||||||
|
qbyte b1,b2,b3,b4;
|
||||||
|
|
||||||
|
b1 = l&255;
|
||||||
|
b2 = (l>>8)&255;
|
||||||
|
b3 = (l>>16)&255;
|
||||||
|
b4 = (l>>24)&255;
|
||||||
|
|
||||||
|
return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
long QCC_BigLong (long l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float QCC_LittleFloat (float l)
|
||||||
|
{
|
||||||
|
union {qbyte b[4]; float f;} in, out;
|
||||||
|
|
||||||
|
in.f = l;
|
||||||
|
out.b[0] = in.b[3];
|
||||||
|
out.b[1] = in.b[2];
|
||||||
|
out.b[2] = in.b[1];
|
||||||
|
out.b[3] = in.b[0];
|
||||||
|
|
||||||
|
return out.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float QCC_BigFloat (float l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
short QCC_BigShort (short l)
|
||||||
|
{
|
||||||
|
qbyte b1,b2;
|
||||||
|
|
||||||
|
b1 = l&255;
|
||||||
|
b2 = (l>>8)&255;
|
||||||
|
|
||||||
|
return (b1<<8) + b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
short QCC_LittleShort (short l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long QCC_BigLong (long l)
|
||||||
|
{
|
||||||
|
qbyte b1,b2,b3,b4;
|
||||||
|
|
||||||
|
b1 = (qbyte)(l&255);
|
||||||
|
b2 = (qbyte)((l>>8)&255);
|
||||||
|
b3 = (qbyte)((l>>16)&255);
|
||||||
|
b4 = (qbyte)((l>>24)&255);
|
||||||
|
|
||||||
|
return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
long QCC_LittleLong (long l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
float QCC_BigFloat (float l)
|
||||||
|
{
|
||||||
|
union {qbyte b[4]; float f;} in, out;
|
||||||
|
|
||||||
|
in.f = l;
|
||||||
|
out.b[0] = in.b[3];
|
||||||
|
out.b[1] = in.b[2];
|
||||||
|
out.b[2] = in.b[1];
|
||||||
|
out.b[3] = in.b[0];
|
||||||
|
|
||||||
|
return out.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float QCC_LittleFloat (float l)
|
||||||
|
{
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SetEndian(void)
|
||||||
|
{
|
||||||
|
if (!BigShort)
|
||||||
|
{
|
||||||
|
BigShort = QCC_BigShort;
|
||||||
|
LittleShort = QCC_LittleShort;
|
||||||
|
BigLong = QCC_BigLong;
|
||||||
|
LittleLong = QCC_LittleLong;
|
||||||
|
BigFloat = QCC_BigFloat;
|
||||||
|
LittleFloat = QCC_LittleFloat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//buffer size and max size are different. buffer is bigger.
|
||||||
|
|
||||||
|
#define MAXQCCFILES 3
|
||||||
|
struct {
|
||||||
|
char name[64];
|
||||||
|
char *buff;
|
||||||
|
// int buffismalloc;
|
||||||
|
int buffsize;
|
||||||
|
int ofs;
|
||||||
|
int maxofs;
|
||||||
|
} qccfile[MAXQCCFILES];
|
||||||
|
int SafeOpenWrite (char *filename, int maxsize)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MAXQCCFILES; i++)
|
||||||
|
{
|
||||||
|
if (!qccfile[i].buff)
|
||||||
|
{
|
||||||
|
strcpy(qccfile[i].name, filename);
|
||||||
|
qccfile[i].buffsize = maxsize;
|
||||||
|
qccfile[i].maxofs = 0;
|
||||||
|
qccfile[i].ofs = 0;
|
||||||
|
// if (maxsize > 8192)
|
||||||
|
// qccfile[i].buffismalloc = 1;
|
||||||
|
// else
|
||||||
|
// qccfile[i].buffismalloc = 0;
|
||||||
|
// if (qccfile[i].buffismalloc)
|
||||||
|
qccfile[i].buff = malloc(qccfile[i].buffsize);
|
||||||
|
// else
|
||||||
|
// qccfile[i].buff = memalloc(qccfile[i].buffsize);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QCC_Error(ERR_TOOMANYOPENFILES, "Too many open files on file %s", filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResizeBuf(int hand, int newsize)
|
||||||
|
{
|
||||||
|
// int wasmal = qccfile[hand].buffismalloc;
|
||||||
|
char *nb;
|
||||||
|
|
||||||
|
if (qccfile[hand].buffsize >= newsize)
|
||||||
|
return; //already big enough
|
||||||
|
|
||||||
|
// if (newsize > 8192)
|
||||||
|
// {
|
||||||
|
// qccfile[hand].buffismalloc = true;
|
||||||
|
nb = malloc(newsize);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// qccfile[hand].buffismalloc = false;
|
||||||
|
// nb = memalloc(newsize);
|
||||||
|
// }
|
||||||
|
|
||||||
|
memcpy(nb, qccfile[hand].buff, qccfile[hand].maxofs);
|
||||||
|
// if (wasmal)
|
||||||
|
free(qccfile[hand].buff);
|
||||||
|
// else
|
||||||
|
// memfree(qccfile[hand].buff);
|
||||||
|
qccfile[hand].buff = nb;
|
||||||
|
qccfile[hand].buffsize = newsize;
|
||||||
|
}
|
||||||
|
void SafeWrite(int hand, void *buf, long count)
|
||||||
|
{
|
||||||
|
if (qccfile[hand].ofs +count >= qccfile[hand].buffsize)
|
||||||
|
ResizeBuf(hand, qccfile[hand].ofs + count+(64*1024));
|
||||||
|
|
||||||
|
memcpy(&qccfile[hand].buff[qccfile[hand].ofs], buf, count);
|
||||||
|
qccfile[hand].ofs+=count;
|
||||||
|
if (qccfile[hand].ofs > qccfile[hand].maxofs)
|
||||||
|
qccfile[hand].maxofs = qccfile[hand].ofs;
|
||||||
|
}
|
||||||
|
int SafeSeek(int hand, int ofs, int mode)
|
||||||
|
{
|
||||||
|
if (mode == SEEK_CUR)
|
||||||
|
return qccfile[hand].ofs;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResizeBuf(hand, ofs+1024);
|
||||||
|
qccfile[hand].ofs = ofs;
|
||||||
|
if (qccfile[hand].ofs > qccfile[hand].maxofs)
|
||||||
|
qccfile[hand].maxofs = qccfile[hand].ofs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SafeClose(int hand)
|
||||||
|
{
|
||||||
|
externs->WriteFile(qccfile[hand].name, qccfile[hand].buff, qccfile[hand].maxofs);
|
||||||
|
// if (qccfile[hand].buffismalloc)
|
||||||
|
free(qccfile[hand].buff);
|
||||||
|
// else
|
||||||
|
// memfree(qccfile[hand].buff);
|
||||||
|
qccfile[hand].buff = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qcc_cachedsourcefile_t *qcc_sourcefile;
|
||||||
|
long QCC_LoadFile (char *filename, void **bufferptr)
|
||||||
|
{
|
||||||
|
char *mem;
|
||||||
|
int len;
|
||||||
|
len = externs->FileSize(filename);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
QCC_Error(ERR_COULDNTOPENFILE, "Couldn't open file %s", filename);
|
||||||
|
// if (!Abort)
|
||||||
|
return -1;
|
||||||
|
// Abort("failed to find file %s", filename);
|
||||||
|
}
|
||||||
|
mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+2);
|
||||||
|
|
||||||
|
((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
|
||||||
|
qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
|
||||||
|
qcc_sourcefile->size = len;
|
||||||
|
mem += sizeof(qcc_cachedsourcefile_t);
|
||||||
|
strcpy(qcc_sourcefile->filename, filename);
|
||||||
|
qcc_sourcefile->file = mem;
|
||||||
|
qcc_sourcefile->type = FT_CODE;
|
||||||
|
|
||||||
|
externs->ReadFile(filename, mem, len+2);
|
||||||
|
mem[len] = '\n';
|
||||||
|
mem[len+1] = '\0';
|
||||||
|
*bufferptr=mem;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void QCC_AddFile (char *filename)
|
||||||
|
{
|
||||||
|
char *mem;
|
||||||
|
int len;
|
||||||
|
len = externs->FileSize(filename);
|
||||||
|
if (len < 0)
|
||||||
|
Abort("failed to find file %s", filename);
|
||||||
|
mem = qccHunkAlloc(sizeof(qcc_cachedsourcefile_t) + len+1);
|
||||||
|
|
||||||
|
((qcc_cachedsourcefile_t*)mem)->next = qcc_sourcefile;
|
||||||
|
qcc_sourcefile = (qcc_cachedsourcefile_t*)mem;
|
||||||
|
qcc_sourcefile->size = len;
|
||||||
|
mem += sizeof(qcc_cachedsourcefile_t);
|
||||||
|
strcpy(qcc_sourcefile->filename, filename);
|
||||||
|
qcc_sourcefile->file = mem;
|
||||||
|
qcc_sourcefile->type = FT_DATA;
|
||||||
|
|
||||||
|
externs->ReadFile(filename, mem, len+1);
|
||||||
|
mem[len] = '\0';
|
||||||
|
|
||||||
|
outputversion = PROG_DEBUGVERSION;
|
||||||
|
}
|
||||||
|
void *FS_ReadToMem(char *filename, void *mem, int *len)
|
||||||
|
{
|
||||||
|
if (!mem)
|
||||||
|
{
|
||||||
|
*len = externs->FileSize(filename);
|
||||||
|
mem = memalloc(*len);
|
||||||
|
}
|
||||||
|
return externs->ReadFile(filename, mem, *len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FS_CloseFromMem(void *mem)
|
||||||
|
{
|
||||||
|
memfree(mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
6905
engine/qclib/qcc_pr_comp.c
Normal file
6905
engine/qclib/qcc_pr_comp.c
Normal file
File diff suppressed because it is too large
Load diff
2660
engine/qclib/qcc_pr_lex.c
Normal file
2660
engine/qclib/qcc_pr_lex.c
Normal file
File diff suppressed because it is too large
Load diff
6
engine/qclib/qcd.h
Normal file
6
engine/qclib/qcd.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, char *info, char *buffer);
|
||||||
|
int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle);
|
||||||
|
|
||||||
|
char *filefromprogs(progfuncs_t *progfuncs, progsnum_t prnum, char *fname, int *size, char *buffer);
|
||||||
|
char *filefromnewprogs(progfuncs_t *progfuncs, char *prname, char *fname, int *size, char *buffer);//fixme - remove parm 1
|
||||||
|
|
209
engine/qclib/qcd_main.c
Normal file
209
engine/qclib/qcd_main.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#include "progsint.h"
|
||||||
|
//#include "qcc.h"
|
||||||
|
|
||||||
|
#ifdef AVAIL_ZLIB
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define ZEXPORT VARGS
|
||||||
|
#include "../libs/zlib.h"
|
||||||
|
|
||||||
|
//# pragma comment (lib, "zip/zlib.lib")
|
||||||
|
#else
|
||||||
|
#include <zlib.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, char *info, char *buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (method == 0) //copy
|
||||||
|
{
|
||||||
|
if (complen != len) Sys_Error("lengths do not match");
|
||||||
|
memcpy(buffer, info, len);
|
||||||
|
}
|
||||||
|
else if (method == 1) //encryption
|
||||||
|
{
|
||||||
|
if (complen != len) Sys_Error("lengths do not match");
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
buffer[i] = info[i] ^ 0xA5;
|
||||||
|
}
|
||||||
|
#ifdef AVAIL_ZLIB
|
||||||
|
else if (method == 2) //compression (ZLIB)
|
||||||
|
{
|
||||||
|
z_stream strm = {
|
||||||
|
info,
|
||||||
|
complen,
|
||||||
|
0,
|
||||||
|
|
||||||
|
buffer,
|
||||||
|
len,
|
||||||
|
0,
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
Z_BINARY,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
inflateInit(&strm);
|
||||||
|
if (Z_STREAM_END != inflate(&strm, Z_FINISH)) //decompress it in one go.
|
||||||
|
Sys_Error("Failed block decompression\n");
|
||||||
|
inflateEnd(&strm);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//add your decryption/decompression routine here.
|
||||||
|
else
|
||||||
|
Sys_Error("Bad file encryption routine\n");
|
||||||
|
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MINIMAL
|
||||||
|
void SafeWrite(int hand, void *buf, long count);
|
||||||
|
int SafeSeek(int hand, int ofs, int mode);
|
||||||
|
//we are allowed to trash our input here.
|
||||||
|
int QC_encode(progfuncs_t *progfuncs, int len, int method, char *in, int handle)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (method == 0) //copy
|
||||||
|
{
|
||||||
|
SafeWrite(handle, in, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
else if (method == 1) //encryption
|
||||||
|
{
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
in[i] = in[i] ^ 0xA5;
|
||||||
|
SafeWrite(handle, in, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#ifdef AVAIL_ZLIB
|
||||||
|
else if (method == 2) //compression (ZLIB)
|
||||||
|
{
|
||||||
|
char out[8192];
|
||||||
|
|
||||||
|
z_stream strm = {
|
||||||
|
in,
|
||||||
|
len,
|
||||||
|
0,
|
||||||
|
|
||||||
|
out,
|
||||||
|
sizeof(out),
|
||||||
|
0,
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
|
||||||
|
Z_BINARY,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
i=0;
|
||||||
|
|
||||||
|
deflateInit(&strm, Z_BEST_COMPRESSION);
|
||||||
|
while(deflate(&strm, Z_FINISH) == Z_OK)
|
||||||
|
{
|
||||||
|
SafeWrite(handle, out, sizeof(out) - strm.avail_out); //compress in chunks of 8192. Saves having to allocate a huge-mega-big buffer
|
||||||
|
i+=sizeof(out) - strm.avail_out;
|
||||||
|
strm.next_out = out;
|
||||||
|
strm.avail_out = sizeof(out);
|
||||||
|
}
|
||||||
|
SafeWrite(handle, out, sizeof(out) - strm.avail_out);
|
||||||
|
i+=sizeof(out) - strm.avail_out;
|
||||||
|
deflateEnd(&strm);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//add your compression/decryption routine here.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Sys_Error("Wierd method");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *filefromprogs(progfuncs_t *progfuncs, progsnum_t prnum, char *fname, int *size, char *buffer)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
includeddatafile_t *s;
|
||||||
|
if (!pr_progstate[prnum].progs)
|
||||||
|
return NULL;
|
||||||
|
if (pr_progstate[prnum].progs->version < PROG_DEBUGVERSION)
|
||||||
|
return NULL;
|
||||||
|
if (!pr_progstate[prnum].progs->ofsfiles)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
num = *(int*)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles);
|
||||||
|
s = (includeddatafile_t *)((char *)pr_progstate[prnum].progs + pr_progstate[prnum].progs->ofsfiles+4);
|
||||||
|
while(num>0)
|
||||||
|
{
|
||||||
|
if (!strcmp(s->filename, fname))
|
||||||
|
{
|
||||||
|
if (size)
|
||||||
|
*size = s->size;
|
||||||
|
if (!buffer)
|
||||||
|
return (char *)0xffffffff;
|
||||||
|
return QC_decode(progfuncs, s->compsize, s->size, s->compmethod, (char *)pr_progstate[prnum].progs+s->ofs, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
s++;
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QCCONLY
|
||||||
|
char *filefromnewprogs(progfuncs_t *progfuncs, char *prname, char *fname, int *size, char *buffer)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
includeddatafile_t *s;
|
||||||
|
progstate_t progs;
|
||||||
|
if (!PR_ReallyLoadProgs(progfuncs, prname, -1, &progs, false))
|
||||||
|
{
|
||||||
|
if (size)
|
||||||
|
*size = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progs.progs->version < PROG_DEBUGVERSION)
|
||||||
|
return NULL;
|
||||||
|
if (!progs.progs->ofsfiles)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
num = *(int*)((char *)progs.progs + progs.progs->ofsfiles);
|
||||||
|
s = (includeddatafile_t *)((char *)progs.progs + progs.progs->ofsfiles+4);
|
||||||
|
while(num>0)
|
||||||
|
{
|
||||||
|
if (!strcmp(s->filename, fname))
|
||||||
|
{
|
||||||
|
if (size)
|
||||||
|
*size = s->size;
|
||||||
|
if (!buffer)
|
||||||
|
return (char *)0xffffffff;
|
||||||
|
return QC_decode(progfuncs, s->compsize, s->size, s->compmethod, (char *)progs.progs+s->ofs, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
s++;
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
979
engine/qclib/qcdecomp.c
Normal file
979
engine/qclib/qcdecomp.c
Normal file
|
@ -0,0 +1,979 @@
|
||||||
|
#ifndef MINIMAL
|
||||||
|
|
||||||
|
#include "progsint.h"
|
||||||
|
#include "setjmp.h"
|
||||||
|
|
||||||
|
#define MAX_PARMS 8
|
||||||
|
|
||||||
|
typedef struct QCC_type_s
|
||||||
|
{
|
||||||
|
etype_t type;
|
||||||
|
|
||||||
|
struct QCC_type_s *next;
|
||||||
|
// function types are more complex
|
||||||
|
struct QCC_type_s *aux_type; // return type or field type
|
||||||
|
int num_parms; // -1 = variable args
|
||||||
|
// struct QCC_type_s *parm_types[MAX_PARMS]; // only [num_parms] allocated
|
||||||
|
|
||||||
|
int ofs; //inside a structure.
|
||||||
|
int size;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
} QCC_type_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern QCC_type_t *qcc_typeinfo;
|
||||||
|
extern int numtypeinfos;
|
||||||
|
extern int maxtypeinfos;
|
||||||
|
extern QCC_type_t *type_void;// = {ev_void/*, &def_void*/};
|
||||||
|
extern QCC_type_t *type_string;// = {ev_string/*, &def_string*/};
|
||||||
|
extern QCC_type_t *type_float;// = {ev_float/*, &def_float*/};
|
||||||
|
extern QCC_type_t *type_vector;// = {ev_vector/*, &def_vector*/};
|
||||||
|
extern QCC_type_t *type_entity;// = {ev_entity/*, &def_entity*/};
|
||||||
|
extern QCC_type_t *type_field;// = {ev_field/*, &def_field*/};
|
||||||
|
extern QCC_type_t *type_function;// = {ev_function/*, &def_function*/,NULL,&type_void};
|
||||||
|
// type_function is a void() function used for state defs
|
||||||
|
extern QCC_type_t *type_pointer;// = {ev_pointer/*, &def_pointer*/};
|
||||||
|
extern QCC_type_t *type_integer;// = {ev_integer/*, &def_integer*/};
|
||||||
|
|
||||||
|
extern QCC_type_t *type_floatfield;// = {ev_field/*, &def_field*/, NULL, &type_float};
|
||||||
|
QCC_type_t *QCC_PR_NewType (char *name, int basictype);
|
||||||
|
|
||||||
|
|
||||||
|
jmp_buf decompilestatementfailure;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
bool Decompile(progfuncs_t *progfuncs, char *fname)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
QCC_type_t **ofstype;
|
||||||
|
qbyte *ofsflags;
|
||||||
|
|
||||||
|
int SafeOpenWrite (char *filename, int maxsize);
|
||||||
|
void SafeWrite(int hand, void *buf, long count);
|
||||||
|
int SafeSeek(int hand, int ofs, int mode);
|
||||||
|
void SafeClose(int hand);
|
||||||
|
void VARGS writes(int hand, char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
char buf[4192];
|
||||||
|
|
||||||
|
va_start(va, msg);
|
||||||
|
Q_vsnprintf (buf,sizeof(buf)-1, msg, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
SafeWrite(hand, buf, strlen(buf));
|
||||||
|
};
|
||||||
|
|
||||||
|
char *PR_UglyValueString (etype_t type, eval_t *val);
|
||||||
|
ddef16_t *ED_GlobalAtOfs16 (progfuncs_t *progfuncs, int ofs);
|
||||||
|
char *VarAtOfs(progfuncs_t *progfuncs, int ofs)
|
||||||
|
{
|
||||||
|
static char buf [4192];
|
||||||
|
ddef16_t *def;
|
||||||
|
int typen;
|
||||||
|
|
||||||
|
if (ofsflags[ofs]&8)
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
else
|
||||||
|
def = NULL;
|
||||||
|
if (!def)
|
||||||
|
{
|
||||||
|
if (ofsflags[ofs]&3)
|
||||||
|
{
|
||||||
|
if (ofstype[ofs])
|
||||||
|
sprintf(buf, "_v_%s_%i", ofstype[ofs]->name, ofs);
|
||||||
|
else
|
||||||
|
sprintf(buf, "_v_%i", ofs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ofstype[ofs])
|
||||||
|
{
|
||||||
|
typen = ofstype[ofs]->type;
|
||||||
|
goto evaluateimmediate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(buf, "_c_%i", ofs);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
if (!*def->s_name || !strcmp(def->s_name, "IMMEDIATE"))
|
||||||
|
{
|
||||||
|
if (current_progstate->types)
|
||||||
|
typen = current_progstate->types[def->type & ~DEF_SHARED].type;
|
||||||
|
else
|
||||||
|
typen = def->type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
|
||||||
|
|
||||||
|
evaluateimmediate:
|
||||||
|
// return PR_UglyValueString(def->type, (eval_t *)¤t_progstate->globals[def->ofs]);
|
||||||
|
switch(typen)
|
||||||
|
{
|
||||||
|
case ev_float:
|
||||||
|
sprintf(buf, "%f", G_FLOAT(ofs));
|
||||||
|
return buf;
|
||||||
|
case ev_vector:
|
||||||
|
sprintf(buf, "\'%f %f %f\'", G_FLOAT(ofs), G_FLOAT(ofs+1), G_FLOAT(ofs+2));
|
||||||
|
return buf;
|
||||||
|
case ev_string:
|
||||||
|
{
|
||||||
|
char *s, *s2;
|
||||||
|
s = buf;
|
||||||
|
*s++ = '\"';
|
||||||
|
s2 = pr_strings+G_INT(ofs);
|
||||||
|
|
||||||
|
|
||||||
|
if (s2)
|
||||||
|
while(*s2)
|
||||||
|
{
|
||||||
|
if (*s2 == '\n')
|
||||||
|
{
|
||||||
|
*s++ = '\\';
|
||||||
|
*s++ = 'n';
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
else if (*s2 == '\"')
|
||||||
|
{
|
||||||
|
*s++ = '\\';
|
||||||
|
*s++ = '\"';
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
else if (*s2 == '\t')
|
||||||
|
{
|
||||||
|
*s++ = '\\';
|
||||||
|
*s++ = 't';
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*s++=*s2++;
|
||||||
|
}
|
||||||
|
*s++ = '\"';
|
||||||
|
*s++ = '\0';
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
case ev_pointer:
|
||||||
|
sprintf(buf, "_c_pointer_%i", ofs);
|
||||||
|
return buf;
|
||||||
|
default:
|
||||||
|
sprintf(buf, "_c_%i", ofs);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def->s_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int file;
|
||||||
|
|
||||||
|
int ImmediateReadLater(progfuncs_t *progfuncs, progstate_t *progs, unsigned int ofs, int firstst)
|
||||||
|
{
|
||||||
|
dstatement16_t *st;
|
||||||
|
if (ofsflags[ofs] & 8)
|
||||||
|
return false; //this is a global/local/pramater, not a temp
|
||||||
|
if (!(ofsflags[ofs] & 3))
|
||||||
|
return false; //this is a constant.
|
||||||
|
for (st = &((dstatement16_t*)progs->statements)[firstst]; ; st++,firstst++)
|
||||||
|
{ //if written, return false, if read, return true.
|
||||||
|
if (st->op >= OP_CALL0 && st->op <= OP_CALL8)
|
||||||
|
{
|
||||||
|
if (ofs == OFS_RETURN)
|
||||||
|
return false;
|
||||||
|
if (ofs < OFS_PARM0 + 3*((unsigned int)st->op - OP_CALL0))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT)
|
||||||
|
{
|
||||||
|
if (ofs == st->b)
|
||||||
|
return false;
|
||||||
|
if (ofs == st->a)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (st->a == ofs)
|
||||||
|
return true;
|
||||||
|
if (st->b == ofs)
|
||||||
|
return true;
|
||||||
|
if (st->c == ofs)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->op == OP_DONE || st->op == OP_RETURN) //we missed our chance. (return/done ends any code coherancy).
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int ProductReadLater(progfuncs_t *progfuncs, progstate_t *progs, int stnum)
|
||||||
|
{
|
||||||
|
dstatement16_t *st;
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stnum];
|
||||||
|
if (pr_opcodes[st->op].priority == -1)
|
||||||
|
{
|
||||||
|
if (st->op >= OP_CALL0 && st->op <= OP_CALL7)
|
||||||
|
return ImmediateReadLater(progfuncs, progs, OFS_RETURN, stnum+1);
|
||||||
|
return false;//these don't have products...
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pr_opcodes[st->op].associative == ASSOC_RIGHT)
|
||||||
|
return ImmediateReadLater(progfuncs, progs, st->b, stnum+1);
|
||||||
|
else
|
||||||
|
return ImmediateReadLater(progfuncs, progs, st->c, stnum+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteStatementProducingOfs(progfuncs_t *progfuncs, progstate_t *progs, int lastnum, int firstpossible, int ofs) //recursive, works backwards
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
dstatement16_t *st;
|
||||||
|
ddef16_t *def;
|
||||||
|
if (ofs == 0)
|
||||||
|
longjmp(decompilestatementfailure, 1);
|
||||||
|
for (; lastnum >= firstpossible; lastnum--)
|
||||||
|
{
|
||||||
|
st = &((dstatement16_t*)progs->statements)[lastnum];
|
||||||
|
if (st->op >= OP_CALL0 && st->op < OP_CALL7)
|
||||||
|
{
|
||||||
|
if (ofs != OFS_RETURN)
|
||||||
|
continue;
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->a);
|
||||||
|
writes(file, "(");
|
||||||
|
for (i = 0; i < st->op - OP_CALL0; i++)
|
||||||
|
{
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, OFS_PARM0 + i*3);
|
||||||
|
if (i != st->op - OP_CALL0-1)
|
||||||
|
writes(file, ", ");
|
||||||
|
}
|
||||||
|
writes(file, ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT)
|
||||||
|
{
|
||||||
|
if (st->b != ofs)
|
||||||
|
continue;
|
||||||
|
if (!ImmediateReadLater(progfuncs, progs, st->b, lastnum+1))
|
||||||
|
{
|
||||||
|
writes(file, "(");
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->b);
|
||||||
|
writes(file, " ");
|
||||||
|
writes(file, pr_opcodes[st->op].name);
|
||||||
|
writes(file, " ");
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->a);
|
||||||
|
writes(file, ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (st->c != ofs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ImmediateReadLater(progfuncs, progs, st->c, lastnum+1))
|
||||||
|
{
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->c);
|
||||||
|
writes(file, " = ");
|
||||||
|
}
|
||||||
|
writes(file, "(");
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->a);
|
||||||
|
|
||||||
|
if (!strcmp(pr_opcodes[st->op].name, "."))
|
||||||
|
writes(file, pr_opcodes[st->op].name); //extra spaces around .s are ugly.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writes(file, " ");
|
||||||
|
writes(file, pr_opcodes[st->op].name);
|
||||||
|
writes(file, " ");
|
||||||
|
}
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, lastnum-1, firstpossible, st->b);
|
||||||
|
writes(file, ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
if (!strcmp(def->s_name, "IMMEDIATE"))
|
||||||
|
writes(file, "%s", VarAtOfs(progfuncs, ofs));
|
||||||
|
else
|
||||||
|
writes(file, "%s", def->s_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writes(file, "%s", VarAtOfs(progfuncs, ofs));
|
||||||
|
// longjmp(decompilestatementfailure, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WriteStatement(progfuncs_t *progfuncs, progstate_t *progs, int stnum, int firstpossible)
|
||||||
|
{
|
||||||
|
int count, skip;
|
||||||
|
dstatement16_t *st;
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stnum];
|
||||||
|
switch(st->op)
|
||||||
|
{
|
||||||
|
case OP_IFNOT:
|
||||||
|
count = (signed short)st->b;
|
||||||
|
writes(file, "if (");
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, stnum, firstpossible, st->a);
|
||||||
|
writes(file, ")\r\n");
|
||||||
|
writes(file, "{\r\n");
|
||||||
|
firstpossible = stnum+1;
|
||||||
|
count--;
|
||||||
|
stnum++;
|
||||||
|
while(count)
|
||||||
|
{
|
||||||
|
if (ProductReadLater(progfuncs, progs, stnum))
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
stnum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
skip = WriteStatement(progfuncs, progs, stnum, firstpossible);
|
||||||
|
count-=skip;
|
||||||
|
stnum+=skip;
|
||||||
|
}
|
||||||
|
writes(file, "}\r\n");
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stnum];
|
||||||
|
if (st->op == OP_GOTO)
|
||||||
|
{
|
||||||
|
count = (signed short)st->b;
|
||||||
|
count--;
|
||||||
|
stnum++;
|
||||||
|
|
||||||
|
writes(file, "else\r\n");
|
||||||
|
writes(file, "{\r\n");
|
||||||
|
while(count)
|
||||||
|
{
|
||||||
|
if (ProductReadLater(progfuncs, progs, stnum))
|
||||||
|
{
|
||||||
|
count--;
|
||||||
|
stnum++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
skip = WriteStatement(progfuncs, progs, stnum, firstpossible);
|
||||||
|
count-=skip;
|
||||||
|
stnum+=skip;
|
||||||
|
}
|
||||||
|
writes(file, "}\r\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_IF:
|
||||||
|
longjmp(decompilestatementfailure, 1);
|
||||||
|
break;
|
||||||
|
case OP_GOTO:
|
||||||
|
longjmp(decompilestatementfailure, 1);
|
||||||
|
break;
|
||||||
|
case OP_RETURN:
|
||||||
|
case OP_DONE:
|
||||||
|
if (st->a)
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, stnum-1, firstpossible, st->a);
|
||||||
|
break;
|
||||||
|
case OP_CALL0:
|
||||||
|
case OP_CALL1:
|
||||||
|
case OP_CALL2:
|
||||||
|
case OP_CALL3:
|
||||||
|
case OP_CALL4:
|
||||||
|
case OP_CALL5:
|
||||||
|
case OP_CALL6:
|
||||||
|
case OP_CALL7:
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, stnum, firstpossible, OFS_RETURN);
|
||||||
|
writes(file, ";\r\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (pr_opcodes[st->op].associative == ASSOC_RIGHT)
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, stnum, firstpossible, st->b);
|
||||||
|
else
|
||||||
|
WriteStatementProducingOfs(progfuncs, progs, stnum, firstpossible, st->c);
|
||||||
|
writes(file, ";\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteAsmStatements(progfuncs_t *progfuncs, progstate_t *progs, int num, int f, char *functionname)
|
||||||
|
{
|
||||||
|
int stn = progs->functions[num].first_statement;
|
||||||
|
QCC_opcode_t *op;
|
||||||
|
dstatement16_t *st = NULL;
|
||||||
|
eval_t *v;
|
||||||
|
|
||||||
|
ddef16_t *def;
|
||||||
|
int ofs,i;
|
||||||
|
|
||||||
|
int fileofs;
|
||||||
|
|
||||||
|
if (!functionname && stn<0)
|
||||||
|
{
|
||||||
|
//we wrote this one...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stn>=0)
|
||||||
|
{
|
||||||
|
for (stn = progs->functions[num].first_statement; stn < (signed int)pr_progs->numstatements; stn++)
|
||||||
|
{
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stn];
|
||||||
|
if (st->op == OP_DONE || st->op == OP_RETURN)
|
||||||
|
{
|
||||||
|
if (!st->a)
|
||||||
|
writes(f, "void(");
|
||||||
|
else if (ofstype[st->a])
|
||||||
|
{
|
||||||
|
writes(f, "%s", ofstype[st->a]->name);
|
||||||
|
writes(f, "(");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writes(f, "function(");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st=NULL;
|
||||||
|
stn = progs->functions[num].first_statement;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writes(f, "function(");
|
||||||
|
for (ofs = progs->functions[num].parm_start, i = 0; i < progs->functions[num].numparms; i++, ofs+=progs->functions[num].parm_size[i])
|
||||||
|
{
|
||||||
|
ofsflags[ofs] |= 4;
|
||||||
|
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
if (def && stn>=0)
|
||||||
|
{
|
||||||
|
if (st)
|
||||||
|
writes(f, ", ");
|
||||||
|
st = (void *)0xffff;
|
||||||
|
|
||||||
|
if (!*def->s_name)
|
||||||
|
{
|
||||||
|
char mem[64];
|
||||||
|
sprintf(mem, "_p_%i", def->ofs);
|
||||||
|
def->s_name = malloc(strlen(mem)+1);
|
||||||
|
strcpy(def->s_name, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_progstate->types)
|
||||||
|
writes(f, "%s %s", current_progstate->types[def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)].name, def->s_name);
|
||||||
|
else
|
||||||
|
switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL))
|
||||||
|
{
|
||||||
|
case ev_string:
|
||||||
|
writes(f, "%s %s", "string", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_float:
|
||||||
|
writes(f, "%s %s", "float", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_entity:
|
||||||
|
writes(f, "%s %s", "entity", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_vector:
|
||||||
|
writes(f, "%s %s", "vector", def->s_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writes(f, "%s %s", "randomtype", def->s_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ofs = progs->functions[num].parm_start+progs->functions[num].numparms, i = progs->functions[num].numparms; i < progs->functions[num].locals; i++, ofs+=1)
|
||||||
|
ofsflags[ofs] |= 4;
|
||||||
|
|
||||||
|
if (!*progs->functions[num].s_name)
|
||||||
|
{
|
||||||
|
char mem[64];
|
||||||
|
if (!functionname)
|
||||||
|
{
|
||||||
|
sprintf(mem, "_bi_%i", num);
|
||||||
|
progs->functions[num].s_name = malloc(strlen(mem)+1);
|
||||||
|
strcpy(progs->functions[num].s_name, mem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progs->functions[num].s_name = malloc(strlen(functionname)+1);
|
||||||
|
strcpy(progs->functions[num].s_name, functionname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writes(f, ") %s", progs->functions[num].s_name);
|
||||||
|
|
||||||
|
if (stn < 0)
|
||||||
|
{
|
||||||
|
stn*=-1;
|
||||||
|
writes(f, " = #%i;\r\n", stn);
|
||||||
|
/*
|
||||||
|
for (ofs = progs->functions[num].parm_start, i = 0; i < progs->functions[num].numparms; i++, ofs+=progs->functions[num].parm_size[i])
|
||||||
|
{
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
|
||||||
|
if (progs->types)
|
||||||
|
{
|
||||||
|
if (progs->types[def->type & ~(DEF_SHARED|DEF_SAVEGLOBAL)].type == ev_vector)
|
||||||
|
{
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs+1);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs+2);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((def->type & (~(DEF_SHARED|DEF_SAVEGLOBAL))) == ev_vector)
|
||||||
|
{
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs+1);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs+2);
|
||||||
|
def->ofs = 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionname) //parsing defs
|
||||||
|
{
|
||||||
|
writes(f, ";\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileofs = SafeSeek(f, 0, SEEK_CUR);
|
||||||
|
if (setjmp(decompilestatementfailure))
|
||||||
|
{
|
||||||
|
writes(f, "*/\r\n");
|
||||||
|
// SafeSeek(f, fileofs, SEEK_SET);
|
||||||
|
writes(f, " = asm {\r\n");
|
||||||
|
|
||||||
|
stn = progs->functions[num].first_statement;
|
||||||
|
for (ofs = progs->functions[num].parm_start+progs->functions[num].numparms, i = progs->functions[num].numparms; i < progs->functions[num].locals; i++, ofs+=1)
|
||||||
|
{
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
v = (eval_t *)&((int *)progs->globals)[def->ofs];
|
||||||
|
if (current_progstate->types)
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", current_progstate->types[def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)].name, def->s_name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!*def->s_name)
|
||||||
|
{
|
||||||
|
char mem[64];
|
||||||
|
sprintf(mem, "_l_%i", def->ofs);
|
||||||
|
def->s_name = malloc(strlen(mem)+1);
|
||||||
|
strcpy(def->s_name, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL))
|
||||||
|
{
|
||||||
|
case ev_string:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "string", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_float:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "float", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_entity:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "entity", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_vector:
|
||||||
|
if (v->vector[0] || v->vector[1] || v->vector[2])
|
||||||
|
writes(f, "\tlocal vector %s = '%f %f %f';\r\n", def->s_name, v->vector[0], v->vector[1], v->vector[2]);
|
||||||
|
else
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "vector", def->s_name);
|
||||||
|
ofs+=2; //skip floats;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "randomtype", def->s_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stn];
|
||||||
|
if (!st->op) //end of function statement!
|
||||||
|
break;
|
||||||
|
op = &pr_opcodes[st->op];
|
||||||
|
writes(f, "\t%s", op->opname);
|
||||||
|
|
||||||
|
if (op->priority==-1&&op->associative==ASSOC_RIGHT) //last param is a goto
|
||||||
|
{
|
||||||
|
if (op->type_b == &type_void)
|
||||||
|
{
|
||||||
|
if (st->a)
|
||||||
|
writes(f, " %i", (signed short)st->a);
|
||||||
|
}
|
||||||
|
else if (op->type_c == &type_void)
|
||||||
|
{
|
||||||
|
if (st->a)
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->a));
|
||||||
|
if (st->b)
|
||||||
|
writes(f, " %i", (signed short)st->b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (st->a)
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->a));
|
||||||
|
if (st->b)
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->b));
|
||||||
|
if (st->c) //rightness means it uses a as c
|
||||||
|
writes(f, " %i", (signed short)st->c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (st->a)
|
||||||
|
{
|
||||||
|
if (op->type_a == NULL)
|
||||||
|
writes(f, " %i", (signed short)st->a);
|
||||||
|
else
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->a));
|
||||||
|
}
|
||||||
|
if (st->b)
|
||||||
|
{
|
||||||
|
if (op->type_b == NULL)
|
||||||
|
writes(f, " %i", (signed short)st->b);
|
||||||
|
else
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->b));
|
||||||
|
}
|
||||||
|
if (st->c && op->associative != ASSOC_RIGHT) //rightness means it uses a as c
|
||||||
|
{
|
||||||
|
if (op->type_c == NULL)
|
||||||
|
writes(f, " %i", (signed short)st->c);
|
||||||
|
else
|
||||||
|
writes(f, " %s", VarAtOfs(progfuncs, st->c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writes(f, ";\r\n");
|
||||||
|
|
||||||
|
stn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!strcmp(progs->functions[num].s_name, "SUB_Remove"))
|
||||||
|
file = 0;
|
||||||
|
file = f;
|
||||||
|
|
||||||
|
writes(f, "/*\r\n");
|
||||||
|
|
||||||
|
writes(f, " =\r\n{\r\n");
|
||||||
|
|
||||||
|
for (ofs = progs->functions[num].parm_start+progs->functions[num].numparms, i = progs->functions[num].numparms; i < progs->functions[num].locals; i++, ofs+=1)
|
||||||
|
{
|
||||||
|
def = ED_GlobalAtOfs16(progfuncs, ofs);
|
||||||
|
if (def)
|
||||||
|
{
|
||||||
|
v = (eval_t *)&((int *)progs->globals)[def->ofs];
|
||||||
|
if (current_progstate->types)
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", current_progstate->types[def->type&~(DEF_SHARED|DEF_SAVEGLOBAL)].name, def->s_name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!*def->s_name)
|
||||||
|
{
|
||||||
|
char mem[64];
|
||||||
|
sprintf(mem, "_l_%i", def->ofs);
|
||||||
|
def->s_name = malloc(strlen(mem)+1);
|
||||||
|
strcpy(def->s_name, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(def->type&~(DEF_SHARED|DEF_SAVEGLOBAL))
|
||||||
|
{
|
||||||
|
case ev_string:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "string", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_float:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "float", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_entity:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "entity", def->s_name);
|
||||||
|
break;
|
||||||
|
case ev_vector:
|
||||||
|
if (v->vector[0] || v->vector[1] || v->vector[2])
|
||||||
|
writes(f, "\tlocal vector %s = '%f %f %f';\r\n", def->s_name, v->vector[0], v->vector[1], v->vector[2]);
|
||||||
|
else
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "vector", def->s_name);
|
||||||
|
ofs+=2; //skip floats;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
writes(f, "\tlocal %s %s;\r\n", "randomtype", def->s_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (stn = progs->functions[num].first_statement; stn < (signed int)pr_progs->numstatements; stn++)
|
||||||
|
{
|
||||||
|
if (ProductReadLater(progfuncs, progs, stn))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
st = &((dstatement16_t*)progs->statements)[stn];
|
||||||
|
if (!st->op)
|
||||||
|
break;
|
||||||
|
WriteStatement(progfuncs, progs, stn, progs->functions[num].first_statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
longjmp(decompilestatementfailure, 1);
|
||||||
|
}
|
||||||
|
writes(f, "};\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FigureOutTypes(progfuncs_t *progfuncs)
|
||||||
|
{
|
||||||
|
ddef16_t *def;
|
||||||
|
QCC_opcode_t *op;
|
||||||
|
unsigned int i,p;
|
||||||
|
dstatement16_t *st;
|
||||||
|
|
||||||
|
int parmofs[8];
|
||||||
|
|
||||||
|
ofstype = realloc(ofstype, sizeof(*ofstype)*65535);
|
||||||
|
ofsflags = realloc(ofsflags, sizeof(*ofsflags)*65535);
|
||||||
|
|
||||||
|
maxtypeinfos=256;
|
||||||
|
qcc_typeinfo = (void *)realloc(qcc_typeinfo, sizeof(QCC_type_t)*maxtypeinfos);
|
||||||
|
numtypeinfos = 0;
|
||||||
|
|
||||||
|
memset(ofstype, 0, sizeof(*ofstype)*65535);
|
||||||
|
memset(ofsflags, 0, sizeof(*ofsflags)*65535);
|
||||||
|
|
||||||
|
type_void = QCC_PR_NewType("void", ev_void);
|
||||||
|
type_string = QCC_PR_NewType("string", ev_string);
|
||||||
|
type_float = QCC_PR_NewType("float", ev_float);
|
||||||
|
type_vector = QCC_PR_NewType("vector", ev_vector);
|
||||||
|
type_entity = QCC_PR_NewType("entity", ev_entity);
|
||||||
|
type_field = QCC_PR_NewType("field", ev_field);
|
||||||
|
type_function = QCC_PR_NewType("function", ev_function);
|
||||||
|
type_pointer = QCC_PR_NewType("pointer", ev_pointer);
|
||||||
|
type_integer = QCC_PR_NewType("integer", ev_integer);
|
||||||
|
|
||||||
|
type_floatfield = QCC_PR_NewType("fieldfloat", ev_field);
|
||||||
|
type_floatfield->aux_type = type_float;
|
||||||
|
type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float);
|
||||||
|
|
||||||
|
type_function->aux_type = type_void;
|
||||||
|
|
||||||
|
for (i = 0,st = pr_statements16; i < pr_progs->numstatements; i++,st++)
|
||||||
|
{
|
||||||
|
op = &pr_opcodes[st->op];
|
||||||
|
if (st->op >= OP_CALL1 && st->op <= OP_CALL8)
|
||||||
|
{
|
||||||
|
for (p = 0; p < (unsigned int)st->op-OP_CALL0; p++)
|
||||||
|
{
|
||||||
|
ofstype[parmofs[p]] = ofstype[OFS_PARM0+p*3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (op->associative == ASSOC_RIGHT)
|
||||||
|
{ //assignment
|
||||||
|
ofsflags[st->b] |= 1;
|
||||||
|
if (st->b >= OFS_PARM0 && st->b < RESERVED_OFS)
|
||||||
|
parmofs[(st->b-OFS_PARM0)/3] = st->a;
|
||||||
|
|
||||||
|
// if (st->op != OP_STORE_F || st->b>RESERVED_OFS) //optimising compilers fix the OP_STORE_V, it's the storef that becomes meaningless (this is the only time that we need this sort of info anyway)
|
||||||
|
{
|
||||||
|
if (op->type_c && op->type_c != &type_void)
|
||||||
|
ofstype[st->a] = *op->type_c;
|
||||||
|
if (op->type_b && op->type_b != &type_void)
|
||||||
|
ofstype[st->b] = *op->type_b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (op->type_c)
|
||||||
|
{
|
||||||
|
ofsflags[st->c] |= 2;
|
||||||
|
|
||||||
|
if (st->c >= OFS_PARM0 && st->b < RESERVED_OFS) //too complicated
|
||||||
|
parmofs[(st->b-OFS_PARM0)/3] = 0;
|
||||||
|
|
||||||
|
// if (st->op != OP_STORE_F || st->b>RESERVED_OFS) //optimising compilers fix the OP_STORE_V, it's the storef that becomes meaningless (this is the only time that we need this sort of info anyway)
|
||||||
|
{
|
||||||
|
if (op->type_a && op->type_a != &type_void)
|
||||||
|
ofstype[st->a] = *op->type_a;
|
||||||
|
if (op->type_b && op->type_b != &type_void)
|
||||||
|
ofstype[st->b] = *op->type_b;
|
||||||
|
if (op->type_c && op->type_c != &type_void)
|
||||||
|
ofstype[st->c] = *op->type_c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i=0 ; i<pr_progs->numglobaldefs ; i++)
|
||||||
|
{
|
||||||
|
def = &pr_globaldefs16[i];
|
||||||
|
ofsflags[def->ofs] |= 8;
|
||||||
|
switch(def->type)
|
||||||
|
{
|
||||||
|
case ev_float:
|
||||||
|
ofstype[def->ofs] = type_float;
|
||||||
|
break;
|
||||||
|
case ev_string:
|
||||||
|
ofstype[def->ofs] = type_string;
|
||||||
|
break;
|
||||||
|
case ev_vector:
|
||||||
|
ofstype[def->ofs] = type_vector;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pbool Decompile(progfuncs_t *progfuncs, char *fname)
|
||||||
|
{
|
||||||
|
extern progfuncs_t *qccprogfuncs;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int fld=0;
|
||||||
|
eval_t *v;
|
||||||
|
// char *filename;
|
||||||
|
int f, type;
|
||||||
|
|
||||||
|
progstate_t progs, *op;
|
||||||
|
|
||||||
|
qccprogfuncs = progfuncs;
|
||||||
|
op=current_progstate;
|
||||||
|
|
||||||
|
if (!PR_ReallyLoadProgs(progfuncs, fname, -1, &progs, false))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f=SafeOpenWrite("qcdtest/defs.qc", 1024*512);
|
||||||
|
|
||||||
|
writes(f, "//Decompiled code can contain little type info.\r\n#define NOWARNINGS\r\n");
|
||||||
|
|
||||||
|
FigureOutTypes(progfuncs);
|
||||||
|
|
||||||
|
for (i = 1; i < progs.progs->numglobaldefs; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(pr_globaldefs16[i].s_name, "IMMEDIATE"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ofsflags[pr_globaldefs16[i].ofs] & 4)
|
||||||
|
continue; //this is a local.
|
||||||
|
|
||||||
|
if (current_progstate->types)
|
||||||
|
type = progs.types[pr_globaldefs16[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL)].type;
|
||||||
|
else
|
||||||
|
type = pr_globaldefs16[i].type & ~(DEF_SHARED|DEF_SAVEGLOBAL);
|
||||||
|
v = (eval_t *)&((int *)progs.globals)[pr_globaldefs16[i].ofs];
|
||||||
|
|
||||||
|
if (!*pr_globaldefs16[i].s_name)
|
||||||
|
{
|
||||||
|
char mem[64];
|
||||||
|
if (ofsflags[pr_globaldefs16[i].ofs] & 3)
|
||||||
|
{
|
||||||
|
ofsflags[pr_globaldefs16[i].ofs] &= ~8;
|
||||||
|
continue; //this is a constant...
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(mem, "_g_%i", pr_globaldefs16[i].ofs);
|
||||||
|
pr_globaldefs16[i].s_name = malloc(strlen(mem)+1);
|
||||||
|
strcpy(pr_globaldefs16[i].s_name, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case ev_void:
|
||||||
|
writes(f, "void %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_string:
|
||||||
|
if (v->string && *(pr_strings+v->_int))
|
||||||
|
writes(f, "string %s = \"%s\";\r\n", pr_globaldefs16[i].s_name, v->string);
|
||||||
|
else
|
||||||
|
writes(f, "string %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_float:
|
||||||
|
if (v->_float)
|
||||||
|
writes(f, "float %s = %f;\r\n", pr_globaldefs16[i].s_name, v->_float);
|
||||||
|
else
|
||||||
|
writes(f, "float %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_vector:
|
||||||
|
if (v->vector[0] || v->vector[1] || v->vector[2])
|
||||||
|
writes(f, "vector %s = '%f %f %f';\r\n", pr_globaldefs16[i].s_name, v->vector[0], v->vector[1], v->vector[2]);
|
||||||
|
else
|
||||||
|
writes(f, "vector %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
i+=3;//skip the floats
|
||||||
|
break;
|
||||||
|
case ev_entity:
|
||||||
|
writes(f, "entity %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_field:
|
||||||
|
//wierd
|
||||||
|
fld++;
|
||||||
|
switch(pr_fielddefs16[fld].type)
|
||||||
|
{
|
||||||
|
case ev_string:
|
||||||
|
writes(f, ".string %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_float:
|
||||||
|
writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_vector:
|
||||||
|
writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_entity:
|
||||||
|
writes(f, ".float %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_function:
|
||||||
|
writes(f, ".void() %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
writes(f, "field %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_function:
|
||||||
|
//wierd
|
||||||
|
WriteAsmStatements(progfuncs, &progs, ((int *)progs.globals)[pr_globaldefs16[i].ofs], f, pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_pointer:
|
||||||
|
writes(f, "pointer %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_integer:
|
||||||
|
writes(f, "integer %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ev_union:
|
||||||
|
writes(f, "union %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
case ev_struct:
|
||||||
|
writes(f, "struct %s;\r\n", pr_globaldefs16[i].s_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < progs.progs->numfunctions; i++)
|
||||||
|
{
|
||||||
|
WriteAsmStatements(progfuncs, &progs, i, f, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeClose(f);
|
||||||
|
|
||||||
|
current_progstate=op;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue