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:
Spoike 2004-08-23 01:38:21 +00:00
parent d7b2ae0270
commit 7c00f2b190
25 changed files with 26992 additions and 0 deletions

238
engine/qclib/Comprout.c Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

446
engine/qclib/Progsint.h Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

83
engine/qclib/cmdlib.h Normal file
View 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
View 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], &current_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
View 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], &current_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
View 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], &current_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
View 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], &current_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
View 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], &current_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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

528
engine/qclib/pr_multi.c Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

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
View 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
View 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
View 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 *)&current_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