fteqw/engine/qclib/QccMain.c

3198 lines
76 KiB
C
Raw Normal View History

#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 ; i<nummodels ; i++)
{
m = precache_models[i];
if (strcmp(m+strlen(m)-4, ".bsp"))
continue;
strcpy (name, m);
name[strlen(m)-4] = 0;
sprintf (cmd, "qbsp %s/%s ; light -extra %s/%s", gamedir, name, gamedir, name);
system (cmd);
}
}
// CopyString returns an offset from the string heap
int QCC_CopyString (char *str)
{
int old;
char *s;
if (opt_noduplicatestrings)
{
if (!str || !*str)
return 0;
for (s = strings; s < strings+strofs; s++)
if (!strcmp(s, str))
{
optres_noduplicatestrings += strlen(str);
return s-strings;
}
}
old = strofs;
strcpy (strings+strofs, str);
strofs += strlen(str)+1;
return old;
}
int QCC_CopyDupBackString (char *str)
{
int old;
char *s;
for (s = strings+strofs-1; s>strings ; 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 ; i<strofs ; i += l)
{
l = strlen(strings+i) + 1;
printf ("%5i : ",i);
for (j=0 ; j<l ; j++)
{
if (strings[i+j] == '\n')
{
putchar ('\\');
putchar ('n');
}
else
putchar (strings[i+j]);
}
printf ("\n");
}
}
/*void QCC_PrintFunctions (void)
{
int i,j;
QCC_dfunction_t *d;
for (i=0 ; i<numfunctions ; i++)
{
d = &functions[i];
printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
for (j=0 ; j<d->numparms ; j++)
printf ("%i ",d->parm_size[j]);
printf (")\n");
}
}*/
void QCC_PrintFields (void)
{
int i;
QCC_ddef_t *d;
for (i=0 ; i<numfielddefs ; i++)
{
d = &fields[i];
printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
}
}
void QCC_PrintGlobals (void)
{
int i;
QCC_ddef_t *d;
for (i=0 ; i<numglobaldefs ; i++)
{
d = &qcc_globals[i];
printf ("%5i : (%i) %s\n", d->ofs, 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 ; i<MAX_PARMS ; i++)
{
def_parms[i].ofs = OFS_PARM0 + 3*i;
def_parms[i].name = parmname[i];
sprintf(parmname[i], "parm%i", i);
}
}
int WriteBodylessFuncs (int handle)
{
QCC_def_t *d;
int ret=0;
for (d=pr.def_head.next ; d ; d=d->next)
{
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<numstatements ; i++)
{
if (statements[i].op >= 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 ; i<numstatements ; i++)
switch(qcc_targetformat == QCF_KK7?32:outputsize) //KK7 sucks.
{
case 32:
for (i=0 ; i<numstatements ; i++)
{
statements[i].op = LittleLong/*LittleShort*/(statements[i].op);
statements[i].a = LittleLong/*LittleShort*/(statements[i].a);
statements[i].b = LittleLong/*LittleShort*/(statements[i].b);
statements[i].c = LittleLong/*LittleShort*/(statements[i].c);
}
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement32_t), 2, (char *)statements, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, statements, numstatements*sizeof(QCC_dstatement32_t));
break;
case 16:
#define statements16 ((QCC_dstatement16_t*) statements)
for (i=0 ; i<numstatements ; i++) //resize as we go - scaling down
{
statements16[i].op = LittleShort((unsigned short)statements[i].op);
if (statements[i].a < 0)
statements16[i].a = LittleShort((short)statements[i].a);
else
statements16[i].a = (unsigned short)LittleShort((unsigned short)statements[i].a);
if (statements[i].b < 0)
statements16[i].b = LittleShort((short)statements[i].b);
else
statements16[i].b = (unsigned short)LittleShort((unsigned short)statements[i].b);
if (statements[i].c < 0)
statements16[i].c = LittleShort((short)statements[i].c);
else
statements16[i].c = (unsigned short)LittleShort((unsigned short)statements[i].c);
}
if (progs.blockscompressed&1)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement16_t), 2, (char *)statements16, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, statements16, numstatements*sizeof(QCC_dstatement16_t));
break;
default:
Sys_Error("intsize error");
}
progs.ofs_functions = SafeSeek (h, 0, SEEK_CUR);
progs.numfunctions = numfunctions;
for (i=0 ; i<numfunctions ; i++)
{
functions[i].first_statement = LittleLong (functions[i].first_statement);
functions[i].parm_start = LittleLong (functions[i].parm_start);
functions[i].s_name = LittleLong (functions[i].s_name);
functions[i].s_file = LittleLong (functions[i].s_file);
functions[i].numparms = LittleLong ((functions[i].numparms>MAX_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<numglobaldefs ; i++)
{
qcc_globals[i].type = LittleLong/*LittleShort*/ (qcc_globals[i].type);
qcc_globals[i].ofs = LittleLong/*LittleShort*/ (qcc_globals[i].ofs);
qcc_globals[i].s_name = LittleLong (qcc_globals[i].s_name);
}
if (progs.blockscompressed&2)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef_t), 2, (char *)qcc_globals, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, qcc_globals, numglobaldefs*sizeof(QCC_ddef_t));
progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
progs.numfielddefs = numfielddefs;
for (i=0 ; i<numfielddefs ; i++)
{
fields[i].type = LittleLong/*LittleShort*/ (fields[i].type);
fields[i].ofs = LittleLong/*LittleShort*/ (fields[i].ofs);
fields[i].s_name = LittleLong (fields[i].s_name);
}
if (progs.blockscompressed&4)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef_t), 2, (char *)fields, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, fields, numfielddefs*sizeof(QCC_ddef_t));
break;
case 16:
#define qcc_globals16 ((QCC_ddef16_t*)qcc_globals)
#define fields16 ((QCC_ddef16_t*)fields)
progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR);
progs.numglobaldefs = numglobaldefs;
for (i=0 ; i<numglobaldefs ; i++)
{
qcc_globals16[i].type = (unsigned short)LittleShort ((unsigned short)qcc_globals[i].type);
qcc_globals16[i].ofs = (unsigned short)LittleShort ((unsigned short)qcc_globals[i].ofs);
qcc_globals16[i].s_name = LittleLong (qcc_globals[i].s_name);
}
if (progs.blockscompressed&2)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef16_t), 2, (char *)qcc_globals16, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, qcc_globals16, numglobaldefs*sizeof(QCC_ddef16_t));
progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
progs.numfielddefs = numfielddefs;
for (i=0 ; i<numfielddefs ; i++)
{
fields16[i].type = (unsigned short)LittleShort ((unsigned short)fields[i].type);
fields16[i].ofs = (unsigned short)LittleShort ((unsigned short)fields[i].ofs);
fields16[i].s_name = LittleLong (fields[i].s_name);
}
if (progs.blockscompressed&4)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef16_t), 2, (char *)fields16, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, fields16, numfielddefs*sizeof(QCC_ddef16_t));
break;
default:
Sys_Error("intsize error");
}
progs.ofs_globals = SafeSeek (h, 0, SEEK_CUR);
progs.numglobals = numpr_globals;
for (i=0 ; (unsigned)i<numpr_globals ; i++)
((int *)qcc_pr_globals)[i] = LittleLong (((int *)qcc_pr_globals)[i]);
if (progs.blockscompressed&32)
{
SafeWrite (h, &len, sizeof(int)); //save for later
len = QC_encode(progfuncs, numpr_globals*4, 2, (char *)qcc_pr_globals, h); //write
i = SafeSeek (h, 0, SEEK_CUR);
SafeSeek(h, progs.ofs_globals, SEEK_SET);//seek back
len = LittleLong(len);
SafeWrite (h, &len, sizeof(int)); //write size.
SafeSeek(h, i, SEEK_SET);
}
else
SafeWrite (h, qcc_pr_globals, numpr_globals*4);
if (types)
for (i=0 ; i<numtypeinfos ; i++)
{
if (qcc_typeinfo[i].aux_type)
(unsigned int)qcc_typeinfo[i].aux_type = qcc_typeinfo[i].aux_type - qcc_typeinfo;
if (qcc_typeinfo[i].next)
(unsigned int)qcc_typeinfo[i].next = qcc_typeinfo[i].next - qcc_typeinfo;
qcc_typeinfo[i].name = (char *)QCC_CopyDupBackString(qcc_typeinfo[i].name);
}
progs.ofsfiles = 0;
progs.ofslinenums = 0;
progs.secondaryversion = 0;
progs.ofsbodylessfuncs = 0;
progs.numbodylessfuncs = 0;
progs.ofs_types = 0;
progs.numtypes = 0;
if (qcc_targetformat == QCF_KK7)
{
outputversion = 7;
}
else if (outputversion >= 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<sizeof(progs)/4 ; i++)
((int *)&progs)[i] = LittleLong ( ((int *)&progs)[i] );
SafeSeek (h, 0, SEEK_SET);
SafeWrite (h, &progs, sizeof(progs));
SafeClose (h);
}
/*
===============
PR_String
Returns a string suitable for printing (no newlines, max 60 chars length)
===============
*/
char *QCC_PR_String (char *string)
{
static char buf[80];
char *s;
s = buf;
*s++ = '"';
while (string && *string)
{
if (s == buf + sizeof(buf) - 2)
break;
if (*string == '\n')
{
*s++ = '\\';
*s++ = 'n';
}
else if (*string == '"')
{
*s++ = '\\';
*s++ = '"';
}
else
*s++ = *string;
string++;
if (s - buf > 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 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 ; i<RESERVED_OFS ; i++)
pr_global_defs[i] = &def_void;
*/
type_void = QCC_PR_NewType("void", ev_void);
type_string = QCC_PR_NewType("string", ev_string);
type_float = QCC_PR_NewType("float", ev_float);
type_vector = QCC_PR_NewType("vector", ev_vector);
type_entity = QCC_PR_NewType("entity", ev_entity);
type_field = QCC_PR_NewType("field", ev_field);
type_function = QCC_PR_NewType("function", ev_function);
type_pointer = QCC_PR_NewType("pointer", ev_pointer);
type_integer = QCC_PR_NewType("__integer", ev_integer);
type_floatfield = QCC_PR_NewType("fieldfloat", ev_field);
type_floatfield->aux_type = type_float;
type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float);
type_function->aux_type = type_void;
//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 ; i<RESERVED_OFS ; i++)
// pr_global_defs[i] = NULL;
}
// link the function type in so state forward declarations match proper type
pr.types = NULL;
// type_function->next = NULL;
pr_error_count = 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\n",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->ofs<RESERVED_OFS)
continue;
switch (d->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("} 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 ; i<numfunctions ; i++)
if (!strcmp (name, strings + functions[i].s_name))
break;
if (i==numfunctions)
QCC_Error (ERR_NOFUNC, "No function named \"%s\"", name);
df = functions + i;
printf ("Statements for function %s:\n", name);
ds = statements + df->first_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 ; i<numfunctions ; i++)
{
df = functions + i;
ds = statements + df->first_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<numsounds ; i++)
{
if (precache_sounds_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",srcdir, precache_sounds[i]);
sprintf (destfile,"%s%s",destdir, precache_sounds[i]);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, precache_sounds[i]);
}
for (i=0 ; i<nummodels ; i++)
{
if (precache_models_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",srcdir, precache_models[i]);
sprintf (destfile,"%s%s",destdir, precache_models[i]);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, precache_models[i]);
}
for (i=0 ; i<numtextures ; i++)
{
if (precache_textures_block[i] != blocknum)
continue;
{
sprintf (name, "%s", precache_textures[i]);
sprintf (srcfile,"%s%s",srcdir, name);
sprintf (destfile,"%s%s",destdir, name);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, name);
}
{
sprintf (name, "%s.bmp", precache_textures[i]);
sprintf (srcfile,"%s%s",srcdir, name);
sprintf (destfile,"%s%s",destdir, name);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, name);
}
{
sprintf (name, "%s.tga", precache_textures[i]);
sprintf (srcfile,"%s%s",srcdir, name);
sprintf (destfile,"%s%s",destdir, name);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, name);
}
}
for (i=0 ; i<numfiles ; i++)
{
if (precache_files_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",srcdir, precache_files[i]);
sprintf (destfile,"%s%s",destdir, precache_files[i]);
if (copytype == 1)
QCC_CopyFile (srcfile, destfile);
else
QCC_PackFile (srcfile, precache_files[i]);
}
if (copytype == 2)
{
header.id[0] = 'P';
header.id[1] = 'A';
header.id[2] = 'C';
header.id[3] = 'K';
dirlen = (qbyte *)pf - (qbyte *)pfiles;
header.dirofs = LittleLong(SafeSeek (packhandle, 0, SEEK_CUR));
header.dirlen = LittleLong(dirlen);
SafeWrite (packhandle, pfiles, dirlen);
SafeSeek (packhandle, 0, SEEK_SET);
SafeWrite (packhandle, &header, sizeof(header));
SafeClose (packhandle);
// do a crc of the file
QCC_CRC_Init (&crc);
for (i=0 ; i<dirlen ; i++)
QCC_CRC_ProcessByte (&crc, ((qbyte *)pfiles)[i]);
i = pf - pfiles;
printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
}
}
void QCC_CopyFiles (void)
{
char *s;
char srcdir[1024], destdir[1024];
int p;
if (numsounds > 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 <myargc-2)
blocknum = 2;
else
p = QCC_CheckParm ("-pak");
if (p && p < myargc-2)
{ // create a pak file
strcpy (srcdir, myargv[p+1]);
strcpy (destdir, myargv[p+2]);
if (srcdir[strlen(srcdir)-1] != '/')
strcat (srcdir, "/");
DefaultExtension (destdir, ".pak");
copytype = 2;
_QCC_CopyFiles(blocknum, copytype, srcdir, destdir);
}
*/
}
//============================================================================
void QCC_PR_CommandLinePrecompilerOptions (void)
{
CompilerConstant_t *cnst;
int i, p;
char *name, *val;
for (i = 1;i<myargc;i++)
{
//compiler constant
if ( !strncmp(myargv[i], "-D", 2) )
{
name = myargv[i] + 2;
val = strchr(name, '=');
if (val)
{
*val = '\0';
val++;
}
cnst = QCC_PR_DefineName(name);
if (val)
{
if (strlen(val)+1 >= 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 <directory>\n");
// printf ("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
// printf ("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
// printf ("to bsp all bmodels: qcc -bspmodels <gamedir>\n");
printf ("-Fwasm <funcname> 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<myargc ; p++)
{
if (myargv[p][0] == '-')
break;
QCC_PrintFunction (myargv[p]);
}
}*/
/*p = QCC_CheckParm ("-ofs");
if (p)
{
for (p++ ; p<myargc ; p++)
{
if (myargv[p][0] == '-')
break;
QCC_PrintOfs (atoi(myargv[p]));
}
}*/
// write progdefs.h
crc = QCC_PR_WriteProgdefs ("progdefs.h");
// write data file
QCC_WriteData (crc);
// regenerate bmodels if -bspmodels
QCC_BspModels ();
// report / copy the data files
QCC_CopyFiles ();
printf ("Compile Complete\n\n");
if (optres_shortenifnots)
printf("optres_shortenifnots %i\n", optres_shortenifnots);
if (optres_overlaptemps)
printf("optres_overlaptemps %i\n", optres_overlaptemps);
if (optres_noduplicatestrings)
printf("optres_noduplicatestrings %i\n", optres_noduplicatestrings);
if (optres_constantarithmatic)
printf("optres_constantarithmatic %i\n", optres_constantarithmatic);
if (optres_nonvec_parms)
printf("optres_nonvec_parms %i\n", optres_nonvec_parms);
if (optres_constant_names)
printf("optres_constant_names %i\n", optres_constant_names);
if (optres_constant_names_strings)
printf("optres_constant_names_strings %i\n", optres_constant_names_strings);
if (optres_precache_file)
printf("optres_precache_file %i\n", optres_precache_file);
if (optres_filenames)
printf("optres_filenames %i\n", optres_filenames);
if (optres_assignments)
printf("optres_assignments %i\n", optres_assignments);
if (optres_unreferenced)
printf("optres_unreferenced %i\n", optres_unreferenced);
if (optres_locals)
printf("optres_locals %i\n", optres_locals);
if (optres_function_names)
printf("optres_function_names %i\n", optres_function_names);
if (optres_dupconstdefs)
printf("optres_dupconstdefs %i\n", optres_dupconstdefs);
if (optres_return_only)
printf("optres_return_only %i\n", optres_return_only);
if (optres_compound_jumps)
printf("optres_compound_jumps %i\n", optres_compound_jumps);
// if (optres_comexprremoval)
// printf("optres_comexprremoval %i\n", optres_comexprremoval);
if (optres_stripfunctions)
printf("optres_stripfunctions %i\n", optres_stripfunctions);
if (optres_locals_marshalling)
printf("optres_locals_marshalling %i\n", optres_locals_marshalling);
if (optres_logicops)
printf("optres_logicops %i\n", optres_logicops);
if (optres_test1)
printf("optres_test1 %i\n", optres_test1);
if (optres_test2)
printf("optres_test2 %i\n", optres_test2);
printf("numtemps %i\n", numtemps);
qcc_compileactive = false;
}
extern char *compilingfile;
extern QCC_string_t s_file, s_file2;
extern char *pr_file_p;
extern int pr_source_line;
extern QCC_def_t *pr_scope;
void QCC_PR_ParseDefs (char *classname);
void StartNewStyleCompile(void)
{
if (setjmp(pr_parse_abort))
{
if (++pr_error_count > 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