mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-26 22:01:50 +00:00
4b0395e079
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@684 fc73d0e0-1445-4013-8a0c-d673dee63da5
3257 lines
77 KiB
C
3257 lines
77 KiB
C
#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;
|
|
|
|
int MAX_STRINGS;
|
|
int MAX_GLOBALS;
|
|
int MAX_FIELDS;
|
|
int MAX_STATEMENTS;
|
|
int MAX_FUNCTIONS;
|
|
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}
|
|
};
|
|
|
|
int QCC_WarningForName(char *name)
|
|
{
|
|
int i;
|
|
for (i = 0; warningnames[i].name; i++)
|
|
{
|
|
if (!stricmp(name, warningnames[i].name))
|
|
return warningnames[i].index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
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 (note - this can screw over some decompilers)
|
|
{&autoprototype, false, "autoproto"}, //so you no longer need to prototype functions and things in advance.
|
|
{&writeasm, false, "wasm"}, //spit out a qc.asm file, containing an assembler dump of the ENTIRE progs. (Doesn't include initialisation of constants)
|
|
{&flag_ifstring, true, "ifstring"}, //correction for if(string) no-ifstring to get the standard behaviour.
|
|
{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;
|
|
|
|
memset(&ret_temp, 0, sizeof(ret_temp));
|
|
|
|
def_ret.ofs = OFS_RETURN;
|
|
def_ret.name = "return";
|
|
def_ret.temp = &ret_temp;
|
|
def_ret.constant = false;
|
|
def_ret.type = NULL;
|
|
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].temp = NULL;
|
|
def_parms[i].type = NULL;
|
|
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();
|
|
|
|
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)
|
|
qcc_typeinfo[i].aux_type = (QCC_type_t*)(qcc_typeinfo[i].aux_type - qcc_typeinfo);
|
|
if (qcc_typeinfo[i].next)
|
|
qcc_typeinfo[i].next = (QCC_type_t*)(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);
|
|
|
|
if (outputversion != 7 || !debugdefined)
|
|
{
|
|
if (opt_filenames)
|
|
{
|
|
printf("Not writing linenumbers file due to conflicting optimisation\n");
|
|
}
|
|
else
|
|
{
|
|
unsigned int lnotype = *(unsigned int*)"LNOF";
|
|
unsigned int version = 1;
|
|
StripExtension(destfile);
|
|
strcat(destfile, ".lno");
|
|
printf("Writing %s\n", destfile);
|
|
h = SafeOpenWrite (destfile, 2*1024*1024);
|
|
SafeWrite (h, &lnotype, sizeof(int));
|
|
SafeWrite (h, &version, sizeof(int));
|
|
SafeWrite (h, &numglobaldefs, sizeof(int));
|
|
SafeWrite (h, &numpr_globals, sizeof(int));
|
|
SafeWrite (h, &numfielddefs, sizeof(int));
|
|
SafeWrite (h, &numstatements, sizeof(int));
|
|
SafeWrite (h, statement_linenums, numstatements*sizeof(int));
|
|
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 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 ; 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;
|
|
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))
|
|
{
|
|
QCC_PR_EmitArrayGetFunction(d, d->name+9);
|
|
pr_scope = NULL;
|
|
}
|
|
else if (!strncmp(d->name, "ArraySet*", 9))
|
|
{
|
|
QCC_PR_EmitArraySetFunction(d, d->name+9);
|
|
pr_scope = NULL;
|
|
}
|
|
else if (!strncmp(d->name, "Class*", 6))
|
|
{
|
|
QCC_PR_EmitClassFromFunction(d, d->name+6);
|
|
pr_scope = NULL;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
pr_scope = NULL;
|
|
|
|
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) )
|
|
{
|
|
p = 0;
|
|
if (myargv[i][2] >= '0' && myargv[i][2] <= '3')
|
|
{
|
|
}
|
|
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) )
|
|
{
|
|
p = 0;
|
|
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) )
|
|
{
|
|
p = 0;
|
|
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) )
|
|
{
|
|
p = 0;
|
|
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
|
|
{
|
|
p = 0;
|
|
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;
|
|
qccwarningdisabled[WARN_INEFFICIENTPLUSPLUS] = true;
|
|
qccwarningdisabled[WARN_FTE_SPECIFIC] = true;
|
|
qccwarningdisabled[WARN_EXTENSION_USED] = true;
|
|
qccwarningdisabled[WARN_IFSTRING_USED] = 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 pr_bracelevel;
|
|
extern int ForcedCRC;
|
|
|
|
int p;
|
|
|
|
#ifndef QCCONLY
|
|
extern char qcc_gamedir[];
|
|
char destfile2[1024], *s2;
|
|
#endif
|
|
char *s;
|
|
|
|
myargc = argc;
|
|
myargv = argv;
|
|
|
|
qcc_compileactive = true;
|
|
|
|
MAX_REGS = 65536;
|
|
MAX_STRINGS = 1000000;
|
|
MAX_GLOBALS = 32768;
|
|
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;
|
|
|
|
pr_bracelevel = 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
|
|
*qccmsourcedir = '\0';
|
|
#endif
|
|
|
|
QCC_InitData ();
|
|
|
|
QCC_PR_BeginCompilation ((void *)qccHunkAlloc (0x100000), 0x100000);
|
|
|
|
p = QCC_CheckParm ("-qc");
|
|
if (!p || p >= argc-1 || argv[p+1][0] == '-')
|
|
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_CheckParm ("-qc"))
|
|
{
|
|
strcpy(destfile, qccmprogsdat);
|
|
StripExtension(destfile);
|
|
strcat(destfile, ".qco");
|
|
|
|
p = QCC_CheckParm ("-o");
|
|
if (!p || p >= argc-1 || argv[p+1][0] == '-')
|
|
if (p && p < argc-1 )
|
|
sprintf (destfile, "%s%s", qccmsourcedir, argv[p+1]);
|
|
goto newstyle;
|
|
}
|
|
|
|
if (*qcc_token == '#')
|
|
{
|
|
void StartNewStyleCompile(void);
|
|
newstyle:
|
|
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
|
|
==============
|
|
*/
|
|
unsigned 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)
|
|
{
|
|
int sucess;
|
|
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;
|
|
sucess = CompileParams(&funcs, true, argc, argv);
|
|
qccClearHunk();
|
|
|
|
#ifdef _WIN32
|
|
// fgetc(stdin); //wait for keypress
|
|
#endif
|
|
return !sucess;
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|