From 5a872df165a3316d3d319e985c3f4e5a16b51107 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 7 Sep 2004 18:16:59 +0000 Subject: [PATCH] All lower case now. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@155 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/qclib/comprout.c | 238 +++ engine/qclib/pr_comp.h | 490 ++++++ engine/qclib/pr_exec.c | 1090 +++++++++++++ engine/qclib/progsint.h | 446 ++++++ engine/qclib/progslib.h | 280 ++++ engine/qclib/qccmain.c | 3201 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 5745 insertions(+) create mode 100644 engine/qclib/comprout.c create mode 100644 engine/qclib/pr_comp.h create mode 100644 engine/qclib/pr_exec.c create mode 100644 engine/qclib/progsint.h create mode 100644 engine/qclib/progslib.h create mode 100644 engine/qclib/qccmain.c diff --git a/engine/qclib/comprout.c b/engine/qclib/comprout.c new file mode 100644 index 000000000..7b528b40c --- /dev/null +++ b/engine/qclib/comprout.c @@ -0,0 +1,238 @@ +//compile routines + +#include "qcc.h" +#undef progfuncs + +char errorfile[128]; +int errorline; + +progfuncs_t *qccprogfuncs; + +#include + +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; +} + diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h new file mode 100644 index 000000000..98e6a45db --- /dev/null +++ b/engine/qclib/pr_comp.h @@ -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; diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c new file mode 100644 index 000000000..a56c83b13 --- /dev/null +++ b/engine/qclib/pr_exec.c @@ -0,0 +1,1090 @@ +#define PROGSUSED +#include "progsint.h" +//#include "editor.h" + +#define HunkAlloc BADGDFG sdfhhsf FHS + + +#define Host_Error Sys_Error + + +//============================================================================= + +/* +================= +PR_PrintStatement +================= +*/ +void PR_PrintStatement (progfuncs_t *progfuncs, dstatement16_t *s) +{ + int i; +printf("PR_PrintStatement is unsupported\n"); +return; + if ( (unsigned)s->op < OP_NUMOPS) + { + printf ("%s ", pr_opcodes[s->op].name); + i = strlen(pr_opcodes[s->op].name); + for ( ; i<10 ; i++) + printf (" "); + } + + if (s->op == OP_IF || s->op == OP_IFNOT) + printf ("%sbranch %i",PR_GlobalString(progfuncs, s->a),s->b); + else if (s->op == OP_GOTO) + { + printf ("branch %i",s->a); + } + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + printf ("%s",PR_GlobalString(progfuncs, s->a)); + printf ("%s", PR_GlobalStringNoContents(progfuncs, s->b)); + } + else + { + if (s->a) + printf ("%s",PR_GlobalString(progfuncs, s->a)); + if (s->b) + printf ("%s",PR_GlobalString(progfuncs, s->b)); + if (s->c) + printf ("%s", PR_GlobalStringNoContents(progfuncs, s->c)); + } + printf ("\n"); +} + +/* +============ +PR_StackTrace +============ +*/ +char *QC_ucase(char *str) +{ + static char s[1024]; + strcpy(s, str); + str = s; + + while(*str) + { + if (*str >= 'a' && *str <= 'z') + *str = *str - 'a' + 'A'; + str++; + } + return s; +} + +void PR_StackTrace (progfuncs_t *progfuncs) +{ + dfunction_t *f; + int i; + int progs; + +#ifdef STACKTRACE + int arg; + int *globalbase; +#endif + progs = -1; + + if (pr_depth == 0) + { + printf ("\n"); + return; + } + +#ifdef STACKTRACE + globalbase = (int *)pr_globals + pr_xfunction->parm_start - pr_xfunction->locals; +#endif + + pr_stack[pr_depth].f = pr_xfunction; + for (i=pr_depth ; i>0 ; i--) + { + f = pr_stack[i].f; + + if (!f) + { + printf ("\n"); + } + else + { + if (pr_stack[i].progsnum != progs) + { + progs = pr_stack[i].progsnum; + + printf ("<%s>\n", pr_progstate[progs].filename); + } + if (!*f->s_file) + printf ("stripped : %s\n", f->s_name); + else + printf ("%12s : %s\n", f->s_file, f->s_name); + +#ifdef STACKTRACE + + for (arg = 0; arg < f->locals; arg++) + { + ddef16_t *local; + local = ED_GlobalAtOfs16(progfuncs, f->parm_start+arg); + if (!local) + { + printf(" ofs %i: %f : %i\n", f->parm_start+arg, *(float *)(globalbase - f->locals+arg), *(int *)(globalbase - f->locals+arg) ); + } + else + { + printf(" %s: %s\n", local->s_name, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg))); + if (local->type == ev_vector) + arg+=2; + } + } + + if (i == pr_depth) + globalbase = localstack + localstack_used; + else + globalbase -= f->locals; +#endif + } + } +} + +/* +============ +PR_Profile_f + +============ +*/ +/* +void PR_Profile_f (void) +{ + dfunction_t *f, *best; + int max; + int num; + unsigned int i; + + num = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; inumfunctions ; i++) + { + f = &pr_functions[i]; + if (f->profile > max && f->first_statement >=0) + { + max = f->profile; + best = f; + } + } + if (best) + { + if (num < 10) + printf ("%7i %s\n", best->profile, best->s_name); + num++; + best->profile = 0; + } + } while (best); +} +*/ + + +/* +============ +PR_RunError + +Aborts the currently executing function +============ +*/ +void VARGS PR_RunError (progfuncs_t *progfuncs, char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + Q_vsnprintf (string,sizeof(string)-1, error,argptr); + va_end (argptr); + +// PR_PrintStatement (pr_statements + pr_xstatement); + PR_StackTrace (progfuncs); + printf ("%s\n", string); + +//editbadfile(pr_strings + pr_xfunction->s_file, -1); + + pr_depth = 0; // dump the stack so host_error can shutdown functions + prinst->exitdepth = 0; + + Abort ("Program error"); +} + +/* +============================================================================ +PR_ExecuteProgram + +The interpretation main loop +============================================================================ +*/ + +/* +==================== +PR_EnterFunction + +Returns the new program statement counter +==================== +*/ +int PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum) +{ + int i, j, c, o; + + pr_stack[pr_depth].s = pr_xstatement; + pr_stack[pr_depth].f = pr_xfunction; + pr_stack[pr_depth].progsnum = progsnum; + pr_depth++; + if (pr_depth >= MAX_STACK_DEPTH) + { + printf ("stack overflow"); + PR_StackTrace (progfuncs); + pr_depth--; + return pr_xstatement; + } + +// save off any locals that the new function steps on (to a side place, fromwhere they are restored on exit) + c = f->locals; + if (localstack_used + c > LOCALSTACK_SIZE) + PR_RunError (progfuncs, "PR_ExecuteProgram: locals stack overflow\n"); + + for (i=0 ; i < c ; i++) + localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i]; + localstack_used += c; + +// copy parameters (set initial values) + o = f->parm_start; + for (i=0 ; inumparms ; i++) + { + for (j=0 ; jparm_size[i] ; j++) + { + ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j]; + o++; + } + } + + pr_xfunction = f; + return f->first_statement - 1; // offset the s++ +} + +/* +==================== +PR_LeaveFunction +==================== +*/ +int PR_LeaveFunction (progfuncs_t *progfuncs) +{ + int i, c; + + if (pr_depth <= 0) + Sys_Error ("prog stack underflow"); + +// restore locals from the stack + c = pr_xfunction->locals; + localstack_used -= c; + if (localstack_used < 0) + PR_RunError (progfuncs, "PR_ExecuteProgram: locals stack underflow\n"); + + for (i=0 ; i < c ; i++) + ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i]; + +// up stack + pr_depth--; + PR_MoveParms(progfuncs, pr_stack[pr_depth].progsnum, pr_typecurrent); + PR_SwitchProgs(progfuncs, pr_stack[pr_depth].progsnum); + pr_xfunction = pr_stack[pr_depth].f; + return pr_stack[pr_depth].s; +} + +ddef32_t *ED_FindLocalOrGlobal(progfuncs_t *progfuncs, char *name, eval_t **val) +{ + static ddef32_t def; + ddef32_t *def32; + ddef16_t *def16; + int i; + + switch (pr_progstate[pr_typecurrent].intsize) + { + case 16: + case 24: + //this gets parms fine, but not locals + if (pr_xfunction) + for (i = 0; i < pr_xfunction->numparms; i++) + { + def16 = ED_GlobalAtOfs16(progfuncs, pr_xfunction->parm_start+i); + if (!def16) + continue; + if (!strcmp(def16->s_name, name)) + { + *val = (eval_t *)&pr_progstate[pr_typecurrent].globals[pr_xfunction->parm_start+i]; + + //we need something like this for functions that are not the top layer + // *val = (eval_t *)&localstack[localstack_used-pr_xfunction->numparms*4]; + def.ofs = def16->ofs; + def.s_name = def16->s_name; + def.type = def16->type; + return &def; + } + } + def16 = ED_FindGlobal16(progfuncs, name); + if (!def16) + return NULL; + def.ofs = def16->ofs; + def.type = def16->type; + def.s_name = def16->s_name; + def32 = &def; + break; + case 32: + //this gets parms fine, but not locals + if (pr_xfunction) + for (i = 0; i < pr_xfunction->numparms; i++) + { + def32 = ED_GlobalAtOfs32(progfuncs, pr_xfunction->parm_start+i); + if (!def32) + continue; + if (!strcmp(def32->s_name, name)) + { + *val = (eval_t *)&pr_progstate[pr_typecurrent].globals[pr_xfunction->parm_start+i]; + + //we need something like this for functions that are not the top layer + // *val = (eval_t *)&localstack[localstack_used-pr_xfunction->numparms*4]; + return def32; + } + } + def32 = ED_FindGlobal32(progfuncs, name); + if (!def32) + return NULL; + break; + default: + Sys_Error("Bad int size in ED_FindLocalOrGlobal"); + def32 = NULL; + } + + *val = (eval_t *)&pr_progstate[pr_typecurrent].globals[def32->ofs]; + return &def; +} + +char *COM_TrimString(char *str) +{ + int i; + static char buffer[256]; + while (*str <= ' ' && *str>'\0') + str++; + + for (i = 0; i < 255; i++) + { + if (*str <= ' ') + break; + buffer[i] = *str++; + } + buffer[i] = '\0'; + return buffer; +} + +char *EvaluateDebugString(progfuncs_t *progfuncs, char *key) +{ + static char buf[256]; + char *c, *c2; + ddef32_t *def; + fdef_t *fdef; + eval_t *val; + char *assignment; + int type; + + assignment = strchr(key, '='); + if (assignment) + *assignment = '\0'; + + c = strchr(key, '.'); + if (c) *c = '\0'; + def = ED_FindLocalOrGlobal(progfuncs, key, &val); + if (c) *c = '.'; + if (!def) + { + return "(Bad string)"; + } + //go through ent vars + + c = strchr(key, '.'); + while(c) + { + c2 = c+1; + c = strchr(c2, '.'); + type = def->type &~DEF_SAVEGLOBAL; + if (current_progstate->types) + type = current_progstate->types[type].type; + if (type != ev_entity) + return "'.' without entity"; + if (c)*c = '\0'; + fdef = ED_FindField(progfuncs, COM_TrimString(c2)); + if (c)*c = '.'; + if (!fdef) + return "(Bad string)"; + val = (eval_t *) (((char *)PROG_TO_EDICT(val->_int) + externs->edictsize) + fdef->ofs*4); + def->type = fdef->type; + } + + if (assignment) + { + assignment++; + switch (def->type&~DEF_SAVEGLOBAL) + { + case ev_string: + *(string_t *)val = ED_NewString (progfuncs, assignment)-progfuncs->stringtable; + break; + + case ev_float: + *(float *)val = (float)atof (assignment); + break; + + case ev_integer: + *(int *)val = atoi (assignment); + break; + +/* case ev_vector: + strcpy (string, assignment); + v = string; + w = string; + for (i=0 ; i<3 ; i++) + { + while (*v && *v != ' ') + v++; + *v = 0; + ((float *)d)[i] = (float)atof (w); + w = v = v+1; + } + break; +*/ + case ev_entity: + *(int *)val = EDICT_TO_PROG(EDICT_NUM(progfuncs, atoi (assignment))); + break; + + case ev_field: + fdef = ED_FindField (progfuncs, assignment); + if (!fdef) + { + sprintf(buf, "Can't find field %s\n", assignment); + return buf; + } + *(int *)val = G_INT(fdef->ofs); + break; +/* + case ev_function: + if (s[1]==':'&&s[2]=='\0') + { + *(func_t *)val = 0; + return true; + } + func = ED_FindFunction (assignment, &i, -1); + if (!func) + { + printf ("Can't find function %s\n", assignment); + return false; + } + *(func_t *)val = (func - pr_progstate[i].functions) | (i<<24); + break; +*/ + default: + break; + + } + } + strcpy(buf, PR_ValueString(progfuncs, def->type, val)); + + return buf; +} + +int debugstatement; +//int EditorHighlightLine(window_t *wnd, int line); +void SetExecutionToLine(progfuncs_t *progfuncs, int linenum) +{ + int pn = pr_typecurrent; + int snum; + dfunction_t *f = pr_xfunction; + + switch(current_progstate->intsize) + { + case 16: + for (snum = f->first_statement; pr_progstate[pn].linenums[snum] < linenum; snum++) + { + if (pr_statements16[snum].op == OP_DONE) + return; + } + break; + case 24: + case 32: + for (snum = f->first_statement; pr_progstate[pn].linenums[snum] < linenum; snum++) + { + if (pr_statements32[snum].op == OP_DONE) + return; + } + break; + default: + Sys_Error("Bad intsize"); + snum = 0; + } + debugstatement = snum; +// EditorHighlightLine(editwnd, pr_progstate[pn].linenums[snum]); +} + +//0 clear. 1 set, 2 toggle, 3 check +int PR_ToggleBreakpoint(progfuncs_t *progfuncs, char *filename, int linenum, int flag) //write alternate route to work by function name. +{ + int ret=0; + unsigned int fl; + unsigned int i; + int pn = pr_typecurrent; + dfunction_t *f; + int op; + + for (pn = 0; pn < maxprogs; pn++) + { + if (!pr_progstate || !pr_progstate[pn].progs) + continue; + + if (linenum) //linenum is set means to set the breakpoint on a file and line + { + if (!pr_progstate[pn].linenums) + continue; + + for (f = pr_progstate[pn].functions, fl = 0; fl < pr_progstate[pn].progs->numfunctions; f++, fl++) + { + if (!strcmp(f->s_file, filename)) + { + for (i = f->first_statement; ; i++) + { + if (pr_progstate[pn].linenums[i] >= linenum) + { + fl = pr_progstate[pn].linenums[i]; + for (; ; i++) + { + if ((unsigned int)pr_progstate[pn].linenums[i] > fl) + break; + + switch(pr_progstate[pn].intsize) + { + case 16: + op = ((dstatement16_t*)pr_progstate[pn].statements + i)->op; + break; + case 24: + case 32: + op = ((dstatement32_t*)pr_progstate[pn].statements + i)->op; + break; + default: + Sys_Error("Bad intsize"); + op = 0; + } + switch (flag) + { + default: + if (op & 0x8000) + { + op &= ~0x8000; + ret = false; + flag = 0; + } + else + { + op |= 0x8000; + ret = true; + flag = 1; + } + break; + case 0: + op &= ~0x8000; + ret = false; + break; + case 1: + op |= 0x8000; + ret = true; + break; + case 3: + if (op & 0x8000) + return true; + } + switch(pr_progstate[pn].intsize) + { + case 16: + ((dstatement16_t*)pr_progstate[pn].statements + i)->op = op; + break; + case 24: + case 32: + ((dstatement32_t*)pr_progstate[pn].statements + i)->op = op; + break; + default: + Sys_Error("Bad intsize"); + op = 0; + } + } + goto cont; + } + } + } + } + } + else //set the breakpoint on the first statement of the function specified. + { + for (f = pr_progstate[pn].functions, fl = 0; fl < pr_progstate[pn].progs->numfunctions; f++, fl++) + { + if (!strcmp(f->s_name, filename)) + { + i = f->first_statement; + switch(pr_progstate[pn].intsize) + { + case 16: + op = ((dstatement16_t*)pr_progstate[pn].statements + i)->op; + break; + case 24: + case 32: + op = ((dstatement32_t*)pr_progstate[pn].statements + i)->op; + break; + default: + Sys_Error("Bad intsize"); + } + switch (flag) + { + default: + if (op & 0x8000) + { + op &= ~0x8000; + ret = false; + flag = 0; + } + else + { + op |= 0x8000; + ret = true; + flag = 1; + } + break; + case 0: + op &= ~0x8000; + ret = false; + break; + case 1: + op |= 0x8000; + ret = true; + break; + case 3: + if (op & 0x8000) + return true; + } + switch(pr_progstate[pn].intsize) + { + case 16: + ((dstatement16_t*)pr_progstate[pn].statements + i)->op = op; + break; + case 24: + case 32: + ((dstatement32_t*)pr_progstate[pn].statements + i)->op = op; + break; + default: + Sys_Error("Bad intsize"); + } + break; + } + } + } +cont: + continue; + } + + return ret; +} + +int ShowStep(progfuncs_t *progfuncs, int statement) +{ +// return statement; +// texture realcursortex; +static int lastline = 0; +static char *lastfile = NULL; + + int pn = pr_typecurrent; + int i; + dfunction_t *f = pr_xfunction; + + if (f && pr_progstate[pn].linenums) + { + if (lastline == pr_progstate[pn].linenums[statement] && lastfile == f->s_file) + return statement; //no info/same line as last time + + lastline = pr_progstate[pn].linenums[statement]; + lastfile = f->s_file; + + lastline = externs->useeditor(lastfile, lastline, 0, NULL); + + if (pr_progstate[pn].linenums[statement] != lastline) + { + for (i = f->first_statement; ; i++) + { + if (lastline == pr_progstate[pn].linenums[i]) + { + return i; + } + else if (lastline <= pr_progstate[pn].linenums[i]) + { + return statement; + } + } + } + } + else if (f) //annoying. + { + externs->useeditor(f->s_file, -1, 0, &f->s_name); + return statement; + } + + + return statement; +} + +//DMW: all pointer functions are modified to be absoloute pointers from NULL not sv_edicts +/* +==================== +PR_ExecuteProgram +==================== +*/ +void PR_ExecuteCode (progfuncs_t *progfuncs, int s) +{ + static dstatement16_t fakeop16; + static dstatement32_t fakeop32; + + eval_t *t, *swtch=NULL; + + int swtchtype; + dstatement16_t *st16; + dstatement32_t *st32; + dfunction_t *newf; + int runaway; + int i; + int p; + edictrun_t *ed; + eval_t *ptr; + + float *glob; + + int fnum; + + runaway = 100000; + + prinst->continuestatement = -1; + +#define PRBOUNDSCHECK +#define RUNAWAYCHECK() if (!--runaway) { pr_xstatement = st-pr_statements; PR_StackTrace(progfuncs); printf ("runaway loop error"); pr_depth = prinst->exitdepth;return;} + +#define OPA ((eval_t *)&glob[st->a]) +#define OPB ((eval_t *)&glob[st->b]) +#define OPC ((eval_t *)&glob[st->c]) + +restart: //jumped to when the progs might have changed. + glob = pr_globals; + switch (current_progstate->intsize) + { + case 16: +#define INTSIZE 16 + st16 = &pr_statements16[s]; + while (pr_trace) + { + #define DEBUGABLE + #include "execloop16d.h" + #undef DEBUGABLE + } + + while(1) + { + #include "execloop.h" + } +#undef INTSIZE + Sys_Error("PR_ExecuteProgram - should be unreachable"); + break; + case 24: + case 32: +#define INTSIZE 32 + st32 = &pr_statements32[s]; + while (pr_trace) + { + #define DEBUGABLE + #include "execloop32d.h" + #undef DEBUGABLE + } + + while(1) + { + #include "execloop32.h" + } +#undef INTSIZE + Sys_Error("PR_ExecuteProgram - should be unreachable"); + break; + default: + Sys_Error("PR_ExecuteProgram - bad intsize"); + } +} + + +void PR_ExecuteProgram (progfuncs_t *progfuncs, func_t fnum) +{ + dfunction_t *f; + int i; + progsnum_t initial_progs; + int oldexitdepth; + + int s; + + int newprogs = (fnum & 0xff000000)>>24; + + initial_progs = pr_typecurrent; + if (newprogs != initial_progs) + { + if (newprogs >= maxprogs || !&pr_progstate[newprogs].globals) //can happen with hexen2... + { + printf("PR_ExecuteProgram: tried branching into invalid progs\n"); + return; + } + PR_MoveParms(progfuncs, newprogs, pr_typecurrent); + PR_SwitchProgs(progfuncs, newprogs); + } + + if (!(fnum & ~0xff000000) || (signed)(fnum & ~0xff000000) >= pr_progs->numfunctions) + { +// if (pr_global_struct->self) +// ED_Print (PROG_TO_EDICT(pr_global_struct->self)); + printf("PR_ExecuteProgram: NULL function from exe\n"); +// Host_Error ("PR_ExecuteProgram: NULL function from exe"); + +// PR_MoveParms(0, pr_typecurrent); + PR_SwitchProgs(progfuncs, 0); + return; + } + + oldexitdepth = prinst->exitdepth; + + f = &pr_functions[fnum & ~0xff000000]; + + if (f->first_statement < 0) + { // negative statements are built in functions + i = -f->first_statement; + + if (i < externs->numglobalbuiltins) + (*externs->globalbuiltins[i]) (progfuncs, (struct globalvars_s *)current_progstate->globals); + else + { + i -= externs->numglobalbuiltins; + if (i > current_progstate->numbuiltins) + { + printf ("Bad builtin call number %i (from exe)\n", -f->first_statement); + // PR_MoveParms(p, pr_typecurrent); + PR_SwitchProgs(progfuncs, initial_progs); + return; + } + current_progstate->builtins [i] (progfuncs, (struct globalvars_s *)current_progstate->globals); + } + PR_MoveParms(progfuncs, initial_progs, pr_typecurrent); + PR_SwitchProgs(progfuncs, initial_progs); + return; + } + + if (pr_trace) + pr_trace--; + +// make a stack frame + prinst->exitdepth = pr_depth; + + s = PR_EnterFunction (progfuncs, f, initial_progs); + + PR_ExecuteCode(progfuncs, s); + + + PR_MoveParms(progfuncs, initial_progs, pr_typecurrent); + PR_SwitchProgs(progfuncs, initial_progs); + + prinst->exitdepth = oldexitdepth; +} + + + + + + + + + + +typedef struct { + int fnum; + int progsnum; + int statement; +} qcthreadstack_t; +typedef struct qcthread_s { + int fstackdepth; + qcthreadstack_t fstack[MAX_STACK_DEPTH]; + int lstackused; + int lstack[LOCALSTACK_SIZE]; + int xstatement; + int xfunction; + progsnum_t xprogs; +} qcthread_t; + +struct qcthread_s *PR_ForkStack(progfuncs_t *progfuncs) +{ //QC code can call builtins that call qc code. + //to get around the problems of restoring the builtins we simply don't save the thread over the builtin. + int i, l; + int ed = prinst->exitdepth; + int localsoffset, baselocalsoffset; + qcthread_t *thread = memalloc(sizeof(qcthread_t)); + dfunction_t *f; + + //copy out the functions stack. + for (i = 0,localsoffset=0; i < ed; i++) + { + if (i+1 == pr_depth) + f = pr_xfunction; + else + f = pr_stack[i+1].f; + localsoffset += f->locals; //this is where it crashes + } + baselocalsoffset = localsoffset; + for (i = ed; i < pr_depth; i++) + { + thread->fstack[i-ed].fnum = pr_stack[i].f - pr_progstate[pr_stack[i].progsnum].functions; + thread->fstack[i-ed].progsnum = pr_stack[i].progsnum; + thread->fstack[i-ed].statement = pr_stack[i].s; + + if (i+1 == pr_depth) + f = pr_xfunction; + else + f = pr_stack[i+1].f; + localsoffset += f->locals; + } + thread->fstackdepth = pr_depth - ed; + + for (i = pr_depth - 1; i >= ed ; i--) + { + if (i+1 == pr_depth) + f = pr_xfunction; + else + f = pr_stack[i+1].f; + localsoffset -= f->locals; + for (l = 0; l < f->locals; l++) + { + thread->lstack[localsoffset-baselocalsoffset + l ] = ((int *)pr_globals)[f->parm_start + l]; + ((int *)pr_globals)[f->parm_start + l] = localstack[localsoffset+l]; //copy the old value into the globals (so the older functions have the correct locals. + } + } + + for (i = ed; i < pr_depth ; i++) //we need to get the locals back to how they were. + { + if (i+1 == pr_depth) + f = pr_xfunction; + else + f = pr_stack[i+1].f; + + for (l = 0; l < f->locals; l++) + { + ((int *)pr_globals)[f->parm_start + l] = thread->lstack[localsoffset-baselocalsoffset + l]; + } + localsoffset += f->locals; + } + thread->lstackused = localsoffset - baselocalsoffset; + + thread->xstatement = pr_xstatement; + thread->xfunction = pr_xfunction - pr_progstate[pr_typecurrent].functions; + thread->xprogs = pr_typecurrent; + + return thread; +} + +void PR_ResumeThread (progfuncs_t *progfuncs, struct qcthread_s *thread) +{ + dfunction_t *f, *oldf; + int i,l,ls; + progsnum_t initial_progs; + int oldexitdepth; + + int s; + + progsnum_t prnum = thread->xprogs; + int fnum = thread->xfunction; + + if (localstack_used + thread->lstackused > LOCALSTACK_SIZE) + PR_RunError(progfuncs, "Too many locals on resumtion of QC thread\n"); + + if (pr_depth + thread->fstackdepth > MAX_STACK_DEPTH) + PR_RunError(progfuncs, "Too large stack on resumtion of QC thread\n"); + + + //do progs switching stuff as appropriate. (fteqw only) + initial_progs = pr_typecurrent; + PR_MoveParms(progfuncs, prnum, pr_typecurrent); + PR_SwitchProgs(progfuncs, prnum); + + + oldexitdepth = prinst->exitdepth; + prinst->exitdepth = pr_depth; + + ls = 0; + //add on the callstack. + for (i = 0; i < thread->fstackdepth; i++) + { + if (pr_depth == prinst->exitdepth) + { + pr_stack[pr_depth].f = pr_xfunction; + pr_stack[pr_depth].s = pr_xstatement; + pr_stack[pr_depth].progsnum = initial_progs; + } + else + { + pr_stack[pr_depth].progsnum = thread->fstack[i].progsnum; + pr_stack[pr_depth].f = pr_progstate[thread->fstack[i].progsnum].functions + thread->fstack[i].fnum; + pr_stack[pr_depth].s = thread->fstack[i].statement; + } + + if (i+1 == thread->fstackdepth) + f = &pr_functions[fnum]; + else + f = pr_progstate[thread->fstack[i+1].progsnum].functions + thread->fstack[i+1].fnum; + for (l = 0; l < f->locals; l++) + { + localstack[localstack_used++] = ((int *)pr_globals)[f->parm_start + l]; + ((int *)pr_globals)[f->parm_start + l] = thread->lstack[ls++]; + } + + pr_depth++; + } + + if (ls != thread->lstackused) + PR_RunError(progfuncs, "Thread stores incorrect locals count\n"); + + + f = &pr_functions[fnum]; + +// thread->lstackused -= f->locals; //the current function is the odd one out. + + //add on the locals stack + memcpy(localstack+localstack_used, thread->lstack, sizeof(int)*thread->lstackused); + localstack_used += thread->lstackused; + + //bung the locals of the current function on the stack. +// for (i=0 ; i < f->locals ; i++) +// ((int *)pr_globals)[f->parm_start + i] = 0xff00ff00;//thread->lstack[thread->lstackused+i]; + + +// PR_EnterFunction (progfuncs, f, initial_progs); + oldf = pr_xfunction; + pr_xfunction = f; + s = thread->xstatement; + + PR_ExecuteCode(progfuncs, s); + + + PR_MoveParms(progfuncs, initial_progs, pr_typecurrent); + PR_SwitchProgs(progfuncs, initial_progs); + + prinst->exitdepth = oldexitdepth; + pr_xfunction = oldf; +} + +void PR_AbortStack (progfuncs_t *progfuncs) +{ + while(pr_depth > prinst->exitdepth+1) + PR_LeaveFunction(progfuncs); + prinst->continuestatement = 0; +} + diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h new file mode 100644 index 000000000..0c724c3bf --- /dev/null +++ b/engine/qclib/progsint.h @@ -0,0 +1,446 @@ +#ifdef WIN32 + +#ifndef AVAIL_ZLIB +#ifdef _MSC_VER +//#define AVAIL_ZLIB +#endif +#endif + +#include + +enum{false, true}; +#else +#include +#include + +#include +#include +#include +#include + +#ifndef __declspec +#define __declspec(mode) +#endif +typedef enum{false, true} boolean; +//#define _inline inline +#endif +typedef unsigned char qbyte; +#include + +#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 diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h new file mode 100644 index 000000000..dcd085602 --- /dev/null +++ b/engine/qclib/progslib.h @@ -0,0 +1,280 @@ +/*#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); + + int lastcalledbuiltinnumber; +}; + +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 diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c new file mode 100644 index 000000000..7d64141ba --- /dev/null +++ b/engine/qclib/qccmain.c @@ -0,0 +1,3201 @@ +#ifndef MINIMAL + +#define PROGSUSED +#include "qcc.h" +int mkdir(const char *path); + +int outputversion; + +char QCC_copyright[1024]; +int QCC_packid; +char QCC_Packname[5][128]; + +extern QCC_def_t *functemps; //floats/strings/funcs/ents... + +extern int optres_test1; +extern int optres_test2; + +int writeasm; + + +pbool QCC_PR_SimpleGetToken (void); +void QCC_PR_LexWhitespace (void); + +void *FS_ReadToMem(char *fname, void *membuf, int *len); +void FS_CloseFromMem(void *mem); + +struct qcc_includechunk_s *currentchunk; + +unsigned int MAX_REGS = 32768; + +int MAX_STRINGS = 1000000; +int MAX_GLOBALS = 16384; +int MAX_FIELDS = 1024; +int MAX_STATEMENTS = 65536; +int MAX_FUNCTIONS = 8192; +int MAX_CONSTANTS; +int max_temps; + +int *qcc_tempofs; +int tempsstart; +int numtemps; + + +pbool newstylesource; +char destfile[1024]; + +float *qcc_pr_globals; +unsigned int numpr_globals; + +char *strings; +int strofs; + +QCC_dstatement_t *statements; +int numstatements; +int *statement_linenums; + +QCC_dfunction_t *functions; +int numfunctions; + +QCC_ddef_t *qcc_globals; +int numglobaldefs; + +QCC_ddef_t *fields; +int numfielddefs; + +//typedef char PATHSTRING[MAX_DATA_PATH]; + +PATHSTRING *precache_sounds; +int *precache_sounds_block; +int numsounds; + +PATHSTRING *precache_textures; +int *precache_textures_block; +int numtextures; + +PATHSTRING *precache_models; +int *precache_models_block; +int nummodels; + +PATHSTRING *precache_files; +int *precache_files_block; +int numfiles; + +extern int numCompilerConstants; +hashtable_t compconstantstable; +hashtable_t globalstable; +hashtable_t localstable; +hashtable_t floatconstdefstable; +hashtable_t stringconstdefstable; + +pbool qccwarningdisabled[WARN_MAX]; + +qcc_targetformat_t qcc_targetformat; + +pbool bodylessfuncs; + +QCC_type_t *qcc_typeinfo; +int numtypeinfos; +int maxtypeinfos; + + +struct { + char *name; + int index; +} warningnames[] = +{ + {"Q302", WARN_NOTREFERENCED}, +// {"", WARN_NOTREFERENCEDCONST}, +// {"", WARN_CONFLICTINGRETURNS}, + {"Q105", WARN_TOOFEWPARAMS}, + {"Q101", WARN_TOOMANYPARAMS}, +// {"", WARN_UNEXPECTEDPUNCT}, + {"Q106", WARN_ASSIGNMENTTOCONSTANT}, + {"Q203", WARN_MISSINGRETURNVALUE}, + {"Q204", WARN_WRONGRETURNTYPE}, + {"Q205", WARN_POINTLESSSTATEMENT}, + {"Q206", WARN_MISSINGRETURN}, + {"Q207", WARN_DUPLICATEDEFINITION}, + {"Q100", WARN_PRECOMPILERMESSAGE}, +// {"", WARN_STRINGTOOLONG}, +// {"", WARN_BADTARGET}, + {"Q120", WARN_BADPRAGMA}, +// {"", WARN_HANGINGSLASHR}, +// {"", WARN_NOTDEFINED}, +// {"", WARN_SWITCHTYPEMISMATCH}, +// {"", WARN_CONFLICTINGUNIONMEMBER}, +// {"", WARN_KEYWORDDISABLED}, +// {"", WARN_ENUMFLAGS_NOTINTEGER}, +// {"", WARN_ENUMFLAGS_NOTBINARY}, +// {"", WARN_CASEINSENSATIVEFRAMEMACRO}, + {"Q111", WARN_DUPLICATELABEL}, + {"Q201", WARN_ASSIGNMENTINCONDITIONAL}, + {"F300", WARN_DEADCODE}, + {NULL} +}; + +optimisations_t optimisations[] = +{ + //level 0 = no optimisations + //level 1 = size optimisations + //level 2 = speed optimisations + //level 3 = dodgy optimisations. + //level 4 = experimental... + {&opt_assignments, "t", 1, 2, "assignments"}, + {&opt_shortenifnots, "i", 1, 2, "shortenifs"}, + {&opt_nonvec_parms, "p", 1, 2, "nonvec_parms"}, + {&opt_constant_names, "c", 2, 1, "constant_names"}, + {&opt_constant_names_strings, "cs", 3, 1, "constant_names_strings"}, + {&opt_dupconstdefs, "d", 1, 2, "dupconstdefs"}, + {&opt_noduplicatestrings, "s", 1, 0, "noduplicatestrings"}, + {&opt_locals, "l", 1, 1, "locals"}, + {&opt_function_names, "n", 1, 1, "function_names"}, + {&opt_filenames, "f", 1, 1, "filenames"}, + {&opt_unreferenced, "u", 1, 2, "unreferenced"}, + {&opt_overlaptemps, "r", 1, 2, "overlaptemps"}, + {&opt_constantarithmatic, "a", 1, 2, "constantarithmatic"}, + {&opt_precache_file, "pf", 2, 0, "precache_file"}, + {&opt_return_only, "ro", 3, 0, "return_only"}, + {&opt_compound_jumps, "cj", 3, 0, "compound_jumps"}, +// {&opt_comexprremoval, "cer", 4, 0, "expression_removal"}, //this would be too hard... + {&opt_stripfunctions, "sf", 3, 0, "strip_functions"}, + {&opt_locals_marshalling, "lm", 4, 1, "locals_marshalling"}, + {&opt_logicops, "o", 2, 0, "logicops"}, + {NULL} +}; + + +struct { + pbool *enabled; + pbool defaultval; + char *name; +} compiler_flag[] = { + //keywords + {&keyword_var, true, "var"}, + {&keyword_thinktime, false, "thinktime"}, + {&keyword_switch, true, "switch"}, + {&keyword_for, true, "for"}, + {&keyword_case, true, "case"}, + {&keyword_default, true, "default"}, + {&keyword_do, true, "do"}, + {&keyword_asm, true, "asm"}, + {&keyword_goto, true, "goto"}, + {&keyword_break, true, "break"}, + {&keyword_continue, true, "continue"}, + {&keyword_state, false, "state"}, + {&keyword_string, true, "string"}, + {&keyword_float, true, "float"}, + {&keyword_entity, true, "entity"}, + {&keyword_vector, true, "vector"}, + {&keyword_const, true, "const"}, + {&keyword_integer, true, "integer"}, + {&keyword_int, true, "int"}, + {&keyword_class, true, "class"}, + + //options + {&keywords_coexist, true, "kce"}, + {&output_parms, false, "parms"}, //controls weather to define PARMx for the parms + {&autoprototype, false, "autoproto"}, + {&writeasm, false, "wasm"}, + {NULL} +}; + +struct { + qcc_targetformat_t target; + char *name; +} targets[] = { + {QCF_STANDARD, "q1"}, + {QCF_STANDARD, "standard"}, + {QCF_STANDARD, "quakec"}, + {QCF_HEXEN2, "h2"}, + {QCF_HEXEN2, "hexen2"}, + {QCF_KK7, "kk7"}, + {QCF_KK7, "bigprogs"}, + {QCF_KK7, "version7"}, + {QCF_KK7, "kkqwsv"}, + {QCF_FTE, "fte"}, + {0, NULL} +}; + +/* +================= +BspModels + +Runs qbsp and light on all of the models with a .bsp extension +================= +*/ +int QCC_CheckParm (char *check); + +void QCC_BspModels (void) +{ + int p; + char *gamedir; + int i; + char *m; + char cmd[1024]; + char name[256]; + + p = QCC_CheckParm ("-bspmodels"); + if (!p) + return; + if (p == myargc-1) + QCC_Error (ERR_BADPARMS, "-bspmodels must preceed a game directory"); + gamedir = myargv[p+1]; + + for (i=0 ; istrings ; s--) + if (!strcmp(s, str)) + return s-strings; + + old = strofs; + strcpy (strings+strofs, str); + strofs += strlen(str)+1; + return old; +} + +void QCC_PrintStrings (void) +{ + int i, l, j; + + for (i=0 ; is_file, strings + d->s_name, d->first_statement, d->parm_start); + for (j=0 ; jnumparms ; j++) + printf ("%i ",d->parm_size[j]); + printf (")\n"); + } +}*/ + +void QCC_PrintFields (void) +{ + int i; + QCC_ddef_t *d; + + for (i=0 ; iofs, d->type, strings + d->s_name); + } +} + +void QCC_PrintGlobals (void) +{ + int i; + QCC_ddef_t *d; + + for (i=0 ; iofs, d->type, strings + d->s_name); + } +} + +int encode(int len, int method, char *in, int handle); +int WriteSourceFiles(int h, dprograms_t *progs, pbool sourceaswell) +{ + includeddatafile_t *idf; + qcc_cachedsourcefile_t *f; + int num=0; + int ofs; + + /* + for (f = qcc_sourcefile; f ; f=f->next) + { + if (f->type == FT_CODE && !sourceaswell) + continue; + + SafeWrite(h, f->filename, strlen(f->filename)+1); + i = LittleLong(f->size); + SafeWrite(h, &i, sizeof(int)); + + i = LittleLong(encrpytmode); + SafeWrite(h, &i, sizeof(int)); + + if (encrpytmode) + for (i = 0; i < f->size; i++) + f->file[i] ^= 0xA5; + + SafeWrite(h, f->file, f->size); + }*/ + + for (f = qcc_sourcefile,num=0; f ; f=f->next) + { + if (f->type == FT_CODE && !sourceaswell) + continue; + + num++; + } + if (!num) + return 0; + idf = qccHunkAlloc(sizeof(includeddatafile_t)*num); + for (f = qcc_sourcefile,num=0; f ; f=f->next) + { + if (f->type == FT_CODE && !sourceaswell) + continue; + + strcpy(idf[num].filename, f->filename); + idf[num].size = f->size; +#ifdef AVAIL_ZLIB + idf[num].compmethod = 2; +#else + idf[num].compmethod = 1; +#endif + idf[num].ofs = SafeSeek(h, 0, SEEK_CUR); + idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h); + num++; + } + + ofs = SafeSeek(h, 0, SEEK_CUR); + SafeWrite(h, &num, sizeof(int)); + SafeWrite(h, idf, sizeof(includeddatafile_t)*num); + + qcc_sourcefile = NULL; + + return ofs; +} + +void QCC_InitData (void) +{ + static char parmname[12][MAX_PARMS]; + static temp_t ret_temp; + int i; + + qcc_sourcefile = NULL; + + numstatements = 1; + strofs = 1; + numfunctions = 1; + numglobaldefs = 1; + numfielddefs = 1; + + def_ret.ofs = OFS_RETURN; + def_ret.name = "return"; + def_ret.temp = &ret_temp; + def_ret.constant = false; + ret_temp.ofs = def_ret.ofs; + ret_temp.scope = NULL; + ret_temp.size = 3; + ret_temp.next = NULL; + for (i=0 ; inext) + { + if (d->type->type == ev_function && !d->scope)// function parms are ok + { + if (d->initialized != 1) + { + SafeWrite(handle, d->name, strlen(d->name)+1); + ret++; + } + } + } + + return ret; +} + +//marshalled locals remaps all the functions to use the range MAX_REGS onwards for the offset to thier locals. +//this function remaps all the locals back into the function. +void QCC_UnmarshalLocals(void) +{ + QCC_def_t *def; + unsigned int ofs; + unsigned int maxo; + int i; + + ofs = numpr_globals; + maxo = ofs; + + for (def = pr.def_head.next ; def ; def = def->next) + { + if (def->ofs >= MAX_REGS) //unmap defs. + { + def->ofs = def->ofs + ofs - MAX_REGS; + if (maxo < def->ofs) + maxo = def->ofs; + } + } + + for (i = 0; i < numfunctions; i++) + { + if (functions[i].parm_start == MAX_REGS) + functions[i].parm_start = ofs; + } + + QCC_RemapOffsets(0, numstatements, MAX_REGS, MAX_REGS + maxo-numpr_globals + 3, ofs); + + numpr_globals = maxo+3; + if (numpr_globals > MAX_REGS) + QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals are in use to unmarshal all locals"); + + if (maxo-ofs) + printf("Total of %i marshalled globals\n", maxo-ofs); +} + + +CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def); +void QCC_WriteData (int crc) +{ + char element[MAX_NAME]; + QCC_def_t *def, *comp_x, *comp_y, *comp_z; + QCC_ddef_t *dd; + dprograms_t progs; + int h; + int i, len; + pbool debugdefined = false; + pbool types = false; + int outputsize = 16; + + progs.blockscompressed=0; + + if (numstatements > MAX_STATEMENTS) + QCC_Error(ERR_TOOMANYSTATEMENTS, "Too many statements - %i\nAdd \"MAX_STATEMENTS\" \"%i\" to qcc.cfg", numstatements, (numstatements+32768)&~32767); + + if (strofs > MAX_STRINGS) + QCC_Error(ERR_TOOMANYSTRINGS, "Too many strings - %i\nAdd \"MAX_STRINGS\" \"%i\" to qcc.cfg", strofs, (strofs+32768)&~32767); + + QCC_UnmarshalLocals(); + + if (QCC_PR_CheckCompConstDefined("DEBUG")) //debug forces it if standard + { + if (!qcc_targetformat) + { + printf("Forcing target due to debugging\n"); + qcc_targetformat = QCF_FTEDEBUG; + } + else if (qcc_targetformat != QCF_FTE && qcc_targetformat != QCF_FTEDEBUG) + printf("Target does not support debugging info\n"); + } + + switch (qcc_targetformat) + { + case QCF_HEXEN2: + case QCF_STANDARD: + if (bodylessfuncs) + printf("Warning: There are some functions without bodies.\n"); + + if (outputversion > PROG_VERSION) + { + printf("Forcing target to FTE due to additional opcodes\n"); + qcc_targetformat = QCF_FTE; + outputversion = PROG_DEBUGVERSION; //force it. + } + else if (numpr_globals > 65530 ) + { + printf("Forcing target to FTE32 due to numpr_globals\n"); + qcc_targetformat = QCF_FTE32; + outputsize = 32; + outputversion = PROG_DEBUGVERSION; //force it. + } + else if (qcc_targetformat == QCF_HEXEN2) + { + outputversion = PROG_VERSION; + printf("Progs execution requires a Hexen2 compatable engine\n"); + break; + } + else + { + if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on origional executors? + printf("An enhanced executor will be required (FTE/QF/KK)\n"); + else + printf("Progs should run on any Quake executor\n"); + break; + } + //intentional + case QCF_FTEDEBUG: + case QCF_FTEDEBUG32: + case QCF_FTE: + case QCF_FTE32: + if (qcc_targetformat == QCF_FTEDEBUG || qcc_targetformat == QCF_FTEDEBUG32) + debugdefined = true; + if (qcc_targetformat == QCF_FTE32 || qcc_targetformat == QCF_FTEDEBUG32) + outputsize = 32; + else if (numpr_globals > 65530) + { + printf("Forcing 32 bit target due to numpr_globals\n"); + } + + //compression of blocks? + if (QCC_PR_CheckCompConstDefined("OP_COMP_STATEMENTS")) progs.blockscompressed |=1; + if (QCC_PR_CheckCompConstDefined("OP_COMP_DEFS")) progs.blockscompressed |=2; + if (QCC_PR_CheckCompConstDefined("OP_COMP_FIELDS")) progs.blockscompressed |=4; + if (QCC_PR_CheckCompConstDefined("OP_COMP_FUNCTIONS")) progs.blockscompressed |=8; + if (QCC_PR_CheckCompConstDefined("OP_COMP_STRINGS")) progs.blockscompressed |=16; + if (QCC_PR_CheckCompConstDefined("OP_COMP_GLOBALS")) progs.blockscompressed |=32; + if (QCC_PR_CheckCompConstDefined("OP_COMP_LINES")) progs.blockscompressed |=64; + if (QCC_PR_CheckCompConstDefined("OP_COMP_TYPES")) progs.blockscompressed |=128; + //include a type block? + types = !!QCC_PR_CheckCompConstDefined("TYPES"); //useful for debugging and saving (maybe, anyway...). + + outputversion = PROG_DEBUGVERSION; + + printf("An FTE executor will be required\n"); + break; + case QCF_KK7: + outputversion = PROG_DEBUGVERSION; + if (bodylessfuncs) + printf("Warning: There are some functions without bodies.\n"); + + printf("A KK compatable executor will be required (FTE/KK)\n"); + break; + } + + //part of how compilation works. This def is always present, and never used. + def = QCC_PR_GetDef(NULL, "end_sys_globals", NULL, false, 0); + if (def) + def->references++; + + def = QCC_PR_GetDef(NULL, "end_sys_fields", NULL, false, 0); + if (def) + def->references++; + + for (def = pr.def_head.next ; def ; def = def->next) + { + if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector)) + { //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x + sprintf(element, "%s_x", def->name); + comp_x = QCC_PR_GetDef(NULL, element, def->scope, false, 0); + sprintf(element, "%s_y", def->name); + comp_y = QCC_PR_GetDef(NULL, element, def->scope, false, 0); + sprintf(element, "%s_z", def->name); + comp_z = QCC_PR_GetDef(NULL, element, def->scope, false, 0); + + h = def->references; + if (comp_x && comp_y && comp_z) + { + h += comp_x->references; + h += comp_y->references; + h += comp_z->references; + + if (!def->references) + if (!comp_x->references || !comp_y->references || !comp_z->references) //one of these vars is useless... + h=0; + + def->references = h; + + + if (!h) + h = 1; + if (comp_x) + comp_x->references = h; + if (comp_y) + comp_y->references = h; + if (comp_z) + comp_z->references = h; + } + } + if (def->references<=0) + { + if (def->constant) + QCC_PR_Warning(WARN_NOTREFERENCEDCONST, strings + def->s_file, def->s_line, "%s no references", def->name); + else + QCC_PR_Warning(WARN_NOTREFERENCED, strings + def->s_file, def->s_line, "%s no references", def->name); + + if (opt_unreferenced && def->type->type != ev_field) + { + optres_unreferenced++; + continue; + } + } + + if (def->type->type == ev_function) + { + if (opt_function_names && functions[G_FUNCTION(def->ofs)].first_statement<0) + { + optres_function_names++; + def->name = ""; + } + if (!def->timescalled) + { + if (def->references<=1) + QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called or referenced (spawn function or dead code)", def->name); + else + QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called", def->name); + } + if (opt_stripfunctions && def->timescalled >= def->references-1) //make sure it's not copied into a different var. + { //if it ever does self.think then it could be needed for saves. + optres_stripfunctions++; //if it's only ever called explicitly, the engine doesn't need to know. + continue; + } + +// df = &functions[numfunctions]; +// numfunctions++; + + } + else if (def->type->type == ev_field)// && !def->constant) + { + dd = &fields[numfielddefs]; + numfielddefs++; + dd->type = def->type->aux_type->type; + dd->s_name = QCC_CopyString (def->name); + dd->ofs = G_INT(def->ofs); + } + else if ((def->scope||def->constant) && (def->type->type != ev_string || opt_constant_names_strings)) + { + if (opt_constant_names) + { + if (def->type->type == ev_string) + optres_constant_names_strings += strlen(def->name); + else + optres_constant_names += strlen(def->name); + continue; + } + } + +// if (!def->saved && def->type->type != ev_string) +// continue; + dd = &qcc_globals[numglobaldefs]; + numglobaldefs++; + + if (types) + dd->type = def->type-qcc_typeinfo; + else + dd->type = def->type->type; +#ifdef DEF_SAVEGLOBAL + if ( def->saved && ((!def->initialized || def->type->type == ev_function) +// && def->type->type != ev_function + && def->type->type != ev_field + && def->scope == NULL)) + dd->type |= DEF_SAVEGLOBAL; +#endif + if (def->shared) + dd->type |= DEF_SHARED; + + if (opt_locals && (def->scope || !strcmp(def->name, "IMMEDIATE"))) + { + dd->s_name = 0; + optres_locals += strlen(def->name); + } + else + dd->s_name = QCC_CopyString (def->name); + dd->ofs = def->ofs; + } + + if (numglobaldefs > MAX_GLOBALS) + QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals - %i\nAdd \"MAX_GLOBALS\" \"%i\" to qcc.cfg", numglobaldefs, (numglobaldefs+32768)&~32767); + + + for (i = 0; i < nummodels; i++) + { + if (!precache_models_used[i]) + QCC_PR_Warning(WARN_EXTRAPRECACHE, NULL, 0, "Model %s was precached but not directly used", precache_models[i]); + else if (!precache_models_block[i]) + QCC_PR_Warning(WARN_NOTPRECACHED, NULL, 0, "Model %s was used but not precached", precache_models[i]); + } +//PrintStrings (); +//PrintFunctions (); +//PrintFields (); +//PrintGlobals (); +strofs = (strofs+3)&~3; + + printf ("%6i strofs (of %i)\n", strofs, MAX_STRINGS); + printf ("%6i numstatements (of %i)\n", numstatements, MAX_STATEMENTS); + printf ("%6i numfunctions (of %i)\n", numfunctions, MAX_FUNCTIONS); + printf ("%6i numglobaldefs (of %i)\n", numglobaldefs, MAX_GLOBALS); + printf ("%6i numfielddefs (%i unique) (of %i)\n", numfielddefs, pr.size_fields, MAX_FIELDS); + printf ("%6i numpr_globals (of %i)\n", numpr_globals, MAX_REGS); + + if (!*destfile) + strcpy(destfile, "progs.dat"); + printf("Writing %s\n", destfile); + h = SafeOpenWrite (destfile, 2*1024*1024); + SafeWrite (h, &progs, sizeof(progs)); + SafeWrite (h, "\r\n", 2); + SafeWrite (h, QCC_copyright, strlen(QCC_copyright)+1); + SafeWrite (h, "\r\n\r\n", 4); + + progs.ofs_strings = SafeSeek (h, 0, SEEK_CUR); + progs.numstrings = strofs; + + if (progs.blockscompressed&16) + { + SafeWrite (h, &len, sizeof(int)); //save for later + len = QC_encode(progfuncs, strofs*sizeof(char), 2, (char *)strings, h); //write + i = SafeSeek (h, 0, SEEK_CUR); + SafeSeek(h, progs.ofs_strings, SEEK_SET);//seek back + len = LittleLong(len); + SafeWrite (h, &len, sizeof(int)); //write size. + SafeSeek(h, i, SEEK_SET); + } + else + SafeWrite (h, strings, strofs); + + progs.ofs_statements = SafeSeek (h, 0, SEEK_CUR); + progs.numstatements = numstatements; + + if (qcc_targetformat == QCF_HEXEN2) + { + for (i=0 ; i= OP_CALL1 && statements[i].op <= OP_CALL8) + QCC_Error(ERR_BADTARGETSWITCH, "Target switching produced incompatable instructions"); + else if (statements[i].op >= OP_CALL1H && statements[i].op <= OP_CALL8H) + statements[i].op = statements[i].op - OP_CALL1H + OP_CALL1; + } + } + + for (i=0 ; iMAX_PARMS)?MAX_PARMS:functions[i].numparms); + functions[i].locals = LittleLong (functions[i].locals); + } + + if (progs.blockscompressed&8) + { + SafeWrite (h, &len, sizeof(int)); //save for later + len = QC_encode(progfuncs, numfunctions*sizeof(QCC_dfunction_t), 2, (char *)functions, h); //write + i = SafeSeek (h, 0, SEEK_CUR); + SafeSeek(h, progs.ofs_functions, SEEK_SET);//seek back + len = LittleLong(len); + SafeWrite (h, &len, sizeof(int)); //write size. + SafeSeek(h, i, SEEK_SET); + } + else + SafeWrite (h, functions, numfunctions*sizeof(QCC_dfunction_t)); + + switch(outputsize) + { + case 32: + progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR); + progs.numglobaldefs = numglobaldefs; + for (i=0 ; i= PROG_DEBUGVERSION) + { + if (outputsize == 32) + progs.secondaryversion = PROG_SECONDARYVERSION32; + else + progs.secondaryversion = PROG_SECONDARYVERSION16; + + progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR); + progs.numbodylessfuncs = WriteBodylessFuncs(h); + + if (debugdefined) + { + progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR); + if (progs.blockscompressed&64) + { + SafeWrite (h, &len, sizeof(int)); //save for later + len = QC_encode(progfuncs, numstatements*sizeof(int), 2, (char *)statement_linenums, h); //write + i = SafeSeek (h, 0, SEEK_CUR); + SafeSeek(h, progs.ofslinenums, SEEK_SET);//seek back + len = LittleLong(len); + SafeWrite (h, &len, sizeof(int)); //write size. + SafeSeek(h, i, SEEK_SET); + } + else + SafeWrite (h, statement_linenums, numstatements*sizeof(int)); + } + else + progs.ofslinenums = 0; + + if (types) + { + progs.ofs_types = SafeSeek (h, 0, SEEK_CUR); + if (progs.blockscompressed&128) + { + SafeWrite (h, &len, sizeof(int)); //save for later + len = QC_encode(progfuncs, sizeof(QCC_type_t)*numtypeinfos, 2, (char *)qcc_typeinfo, h); //write + i = SafeSeek (h, 0, SEEK_CUR); + SafeSeek(h, progs.ofs_types, SEEK_SET);//seek back# + len = LittleLong(len); + SafeWrite (h, &len, sizeof(int)); //write size. + SafeSeek(h, i, SEEK_SET); + } + else + SafeWrite (h, qcc_typeinfo, sizeof(QCC_type_t)*numtypeinfos); + progs.numtypes = numtypeinfos; + } + else + { + progs.ofs_types = 0; + progs.numtypes = 0; + } + + progs.ofsfiles = WriteSourceFiles(h, &progs, debugdefined); + } + + progs.version = outputversion; + + printf ("%6i TOTAL SIZE\n", (int)SafeSeek (h, 0, SEEK_CUR)); + + progs.entityfields = pr.size_fields; + + progs.crc = crc; + +// qbyte swap the header and write it out + + for (i=0 ; i 60) + { + *s++ = '.'; + *s++ = '.'; + *s++ = '.'; + break; + } + } + *s++ = '"'; + *s++ = 0; + return buf; +} + + + +QCC_def_t *QCC_PR_DefForFieldOfs (gofs_t ofs) +{ + QCC_def_t *d; + + for (d=pr.def_head.next ; d ; d=d->next) + { + if (d->type->type != ev_field) + continue; + if (*((unsigned int *)&qcc_pr_globals[d->ofs]) == ofs) + return d; + } + QCC_Error (ERR_NOTDEFINED, "PR_DefForFieldOfs: couldn't find %i",ofs); + return NULL; +} + +/* +============ +PR_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *QCC_PR_ValueString (etype_t type, void *val) +{ + static char line[256]; + QCC_def_t *def; + QCC_dfunction_t *f; + + switch (type) + { + case ev_string: + sprintf (line, "%s", QCC_PR_String(strings + *(int *)val)); + break; + case ev_entity: + sprintf (line, "entity %i", *(int *)val); + break; + case ev_function: + f = functions + *(int *)val; + if (!f) + sprintf (line, "undefined function"); + else + sprintf (line, "%s()", strings + f->s_name); + break; + case ev_field: + def = QCC_PR_DefForFieldOfs ( *(int *)val ); + sprintf (line, ".%s", def->name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%5.1f", *(float *)val); + break; + case ev_integer: + sprintf (line, "%i", *(int *)val); + break; + case ev_vector: + sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +/*char *QCC_PR_GlobalStringNoContents (gofs_t ofs) +{ + int i; + QCC_def_t *def; + void *val; + static char line[128]; + + val = (void *)&qcc_pr_globals[ofs]; + def = pr_global_defs[ofs]; + if (!def) +// Error ("PR_GlobalString: no def for %i", ofs); + sprintf (line,"%i(?""?""?)", ofs); + else + sprintf (line,"%i(%s)", ofs, def->name); + + i = strlen(line); + for ( ; i<16 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +char *QCC_PR_GlobalString (gofs_t ofs) +{ + char *s; + int i; + QCC_def_t *def; + void *val; + static char line[128]; + + val = (void *)&qcc_pr_globals[ofs]; + def = pr_global_defs[ofs]; + if (!def) + return QCC_PR_GlobalStringNoContents(ofs); + if (def->initialized && def->type->type != ev_function) + { + s = QCC_PR_ValueString (def->type->type, &qcc_pr_globals[ofs]); + sprintf (line,"%i(%s)", ofs, s); + } + else + sprintf (line,"%i(%s)", ofs, def->name); + + i = strlen(line); + for ( ; i<16 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +}*/ + +/* +============ +PR_PrintOfs +============ +*/ +/*void QCC_PR_PrintOfs (gofs_t ofs) +{ + printf ("%s\n",QCC_PR_GlobalString(ofs)); +}*/ + +/* +================= +PR_PrintStatement +================= +*/ +/*void QCC_PR_PrintStatement (QCC_dstatement_t *s) +{ + int i; + + printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname); + i = strlen(pr_opcodes[s->op].opname); + for ( ; i<10 ; i++) + printf (" "); + + if (s->op == OP_IF || s->op == OP_IFNOT) + printf ("%sbranch %i",QCC_PR_GlobalString(s->a),s->b); + else if (s->op == OP_GOTO) + { + printf ("branch %i",s->a); + } + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + printf ("%s",QCC_PR_GlobalString(s->a)); + printf ("%s", QCC_PR_GlobalStringNoContents(s->b)); + } + else + { + if (s->a) + printf ("%s",QCC_PR_GlobalString(s->a)); + if (s->b) + printf ("%s",QCC_PR_GlobalString(s->b)); + if (s->c) + printf ("%s", QCC_PR_GlobalStringNoContents(s->c)); + } + printf ("\n"); +}*/ + + +/* +============ +PR_PrintDefs +============ +*/ +/*void QCC_PR_PrintDefs (void) +{ + QCC_def_t *d; + + for (d=pr.def_head.next ; d ; d=d->next) + QCC_PR_PrintOfs (d->ofs); +}*/ + +QCC_type_t *QCC_PR_NewType (char *name, int basictype) +{ + if (numtypeinfos>= maxtypeinfos) + QCC_Error(ERR_TOOMANYTYPES, "Too many types"); + memset(&qcc_typeinfo[numtypeinfos], 0, sizeof(QCC_type_t)); + qcc_typeinfo[numtypeinfos].type = basictype; + qcc_typeinfo[numtypeinfos].name = name; + qcc_typeinfo[numtypeinfos].num_parms = 0; + qcc_typeinfo[numtypeinfos].param = NULL; + qcc_typeinfo[numtypeinfos].size = type_size[basictype]; + + + numtypeinfos++; + + return &qcc_typeinfo[numtypeinfos-1]; +} + +/* +============== +PR_BeginCompilation + +called before compiling a batch of files, clears the pr struct +============== +*/ +void QCC_PR_BeginCompilation (void *memory, int memsize) +{ + extern int recursivefunctiontype; + extern struct freeoffset_s *freeofs; + int i; + char name[16]; + + pr.memory = memory; + pr.max_memory = memsize; + + pr.def_tail = &pr.def_head; + +/* numpr_globals = RESERVED_OFS; + + for (i=0 ; iaux_type = type_float; + type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float); + + type_function->aux_type = type_void; + + //type_field->aux_type = type_float; + + if (keyword_int) + QCC_PR_NewType("int", ev_integer); + if (keyword_integer) + QCC_PR_NewType("integer", ev_integer); + + + + if (output_parms) + { //this tends to confuse the brains out of decompilers. :) + numpr_globals = 1; + QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 1)->references++; + for (i = 0; i < MAX_PARMS; i++) + { + sprintf(name, "PARM%i", i); + QCC_PR_GetDef(type_vector, name, NULL, true, 1)->references++; + } + } + else + { + numpr_globals = RESERVED_OFS; +// for (i=0 ; inext = NULL; + pr_error_count = 0; + recursivefunctiontype = 0; + + freeofs = NULL; +} + +/* +============== +PR_FinishCompilation + +called after all files are compiled to check for errors +Returns false if errors were detected. +============== +*/ +int QCC_PR_FinishCompilation (void) +{ + QCC_def_t *d; + int errors; + + errors = false; + +// check to make sure all functions prototyped have code + for (d=pr.def_head.next ; d ; d=d->next) + { + if (d->type->type == ev_function && !d->scope)// function parms are ok + { +// f = G_FUNCTION(d->ofs); +// if (!f || (!f->code && !f->builtin) ) + if (d->initialized==0) + { + if (!strncmp(d->name, "ArrayGet*", 9)) + { + G_FUNCTION(d->ofs) = QCC_PR_EmitArrayGetFunction(d->name+9); + } + else if (!strncmp(d->name, "ArraySet*", 9)) + { + G_FUNCTION(d->ofs) = QCC_PR_EmitArraySetFunction(d->name+9); + } + else if (!strncmp(d->name, "Class*", 6)) + { + G_FUNCTION(d->ofs) = QCC_PR_EmitClassFromFunction(d, d->name+6); + } + else + { + QCC_PR_Warning(WARN_NOTDEFINED, strings + d->s_file, d->s_line, "function %s was not defined",d->name); + bodylessfuncs = true; + } +// errors = true; + } + else if (d->initialized==2) + bodylessfuncs = true; + } + } + + return !errors; +} + +//============================================================================= + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short QCC_crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void QCC_CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void QCC_CRC_ProcessByte(unsigned short *crcvalue, qbyte data) +{ + *crcvalue = (*crcvalue << 8) ^ QCC_crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short QCC_CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + + +/* +============ +PR_WriteProgdefs + +Writes the global and entity structures out +Returns a crc of the header, to be stored in the progs file for comparison +at load time. +============ +*/ +/* +char *Sva(char *msg, ...) +{ + va_list l; + static char buf[1024]; + + va_start(l, msg); + QC_vsnprintf (buf,sizeof(buf)-1, msg, l); + va_end(l); + + return buf; +} +*/ + +//write (to file buf) and add to the crc +void inline Add(char *p, unsigned short *crc, char *file) +{ + char *s; + int i = strlen(file); + for(s=p;*s;s++,i++) + { + QCC_CRC_ProcessByte(crc, *s); + file[i] = *s; + } + file[i]='\0'; +} +#define ADD(p) Add(p, &crc, file) +//#define ADD(p) {char *s;int i = strlen(p);for(s=p;*s;s++,i++){QCC_CRC_ProcessByte(&crc, *s);file[i] = *s;}file[i]='\0';} + +void inline Add3(char *p, unsigned short *crc, char *file) +{ + char *s; + for(s=p;*s;s++) + QCC_CRC_ProcessByte(crc, *s); +} +#define ADD3(p) Add3(p, &crc, file) + +unsigned short QCC_PR_WriteProgdefs (char *filename) +{ + extern int ForcedCRC; +#define ADD2(p) strcat(file, p) //no crc (later changes) + char file[16384]; + QCC_def_t *d; + int f; + unsigned short crc; +// int c; + + file[0] = '\0'; + + QCC_CRC_Init (&crc); + +// print global vars until the first field is defined + ADD("\n/* "); + if (qcc_targetformat == QCF_HEXEN2) + ADD3("generated by hcc, do not modify"); + else + ADD3("file generated by qcc, do not modify"); + ADD2("File generated by FTEQCC, relevent for engine modding only, the generated crc must be the same as your engine expects."); + ADD(" */\n\ntypedef struct"); + ADD2(" globalvars_s"); + ADD(qcva("\n{")); + ADD2("\tint pad;\n" + "\tint ofs_return[3];\n" //makes it easier with the get globals func + "\tint ofs_parm0[3];\n" + "\tint ofs_parm1[3];\n" + "\tint ofs_parm2[3];\n" + "\tint ofs_parm3[3];\n" + "\tint ofs_parm4[3];\n" + "\tint ofs_parm5[3];\n" + "\tint ofs_parm6[3];\n" + "\tint ofs_parm7[3];\n"); + ADD3(qcva("\tint\tpad[%i];\n", RESERVED_OFS)); + for (d=pr.def_head.next ; d ; d=d->next) + { + if (!strcmp (d->name, "end_sys_globals")) + break; + if (d->ofstype->type) + { + case ev_float: + ADD(qcva("\tfloat\t%s;\n",d->name)); + break; + case ev_vector: + ADD(qcva("\tvec3_t\t%s;\n",d->name)); + d=d->next->next->next; // skip the elements + break; + case ev_string: + ADD(qcva("\tstring_t\t%s;\n",d->name)); + break; + case ev_function: + ADD(qcva("\tfunc_t\t%s;\n",d->name)); + break; + case ev_entity: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + case ev_integer: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + default: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + } + } + ADD("} globalvars_t;\n\n"); + +// print all fields + ADD("typedef struct"); + ADD2(" entvars_s"); + ADD("\n{\n"); + for (d=pr.def_head.next ; d ; d=d->next) + { + if (!strcmp (d->name, "end_sys_fields")) + break; + + if (d->type->type != ev_field) + continue; + + switch (d->type->aux_type->type) + { + case ev_float: + ADD(qcva("\tfloat\t%s;\n",d->name)); + break; + case ev_vector: + ADD(qcva("\tvec3_t\t%s;\n",d->name)); + d=d->next->next->next; // skip the elements + break; + case ev_string: + ADD(qcva("\tstring_t\t%s;\n",d->name)); + break; + case ev_function: + ADD(qcva("\tfunc_t\t%s;\n",d->name)); + break; + case ev_entity: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + case ev_integer: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + default: + ADD(qcva("\tint\t%s;\n",d->name)); + break; + } + } + ADD("} entvars_t;\n\n"); + + ///temp + ADD2("//with this the crc isn't needed for fields.\n#ifdef FIELDSSTRUCT\nstruct fieldvars_s {\n\tint ofs;\n\tint type;\n\tchar *name;\n} fieldvars[] = {\n"); + f=0; + for (d=pr.def_head.next ; d ; d=d->next) + { + if (!strcmp (d->name, "end_sys_fields")) + break; + + if (d->type->type != ev_field) + continue; + if (f) + ADD2(",\n"); + ADD2(qcva("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name)); + f = 1; + } + ADD2("\n};\n#endif\n\n"); + //end temp + + ADD2(qcva("#define PROGHEADER_CRC %i\n", crc)); + + if (QCC_CheckParm("-progdefs")) + { + printf ("writing %s\n", filename); + f = SafeOpenWrite("progdefs.h", 16384); + SafeWrite(f, file, strlen(file)); + SafeClose(f); + } + + + if (ForcedCRC) + return ForcedCRC; + + return crc; +} + + +/*void QCC_PrintFunction (char *name) +{ + int i; + QCC_dstatement_t *ds; + QCC_dfunction_t *df; + + for (i=0 ; ifirst_statement; + while (1) + { + QCC_PR_PrintStatement (ds); + if (!ds->op) + break; + ds++; + } +}*/ +/* +void QCC_PrintOfs(unsigned int ofs) +{ + int i; + bool printfunc; + QCC_dstatement_t *ds; + QCC_dfunction_t *df; + + for (i=0 ; ifirst_statement; + printfunc = false; + while (1) + { + if (!ds->op) + break; + if (ds->a == ofs || ds->b == ofs || ds->c == ofs) + { + QCC_PR_PrintStatement (ds); + printfunc = true; + } + ds++; + } + if (printfunc) + { + QCC_PrintFunction(strings + functions[i].s_name); + printf(" \n \n"); + } + } + +} +*/ +/* +============================================================================== + +DIRECTORY COPYING / PACKFILE CREATION + +============================================================================== +*/ + +typedef struct +{ + char name[56]; + int filepos, filelen; +} packfile_t; + +typedef struct +{ + char id[4]; + int dirofs; + int dirlen; +} packheader_t; + +packfile_t pfiles[4096], *pf; +int packhandle; +int packbytes; + + +/* +============ +CreatePath +============ +*/ +void QCC_CreatePath (char *path) +{ + /* + char *ofs; + + for (ofs = path+1 ; *ofs ; ofs++) + { + if (*ofs == '/') + { // create the directory + *ofs = 0; +#ifdef QCC + mkdir(path); +#else + QCC_mkdir (path); +#endif + *ofs = '/'; + } + } + */ +} + + +/* +=========== +PackFile + +Copy a file into the pak file +=========== +*/ +void QCC_PackFile (char *src, char *name) +{ + int remaining; +#if 1 + char *f; +#else + int in; + int count; + char buf[4096]; +#endif + + + if ( (qbyte *)pf - (qbyte *)pfiles > sizeof(pfiles) ) + QCC_Error (ERR_TOOMANYPAKFILES, "Too many files in pak file"); + +#if 1 + f = FS_ReadToMem(src, NULL, &remaining); + if (!f) + { + printf ("%64s : %7s\n", name, ""); +// QCC_Error("Failed to open file %s", src); + return; + } + + pf->filepos = LittleLong (SafeSeek (packhandle, 0, SEEK_CUR)); + pf->filelen = LittleLong (remaining); + strcpy (pf->name, name); + printf ("%64s : %7i\n", pf->name, remaining); + + packbytes += remaining; + + SafeWrite (packhandle, f, remaining); + + FS_CloseFromMem(f); +#else + in = SafeOpenRead (src); + remaining = filelength (in); + + pf->filepos = LittleLong (lseek (packhandle, 0, SEEK_CUR)); + pf->filelen = LittleLong (remaining); + strcpy (pf->name, name); + printf ("%64s : %7i\n", pf->name, remaining); + + packbytes += remaining; + + while (remaining) + { + if (remaining < sizeof(buf)) + count = remaining; + else + count = sizeof(buf); + SafeRead (in, buf, count); + SafeWrite (packhandle, buf, count); + remaining -= count; + } + + close (in); +#endif + pf++; +} + + +/* +=========== +CopyFile + +Copies a file, creating any directories needed +=========== +*/ +void QCC_CopyFile (char *src, char *dest) +{ + /* + int in, out; + int remaining, count; + char buf[4096]; + + print ("%s to %s\n", src, dest); + + in = SafeOpenRead (src); + remaining = filelength (in); + + QCC_CreatePath (dest); + out = SafeOpenWrite (dest, remaining+10); + + while (remaining) + { + if (remaining < sizeof(buf)) + count = remaining; + else + count = sizeof(buf); + SafeRead (in, buf, count); + SafeWrite (out, buf, count); + remaining -= count; + } + + close (in); + SafeClose (out); + */ +} + + +/* +=========== +CopyFiles +=========== +*/ + +void _QCC_CopyFiles (int blocknum, int copytype, char *srcdir, char *destdir) +{ + int i; + int dirlen; + unsigned short crc; + packheader_t header; + char name[1024]; + char srcfile[1024], destfile[1024]; + + packbytes = 0; + + if (copytype == 2) + { + pf = pfiles; + packhandle = SafeOpenWrite (destdir, 1024*1024); + SafeWrite (packhandle, &header, sizeof(header)); + } + + for (i=0 ; i 0) + printf ("%3i unique precache_sounds\n", numsounds); + if (nummodels > 0) + printf ("%3i unique precache_models\n", nummodels); + if (numtextures > 0) + printf ("%3i unique precache_textures\n", numtextures); + if (numfiles > 0) + printf ("%3i unique precache_files\n", numfiles); + + p = QCC_CheckParm ("-copy"); + if (p && p < myargc-2) + { // create a new directory tree + + strcpy (srcdir, myargv[p+1]); + strcpy (destdir, myargv[p+2]); + if (srcdir[strlen(srcdir)-1] != '/') + strcat (srcdir, "/"); + if (destdir[strlen(destdir)-1] != '/') + strcat (destdir, "/"); + + _QCC_CopyFiles(0, 1, srcdir, destdir); + return; + } + + for ( p = 0; p < 5; p++) + { + s = QCC_Packname[p]; + if (!*s) + continue; + strcpy(destdir, s); + strcpy(srcdir, ""); + _QCC_CopyFiles(p+1, 2, srcdir, destdir); + } + return; + /* + + blocknum = 1; + p = QCC_CheckParm ("-pak2"); + if (p && p = sizeof(cnst->value)) + QCC_Error(ERR_PRECOMPILERCONSTANTTOOLONG, "Compiler constant value is too long\n"); + strncpy(cnst->value, val, sizeof(cnst->value)-1); + cnst->value[sizeof(cnst->value)-1] = '\0'; + } + } + + //optimisations. + else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) ) + { + if (myargv[i][2] >= '0' && myargv[i][2] <= '3') + { + p=0; + } + else if (!strnicmp(myargv[i]+2, "no-", 3)) + { + if (myargv[i][5]) + for (p = 0; optimisations[p].enabled; p++) + if ((*optimisations[p].abbrev && !stricmp(myargv[i]+5, optimisations[p].abbrev)) || !stricmp(myargv[i]+5, optimisations[p].fullname)) + { + *optimisations[p].enabled = false; + break; + } + } + else + { + if (myargv[i][2]) + for (p = 0; optimisations[p].enabled; p++) + if ((*optimisations[p].abbrev && !stricmp(myargv[i]+2, optimisations[p].abbrev)) || !stricmp(myargv[i]+2, optimisations[p].fullname)) + { + *optimisations[p].enabled = true; + break; + } + } + if (!optimisations[p].enabled) + QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised optimisation parameter (%s)", myargv[i]); + } + + else if ( !strnicmp(myargv[i], "-K", 2) || !strnicmp(myargv[i], "/K", 2) ) + { + if (!strnicmp(myargv[i]+2, "no-", 3)) + { + for (p = 0; compiler_flag[p].enabled; p++) + if (!stricmp(myargv[i]+5, compiler_flag[p].name)) + { + *compiler_flag[p].enabled = false; + break; + } + } + else + { + for (p = 0; compiler_flag[p].enabled; p++) + if (!stricmp(myargv[i]+2, compiler_flag[p].name)) + { + *compiler_flag[p].enabled = true; + break; + } + } + + if (!compiler_flag[p].enabled) + QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised keyword parameter (%s)", myargv[i]); + } + else if ( !strnicmp(myargv[i], "-F", 2) || !strnicmp(myargv[i], "/F", 2) ) + { + if (!strnicmp(myargv[i]+2, "no-", 3)) + { + for (p = 0; compiler_flag[p].enabled; p++) + if (!stricmp(myargv[i]+5, compiler_flag[p].name)) + { + *compiler_flag[p].enabled = false; + break; + } + } + else + { + for (p = 0; compiler_flag[p].enabled; p++) + if (!stricmp(myargv[i]+2, compiler_flag[p].name)) + { + *compiler_flag[p].enabled = true; + break; + } + } + + if (!compiler_flag[p].enabled) + QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised flag parameter (%s)", myargv[i]); + } + + + else if ( !strncmp(myargv[i], "-T", 2) || !strncmp(myargv[i], "/T", 2) ) + { + for (p = 0; targets[p].name; p++) + if (!stricmp(myargv[i]+2, targets[p].name)) + { + qcc_targetformat = targets[p].target; + break; + } + + if (!targets[p].name) + QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised target parameter (%s)", myargv[i]); + } + + else if ( !strnicmp(myargv[i], "-W", 2) || !strnicmp(myargv[i], "/W", 2) ) + { + if (!stricmp(myargv[i]+2, "all")) + memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled)); + else if (!stricmp(myargv[i]+2, "none")) + memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled)); + else + { + if (!strnicmp(myargv[i]+2, "no-", 3)) + { + for (p = 0; warningnames[p].name; p++) + if (!strcmp(myargv[i]+5, warningnames[p].name)) + { + qccwarningdisabled[warningnames[p].index] = true; + break; + } + } + else + { + for (p = 0; warningnames[p].name; p++) + if (!stricmp(myargv[i]+2, warningnames[p].name)) + { + qccwarningdisabled[warningnames[p].index] = false; + break; + } + } + + if (!warningnames[p].name) + QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised warning parameter (%s)", myargv[i]); + } + } + } +} + +/* +============ +main +============ +*/ + +char *qccmsrc; +char *qccmsrc2; +char qccmfilename[1024]; +char qccmprogsdat[1024]; +char qccmsourcedir[1024]; + +void QCC_FinishCompile(void); + + +void SetEndian(void); + + + +void QCC_SetDefaultProperties (void) +{ + int level; + int i; + QCC_PR_DefineName("FTEQCC"); + + if (QCC_CheckParm("/Oz")) + { + qcc_targetformat = QCF_FTE; + QCC_PR_DefineName("OP_COMP_STATEMENTS"); + QCC_PR_DefineName("OP_COMP_DEFS"); + QCC_PR_DefineName("OP_COMP_FIELDS"); + QCC_PR_DefineName("OP_COMP_FUNCTIONS"); + QCC_PR_DefineName("OP_COMP_STRINGS"); + QCC_PR_DefineName("OP_COMP_GLOBALS"); + QCC_PR_DefineName("OP_COMP_LINES"); + QCC_PR_DefineName("OP_COMP_TYPES"); + } + + if (QCC_CheckParm("/O0") || QCC_CheckParm("-O0")) + level = 0; + else if (QCC_CheckParm("/O1") || QCC_CheckParm("-O1")) + level = 1; + else if (QCC_CheckParm("/O2") || QCC_CheckParm("-O2")) + level = 2; + else if (QCC_CheckParm("/O3") || QCC_CheckParm("-O3")) + level = 3; + else + level = -1; + + if (level == -1) + { + for (i = 0; optimisations[i].enabled; i++) + { + if (optimisations[i].flags & 2) + *optimisations[i].enabled = true; + else + *optimisations[i].enabled = false; + } + } + else + { + for (i = 0; optimisations[i].enabled; i++) + { + if (level >= optimisations[i].optimisationlevel) + *optimisations[i].enabled = true; + else + *optimisations[i].enabled = false; + } + } + + if (QCC_CheckParm ("-h2")) + qcc_targetformat = QCF_HEXEN2; + else if (QCC_CheckParm ("-fte")) + qcc_targetformat = QCF_FTE; + else + qcc_targetformat = QCF_STANDARD; + + + //enable all warnings + memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled)); + + //play with default warnings. + qccwarningdisabled[WARN_NOTREFERENCEDCONST] = true; + qccwarningdisabled[WARN_MACROINSTRING] = true; + qccwarningdisabled[WARN_ASSIGNMENTTOCONSTANT] = true; + qccwarningdisabled[WARN_FIXEDRETURNVALUECONFLICT] = true; + qccwarningdisabled[WARN_EXTRAPRECACHE] = true; + qccwarningdisabled[WARN_DEADCODE] = true; + + if (QCC_CheckParm("-nowarn") || QCC_CheckParm("-Wnone")) + memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled)); + if (QCC_CheckParm("-Wall")) + memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled)); + + if (QCC_CheckParm("-h2")) + qccwarningdisabled[WARN_CASEINSENSATIVEFRAMEMACRO] = true; + + //Check the command line + QCC_PR_CommandLinePrecompilerOptions(); + + + if (qcc_targetformat == QCF_HEXEN2) + keyword_thinktime = true; + + if (QCC_CheckParm("/Debug")) //disable any debug optimisations + { + for (i = 0; optimisations[i].enabled; i++) + { + if (optimisations[i].flags & 1) + *optimisations[i].enabled = false; + } + } +} + +int qcc_compileactive = false; +char *origionalqccmsrc; //for autoprototype. +void QCC_main (int argc, char **argv) //as part of the quake engine +{ + extern int ForcedCRC; + + int p; + + extern char qcc_gamedir[]; +#ifndef QCCONLY + char destfile2[1024], *s2; +#endif + char *s; + + myargc = argc; + myargv = argv; + + qcc_compileactive = true; + + MAX_REGS = 65536; + MAX_STRINGS = 1000000; + MAX_GLOBALS = 16384; + MAX_FIELDS = 2048; + MAX_STATEMENTS = 0x20000; + MAX_FUNCTIONS = 16384; + maxtypeinfos = 16384; + MAX_CONSTANTS = 2048; + + p = externs->FileSize("qcc.cfg"); + if (p < 0) + p = externs->FileSize("src/qcc.cfg"); + if (p>0) + { + s = qccHunkAlloc(p+1); + s = externs->ReadFile("qcc.cfg", s, p); + + while(1) + { + s = QCC_COM_Parse(s); + if (!strcmp(qcc_token, "MAX_REGS")) + { + s = QCC_COM_Parse(s); + MAX_REGS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_STRINGS")) { + s = QCC_COM_Parse(s); + MAX_STRINGS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_GLOBALS")) { + s = QCC_COM_Parse(s); + MAX_GLOBALS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_FIELDS")) { + s = QCC_COM_Parse(s); + MAX_FIELDS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_STATEMENTS")) { + s = QCC_COM_Parse(s); + MAX_STATEMENTS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_FUNCTIONS")) { + s = QCC_COM_Parse(s); + MAX_FUNCTIONS = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_TYPES")) { + s = QCC_COM_Parse(s); + maxtypeinfos = atoi(qcc_token); + } else if (!strcmp(qcc_token, "MAX_TEMPS")) { + s = QCC_COM_Parse(s); + max_temps = atoi(qcc_token); + } else if (!strcmp(qcc_token, "CONSTANTS")) { + s = QCC_COM_Parse(s); + MAX_CONSTANTS = atoi(qcc_token); + } + else if (!s) + break; + else + printf("Bad token in qcc.cfg file\n"); + } + } + /* don't try to be clever + else if (p < 0) + { + s = qccHunkAlloc(8192); + sprintf(s, "MAX_REGS\t%i\r\nMAX_STRINGS\t%i\r\nMAX_GLOBALS\t%i\r\nMAX_FIELDS\t%i\r\nMAX_STATEMENTS\t%i\r\nMAX_FUNCTIONS\t%i\r\nMAX_TYPES\t%i\r\n", + MAX_REGS, MAX_STRINGS, MAX_GLOBALS, MAX_FIELDS, MAX_STATEMENTS, MAX_FUNCTIONS, maxtypeinfos); + externs->WriteFile("qcc.cfg", s, strlen(s)); + } + */ + + SetEndian(); + + strcpy(QCC_copyright, "This file was created with ForeThought's modified QuakeC compiler\nThanks to ID Software"); + for (p = 0; p < 5; p++) + strcpy(QCC_Packname[p], ""); + + outputversion = PROG_VERSION; + + for (p = 0; compiler_flag[p].enabled; p++) + { + *compiler_flag[p].enabled = compiler_flag[p].defaultval; + } + + Hash_InitTable(&compconstantstable, MAX_CONSTANTS, qccHunkAlloc(Hash_BytesForBuckets(MAX_CONSTANTS))); + QCC_SetDefaultProperties(); + + optres_shortenifnots = 0; + optres_overlaptemps = 0; + optres_noduplicatestrings = 0; + optres_constantarithmatic = 0; + optres_nonvec_parms = 0; + optres_constant_names = 0; + optres_constant_names_strings = 0; + optres_precache_file = 0; + optres_filenames = 0; + optres_assignments = 0; + optres_unreferenced = 0; + optres_function_names = 0; + optres_locals = 0; + optres_dupconstdefs = 0; + optres_return_only = 0; + optres_compound_jumps = 0; +// optres_comexprremoval = 0; + optres_stripfunctions = 0; + optres_locals_marshalling = 0; + optres_logicops = 0; + + optres_test1 = 0; + optres_test2 = 0; + + + numtemps = 0; + + functemps=NULL; + + strings = (void *)qccHunkAlloc(sizeof(char) * MAX_STRINGS); + strofs = 1; + + statements = (void *)qccHunkAlloc(sizeof(QCC_dstatement_t) * MAX_STATEMENTS); + numstatements = 0; + statement_linenums = (void *)qccHunkAlloc(sizeof(int) * MAX_STATEMENTS); + + functions = (void *)qccHunkAlloc(sizeof(QCC_dfunction_t) * MAX_FUNCTIONS); + numfunctions=0; + + qcc_pr_globals = (void *)qccHunkAlloc(sizeof(float) * MAX_REGS); + numpr_globals=0; + + Hash_InitTable(&globalstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS))); + Hash_InitTable(&localstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS))); + Hash_InitTable(&floatconstdefstable, MAX_REGS+1, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS+1))); + Hash_InitTable(&stringconstdefstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS))); + +// pr_global_defs = (QCC_def_t **)qccHunkAlloc(sizeof(QCC_def_t *) * MAX_REGS); + + qcc_globals = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_GLOBALS); + numglobaldefs=0; + + fields = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_FIELDS); + numfielddefs=0; + +memset(pr_immediate_string, 0, sizeof(pr_immediate_string)); + + precache_sounds = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_SOUNDS); + precache_sounds_block = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS); + precache_sounds_used = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS); + numsounds=0; + + precache_textures = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_TEXTURES); + precache_textures_block = (void *)qccHunkAlloc(sizeof(int)*MAX_TEXTURES); + numtextures=0; + + precache_models = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_MODELS); + precache_models_block = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS); + precache_models_used = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS); + nummodels=0; + + precache_files = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_FILES); + precache_files_block = (void *)qccHunkAlloc(sizeof(int)*MAX_FILES); + numfiles = 0; + + qcc_typeinfo = (void *)qccHunkAlloc(sizeof(QCC_type_t)*maxtypeinfos); + numtypeinfos = 0; + + qcc_tempofs = qccHunkAlloc(sizeof(int) * max_temps); + tempsstart = 0; + + bodylessfuncs=0; + + memset(&pr, 0, sizeof(pr)); +#ifdef MAX_EXTRA_PARMS + memset(&extra_parms, 0, sizeof(extra_parms)); +#endif + + ForcedCRC = 0; + + if ( QCC_CheckParm ("/?") || QCC_CheckParm ("?") || QCC_CheckParm ("-?") || QCC_CheckParm ("-help") || QCC_CheckParm ("--help")) + { + printf ("qcc looks for progs.src in the current directory.\n"); + printf ("to look in a different directory: qcc -src \n"); +// printf ("to build a clean data tree: qcc -copy \n"); +// printf ("to build a clean pak file: qcc -pak \n"); +// printf ("to bsp all bmodels: qcc -bspmodels \n"); + printf ("-Fwasm causes FTEQCC to dump all asm to qc.asm\n"); + printf ("-O0 to disable optimisations\n"); + printf ("-O1 to optimise for size\n"); + printf ("-O2 to optimise more - some behaviours may change\n"); + printf ("-O3 to optimise lots - experimental or non-future-proof\n"); + printf ("-Oname to enable an optimisation\n"); + printf ("-Ono-name to disable optimisations\n"); + printf ("-Kkeyword to activate keyword\n"); + printf ("-Kno-keyword to disable keyword\n"); + printf ("-Wall to give a stupid number of warnings\n"); + printf ("-Ttarget to set a output format\n"); + printf ("-Fautoproto to enable automatic prototyping\n"); + + qcc_compileactive = false; + return; + } + + if (opt_locals_marshalling) + printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nLocals marshalling might be buggy. Use with caution\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + + p = QCC_CheckParm ("-src"); + if (p && p < argc-1 ) + { + strcpy (qccmsourcedir, argv[p+1]); + strcat (qccmsourcedir, "/"); + printf ("Source directory: %s\n", qccmsourcedir); + } + else +#ifndef QCCONLY + if (!*qcc_gamedir) + sprintf (qccmsourcedir, "src/"); + else + sprintf (qccmsourcedir, "%s/src/", qcc_gamedir); +#else + sprintf (qccmsourcedir, ""); +#endif + + QCC_InitData (); +#if 0 + p = QCC_CheckParm ("-base"); + if (p && p < argc-1 ) + sprintf (qccmprogsdat, "%s%s", qccmsourcedir, argv[p+1]); + else + { //look for a preprogs.src... :o) + sprintf (qccmprogsdat, "%spreprogs.src", qccmsourcedir); + if (externs->FileSize(qccmprogsdat) <= 0) + sprintf (qccmprogsdat, "%sprogs.src", qccmsourcedir); + } +#endif + QCC_PR_BeginCompilation ((void *)qccHunkAlloc (0x100000), 0x100000); +#if 0 + QCC_ReadPoff(qccmprogsdat); +#endif + p = QCC_CheckParm ("-srcfile"); + if (p && p < argc-1 ) + sprintf (qccmprogsdat, "%s%s", qccmsourcedir, argv[p+1]); + else + { //look for a preprogs.src... :o) + sprintf (qccmprogsdat, "%spreprogs.src", qccmsourcedir); + if (externs->FileSize(qccmprogsdat) <= 0) + sprintf (qccmprogsdat, "%sprogs.src", qccmsourcedir); + } + + printf ("Source file: %s\n", qccmprogsdat); + + if (QCC_LoadFile (qccmprogsdat, (void *)&qccmsrc) == -1) + { + return; + } + + newstylesource = false; + + while(*qccmsrc && *qccmsrc < ' ') + qccmsrc++; + + pr_file_p = QCC_COM_Parse(qccmsrc); + +#ifdef WRITEASM + if (writeasm) + { + asmfile = fopen("qc.asm", "wb"); + if (!asmfile) + QCC_Error (ERR_INTERNAL, "Couldn't open file for asm output."); + } +#endif + + if (*qcc_token == '#') + { + void StartNewStyleCompile(void); + newstylesource = true; + StartNewStyleCompile(); + return; + } + + pr_file_p = qccmsrc; + QCC_PR_LexWhitespace(); + qccmsrc = pr_file_p; + + s = qccmsrc; + pr_file_p = qccmsrc; + QCC_PR_SimpleGetToken (); + strcpy(qcc_token, pr_token); + qccmsrc = pr_file_p; + + if (!qccmsrc) + QCC_Error (ERR_NOOUTPUT, "No destination filename. qcc -help for info."); + strcpy (destfile, qcc_token); + +#ifndef QCCONLY + p=1; + s2 = strcpy(destfile2, destfile); + if (!strncmp(s2, "./", 2)) + s2+=2; + else + { + while(!strncmp(s2, "../", 3)) + { + s2+=3; + p++; + } + } + strcpy(qccmfilename, qccmsourcedir); + for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--) + { + if (*s == '/' || *s == '\\') + { + *(s+1) = '\0'; + p--; + } + } + if (s>=qccmfilename) + sprintf(destfile, "%s%s", qccmfilename, s2); + else + sprintf(destfile, "%s", s2); +#endif + + printf ("outputfile: %s\n", destfile); + + pr_dumpasm = false; + + currentchunk = NULL; + + origionalqccmsrc = qccmsrc; +} + +void new_QCC_ContinueCompile(void); +//called between exe frames - won't loose net connection (is the theory)... +void QCC_ContinueCompile(void) +{ + char *s, *s2; + currentchunk = NULL; + if (!qcc_compileactive) + //HEY! + return; + + if (newstylesource) + { + new_QCC_ContinueCompile(); + return; + } + + qccmsrc = QCC_COM_Parse(qccmsrc); + if (!qccmsrc) + { + if (autoprototype) + { + qccmsrc = origionalqccmsrc; + autoprototype = false; + return; + } + QCC_FinishCompile(); + return; + } + s = qcc_token; + + strcpy (qccmfilename, qccmsourcedir); + while(1) + { + if (!strncmp(s, "..\\", 3)) + { + s2 = qccmfilename + strlen(qccmfilename)-2; + while (s2>=qccmfilename) + { + if (*s2 == '/' || *s2 == '\\') + { + s2[1] = '\0'; + break; + } + s2--; + } + s+=3; + continue; + } + if (!strncmp(s, ".\\", 2)) + { + s+=2; + continue; + } + + break; + } + strcat (qccmfilename, s); + if (autoprototype) + printf ("prototyping %s\n", qccmfilename); + else + printf ("compiling %s\n", qccmfilename); + QCC_LoadFile (qccmfilename, (void *)&qccmsrc2); + + if (!QCC_PR_CompileFile (qccmsrc2, qccmfilename) ) + QCC_Error (ERR_PARSEERRORS, "Errors have occured\n"); +} +void QCC_FinishCompile(void) +{ + int crc; +// int p; + currentchunk = NULL; + + if (setjmp(pr_parse_abort)) + QCC_Error(ERR_INTERNAL, ""); + + if (!QCC_PR_FinishCompilation ()) + { + QCC_Error (ERR_PARSEERRORS, "compilation errors"); + } + +/* p = QCC_CheckParm ("-asm"); + if (p) + { + for (p++ ; p MAX_ERRORS) + return; + QCC_PR_SkipToSemicolon (); + if (pr_token_type == tt_eof) + return; + } + + + QCC_PR_ClearGrabMacros (); // clear the frame macros + + compilingfile = qccmprogsdat; + + pr_file_p = qccmsrc; + s_file = s_file2 = QCC_CopyString (compilingfile); + + pr_source_line = 0; + + QCC_PR_NewLine (false); + + QCC_PR_Lex (); // read first token +} +void new_QCC_ContinueCompile(void) +{ + if (setjmp(pr_parse_abort)) + { +// if (pr_error_count != 0) + { + QCC_Error (ERR_PARSEERRORS, "Errors have occured"); + return; + } + QCC_PR_SkipToSemicolon (); + if (pr_token_type == tt_eof) + return; + } + + if (pr_token_type == tt_eof) + { + if (pr_error_count) + QCC_Error (ERR_PARSEERRORS, "Errors have occured"); + QCC_FinishCompile(); + return; + } + + pr_scope = NULL; // outside all functions + + QCC_PR_ParseDefs (NULL); +} + +/*void new_QCC_ContinueCompile(void) +{ + char *s, *s2; + if (!qcc_compileactive) + //HEY! + return; + +// compile all the files + + qccmsrc = QCC_COM_Parse(qccmsrc); + if (!qccmsrc) + { + QCC_FinishCompile(); + return; + } + s = qcc_token; + + strcpy (qccmfilename, qccmsourcedir); + while(1) + { + if (!strncmp(s, "..\\", 3)) + { + s2 = qccmfilename + strlen(qccmfilename)-2; + while (s2>=qccmfilename) + { + if (*s2 == '/' || *s2 == '\\') + { + s2[1] = '\0'; + break; + } + s2--; + } + s+=3; + continue; + } + if (!strncmp(s, ".\\", 2)) + { + s+=2; + continue; + } + + break; + } +// strcat (qccmfilename, s); +// printf ("compiling %s\n", qccmfilename); +// QCC_LoadFile (qccmfilename, (void *)&qccmsrc2); + +// if (!new_QCC_PR_CompileFile (qccmsrc2, qccmfilename) ) +// QCC_Error ("Errors have occured\n"); + + + { + + if (!pr.memory) + QCC_Error ("PR_CompileFile: Didn't clear"); + + QCC_PR_ClearGrabMacros (); // clear the frame macros + + compilingfile = filename; + + pr_file_p = qccmsrc2; + s_file = QCC_CopyString (filename); + + pr_source_line = 0; + + QCC_PR_NewLine (); + + QCC_PR_Lex (); // read first token + + while (pr_token_type != tt_eof) + { + if (setjmp(pr_parse_abort)) + { + if (++pr_error_count > MAX_ERRORS) + return false; + QCC_PR_SkipToSemicolon (); + if (pr_token_type == tt_eof) + return false; + } + + pr_scope = NULL; // outside all functions + + QCC_PR_ParseDefs (); + } + } + return (pr_error_count == 0); + +}*/ + + + + + + + + + + + + +#ifdef QCCONLY +progfuncs_t *progfuncs; + +short (*BigShort) (short l); +short (*LittleShort) (short l); +long (*BigLong) (long l); +long (*LittleLong) (long l); +float (*BigFloat) (float l); +float (*LittleFloat) (float l); + +/* +============== +LoadFile +============== +*/ +char *QCC_ReadFile (char *fname, void *buffer, int len) +{ + long length; + FILE *f; + f = fopen(fname, "rb"); + if (!f) + return NULL; + length = fread(buffer, 1, len, f); + fclose(f); + + if (length != len) + return NULL; + + return buffer; +} +int QCC_FileSize (char *fname) +{ + long length; + FILE *f; + f = fopen(fname, "rb"); + if (!f) + return -1; + fseek(f, 0, SEEK_END); + length = ftell(f); + fclose(f); + + return length; +} + +pbool QCC_WriteFile (char *name, void *data, int len) +{ + long length; + FILE *f; + f = fopen(name, "wb"); + if (!f) + return false; + length = fwrite(data, 1, len, f); + fclose(f); + + if (length != len) + return false; + + return true; +} + +#undef printf +#undef Sys_Error + +void Sys_Error(const char *text, ...) +{ + va_list argptr; + static char msg[2048]; + + va_start (argptr,text); + QC_vsnprintf (msg,sizeof(msg)-1, text,argptr); + va_end (argptr); + + QCC_Error(ERR_INTERNAL, "%s", msg); +} + +int main (int argc, char **argv) +{ + progexterns_t ext; + progfuncs_t funcs; + progfuncs = &funcs; + memset(&funcs, 0, sizeof(funcs)); + funcs.parms = &ext; + memset(&ext, 0, sizeof(progexterns_t)); + funcs.parms->ReadFile = QCC_ReadFile; + funcs.parms->FileSize = QCC_FileSize; + funcs.parms->WriteFile = QCC_WriteFile; + funcs.parms->printf = printf; + funcs.parms->Sys_Error = Sys_Error; + CompileParams(&funcs, true, argc, argv); + qccClearHunk(); + +#ifdef _WIN32 + fgetc(stdin); //wait for keypress +#endif + return 0; +} +#endif + +#endif +