#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 ; istrings ; s--) if (!strcmp(s, str)) return s-strings; old = strofs; strcpy (strings+strofs, str); strofs += strlen(str)+1; return old; } void QCC_PrintStrings (void) { int i, l, j; for (i=0 ; is_file, strings + d->s_name, d->first_statement, d->parm_start); for (j=0 ; jnumparms ; j++) printf ("%i ",d->parm_size[j]); printf (")\n"); } }*/ void QCC_PrintFields (void) { int i; QCC_ddef_t *d; for (i=0 ; iofs, d->type, strings + d->s_name); } } void QCC_PrintGlobals (void) { int i; QCC_ddef_t *d; for (i=0 ; iofs, d->type, strings + d->s_name); } } int encode(int len, int method, char *in, int handle); int WriteSourceFiles(int h, dprograms_t *progs, pbool sourceaswell) { includeddatafile_t *idf; qcc_cachedsourcefile_t *f; int num=0; int ofs; /* for (f = qcc_sourcefile; f ; f=f->next) { if (f->type == FT_CODE && !sourceaswell) continue; SafeWrite(h, f->filename, strlen(f->filename)+1); i = LittleLong(f->size); SafeWrite(h, &i, sizeof(int)); i = LittleLong(encrpytmode); SafeWrite(h, &i, sizeof(int)); if (encrpytmode) for (i = 0; i < f->size; i++) f->file[i] ^= 0xA5; SafeWrite(h, f->file, f->size); }*/ for (f = qcc_sourcefile,num=0; f ; f=f->next) { if (f->type == FT_CODE && !sourceaswell) continue; num++; } if (!num) return 0; idf = qccHunkAlloc(sizeof(includeddatafile_t)*num); for (f = qcc_sourcefile,num=0; f ; f=f->next) { if (f->type == FT_CODE && !sourceaswell) continue; strcpy(idf[num].filename, f->filename); idf[num].size = f->size; #ifdef AVAIL_ZLIB idf[num].compmethod = 2; #else idf[num].compmethod = 1; #endif idf[num].ofs = SafeSeek(h, 0, SEEK_CUR); idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h); num++; } ofs = SafeSeek(h, 0, SEEK_CUR); SafeWrite(h, &num, sizeof(int)); SafeWrite(h, idf, sizeof(includeddatafile_t)*num); qcc_sourcefile = NULL; return ofs; } void QCC_InitData (void) { static char parmname[12][MAX_PARMS]; static temp_t ret_temp; int i; qcc_sourcefile = NULL; numstatements = 1; strofs = 1; numfunctions = 1; numglobaldefs = 1; numfielddefs = 1; 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 ; inext) { if (d->type->type == ev_function && !d->scope)// function parms are ok { if (d->initialized != 1) { SafeWrite(handle, d->name, strlen(d->name)+1); ret++; } } } return ret; } //marshalled locals remaps all the functions to use the range MAX_REGS onwards for the offset to thier locals. //this function remaps all the locals back into the function. void QCC_UnmarshalLocals(void) { QCC_def_t *def; unsigned int ofs; unsigned int maxo; int i; ofs = numpr_globals; maxo = ofs; for (def = pr.def_head.next ; def ; def = def->next) { if (def->ofs >= MAX_REGS) //unmap defs. { def->ofs = def->ofs + ofs - MAX_REGS; if (maxo < def->ofs) maxo = def->ofs; } } for (i = 0; i < numfunctions; i++) { if (functions[i].parm_start == MAX_REGS) functions[i].parm_start = ofs; } QCC_RemapOffsets(0, numstatements, MAX_REGS, MAX_REGS + maxo-numpr_globals + 3, ofs); numpr_globals = maxo+3; if (numpr_globals > MAX_REGS) QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals are in use to unmarshal all locals"); if (maxo-ofs) printf("Total of %i marshalled globals\n", maxo-ofs); } CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def); void QCC_WriteData (int crc) { char element[MAX_NAME]; QCC_def_t *def, *comp_x, *comp_y, *comp_z; QCC_ddef_t *dd; dprograms_t progs; int h; int i, len; pbool debugdefined = false; pbool types = false; int outputsize = 16; progs.blockscompressed=0; if (numstatements > MAX_STATEMENTS) QCC_Error(ERR_TOOMANYSTATEMENTS, "Too many statements - %i\nAdd \"MAX_STATEMENTS\" \"%i\" to qcc.cfg", numstatements, (numstatements+32768)&~32767); if (strofs > MAX_STRINGS) QCC_Error(ERR_TOOMANYSTRINGS, "Too many strings - %i\nAdd \"MAX_STRINGS\" \"%i\" to qcc.cfg", strofs, (strofs+32768)&~32767); QCC_UnmarshalLocals(); switch (qcc_targetformat) { case QCF_HEXEN2: case QCF_STANDARD: if (bodylessfuncs) printf("Warning: There are some functions without bodies.\n"); if (outputversion > PROG_VERSION) { printf("Forcing target to FTE due to additional opcodes\n"); qcc_targetformat = QCF_FTE; outputversion = PROG_DEBUGVERSION; //force it. } else if (numpr_globals > 65530 ) { printf("Forcing target to FTE32 due to numpr_globals\n"); qcc_targetformat = QCF_FTE32; outputsize = 32; outputversion = PROG_DEBUGVERSION; //force it. } else if (qcc_targetformat == QCF_HEXEN2) { outputversion = PROG_VERSION; printf("Progs execution requires a Hexen2 compatable engine\n"); break; } else { if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on origional executors? printf("An enhanced executor will be required (FTE/QF/KK)\n"); else printf("Progs should run on any Quake executor\n"); break; } //intentional case QCF_FTEDEBUG: case QCF_FTEDEBUG32: case QCF_FTE: case QCF_FTE32: if (qcc_targetformat == QCF_FTEDEBUG || qcc_targetformat == QCF_FTEDEBUG32) debugdefined = true; if (qcc_targetformat == QCF_FTE32 || qcc_targetformat == QCF_FTEDEBUG32) outputsize = 32; else if (numpr_globals > 65530) { printf("Forcing 32 bit target due to numpr_globals\n"); } //compression of blocks? if (QCC_PR_CheckCompConstDefined("OP_COMP_STATEMENTS")) progs.blockscompressed |=1; if (QCC_PR_CheckCompConstDefined("OP_COMP_DEFS")) progs.blockscompressed |=2; if (QCC_PR_CheckCompConstDefined("OP_COMP_FIELDS")) progs.blockscompressed |=4; if (QCC_PR_CheckCompConstDefined("OP_COMP_FUNCTIONS")) progs.blockscompressed |=8; if (QCC_PR_CheckCompConstDefined("OP_COMP_STRINGS")) progs.blockscompressed |=16; if (QCC_PR_CheckCompConstDefined("OP_COMP_GLOBALS")) progs.blockscompressed |=32; if (QCC_PR_CheckCompConstDefined("OP_COMP_LINES")) progs.blockscompressed |=64; if (QCC_PR_CheckCompConstDefined("OP_COMP_TYPES")) progs.blockscompressed |=128; //include a type block? types = !!QCC_PR_CheckCompConstDefined("TYPES"); //useful for debugging and saving (maybe, anyway...). outputversion = PROG_DEBUGVERSION; printf("An FTE executor will be required\n"); break; case QCF_KK7: outputversion = PROG_DEBUGVERSION; if (bodylessfuncs) printf("Warning: There are some functions without bodies.\n"); printf("A KK compatable executor will be required (FTE/KK)\n"); break; } //part of how compilation works. This def is always present, and never used. def = QCC_PR_GetDef(NULL, "end_sys_globals", NULL, false, 0); if (def) def->references++; def = QCC_PR_GetDef(NULL, "end_sys_fields", NULL, false, 0); if (def) def->references++; for (def = pr.def_head.next ; def ; def = def->next) { if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector)) { //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x sprintf(element, "%s_x", def->name); comp_x = QCC_PR_GetDef(NULL, element, def->scope, false, 0); sprintf(element, "%s_y", def->name); comp_y = QCC_PR_GetDef(NULL, element, def->scope, false, 0); sprintf(element, "%s_z", def->name); comp_z = QCC_PR_GetDef(NULL, element, def->scope, false, 0); h = def->references; if (comp_x && comp_y && comp_z) { h += comp_x->references; h += comp_y->references; h += comp_z->references; if (!def->references) if (!comp_x->references || !comp_y->references || !comp_z->references) //one of these vars is useless... h=0; def->references = h; if (!h) h = 1; if (comp_x) comp_x->references = h; if (comp_y) comp_y->references = h; if (comp_z) comp_z->references = h; } } if (def->references<=0) { if (def->constant) QCC_PR_Warning(WARN_NOTREFERENCEDCONST, strings + def->s_file, def->s_line, "%s no references", def->name); else QCC_PR_Warning(WARN_NOTREFERENCED, strings + def->s_file, def->s_line, "%s no references", def->name); if (opt_unreferenced && def->type->type != ev_field) { optres_unreferenced++; continue; } } if (def->type->type == ev_function) { if (opt_function_names && functions[G_FUNCTION(def->ofs)].first_statement<0) { optres_function_names++; def->name = ""; } if (!def->timescalled) { if (def->references<=1) QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called or referenced (spawn function or dead code)", def->name); else QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called", def->name); } if (opt_stripfunctions && def->timescalled >= def->references-1) //make sure it's not copied into a different var. { //if it ever does self.think then it could be needed for saves. optres_stripfunctions++; //if it's only ever called explicitly, the engine doesn't need to know. continue; } // df = &functions[numfunctions]; // numfunctions++; } else if (def->type->type == ev_field)// && !def->constant) { dd = &fields[numfielddefs]; numfielddefs++; dd->type = def->type->aux_type->type; dd->s_name = QCC_CopyString (def->name); dd->ofs = G_INT(def->ofs); } else if ((def->scope||def->constant) && (def->type->type != ev_string || opt_constant_names_strings)) { if (opt_constant_names) { if (def->type->type == ev_string) optres_constant_names_strings += strlen(def->name); else optres_constant_names += strlen(def->name); continue; } } // if (!def->saved && def->type->type != ev_string) // continue; dd = &qcc_globals[numglobaldefs]; numglobaldefs++; if (types) dd->type = def->type-qcc_typeinfo; else dd->type = def->type->type; #ifdef DEF_SAVEGLOBAL if ( def->saved && ((!def->initialized || def->type->type == ev_function) // && def->type->type != ev_function && def->type->type != ev_field && def->scope == NULL)) dd->type |= DEF_SAVEGLOBAL; #endif if (def->shared) dd->type |= DEF_SHARED; if (opt_locals && (def->scope || !strcmp(def->name, "IMMEDIATE"))) { dd->s_name = 0; optres_locals += strlen(def->name); } else dd->s_name = QCC_CopyString (def->name); dd->ofs = def->ofs; } if (numglobaldefs > MAX_GLOBALS) QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals - %i\nAdd \"MAX_GLOBALS\" \"%i\" to qcc.cfg", numglobaldefs, (numglobaldefs+32768)&~32767); for (i = 0; i < nummodels; i++) { if (!precache_models_used[i]) QCC_PR_Warning(WARN_EXTRAPRECACHE, NULL, 0, "Model %s was precached but not directly used", precache_models[i]); else if (!precache_models_block[i]) QCC_PR_Warning(WARN_NOTPRECACHED, NULL, 0, "Model %s was used but not precached", precache_models[i]); } //PrintStrings (); //PrintFunctions (); //PrintFields (); //PrintGlobals (); strofs = (strofs+3)&~3; printf ("%6i strofs (of %i)\n", strofs, MAX_STRINGS); printf ("%6i numstatements (of %i)\n", numstatements, MAX_STATEMENTS); printf ("%6i numfunctions (of %i)\n", numfunctions, MAX_FUNCTIONS); printf ("%6i numglobaldefs (of %i)\n", numglobaldefs, MAX_GLOBALS); printf ("%6i numfielddefs (%i unique) (of %i)\n", numfielddefs, pr.size_fields, MAX_FIELDS); printf ("%6i numpr_globals (of %i)\n", numpr_globals, MAX_REGS); if (!*destfile) strcpy(destfile, "progs.dat"); printf("Writing %s\n", destfile); h = SafeOpenWrite (destfile, 2*1024*1024); SafeWrite (h, &progs, sizeof(progs)); SafeWrite (h, "\r\n", 2); SafeWrite (h, QCC_copyright, strlen(QCC_copyright)+1); SafeWrite (h, "\r\n\r\n", 4); progs.ofs_strings = SafeSeek (h, 0, SEEK_CUR); progs.numstrings = strofs; if (progs.blockscompressed&16) { SafeWrite (h, &len, sizeof(int)); //save for later len = QC_encode(progfuncs, strofs*sizeof(char), 2, (char *)strings, h); //write i = SafeSeek (h, 0, SEEK_CUR); SafeSeek(h, progs.ofs_strings, SEEK_SET);//seek back len = LittleLong(len); SafeWrite (h, &len, sizeof(int)); //write size. SafeSeek(h, i, SEEK_SET); } else SafeWrite (h, strings, strofs); progs.ofs_statements = SafeSeek (h, 0, SEEK_CUR); progs.numstatements = numstatements; if (qcc_targetformat == QCF_HEXEN2) { for (i=0 ; i= OP_CALL1 && statements[i].op <= OP_CALL8) QCC_Error(ERR_BADTARGETSWITCH, "Target switching produced incompatable instructions"); else if (statements[i].op >= OP_CALL1H && statements[i].op <= OP_CALL8H) statements[i].op = statements[i].op - OP_CALL1H + OP_CALL1; } } for (i=0 ; iMAX_PARMS)?MAX_PARMS:functions[i].numparms); functions[i].locals = LittleLong (functions[i].locals); } if (progs.blockscompressed&8) { SafeWrite (h, &len, sizeof(int)); //save for later len = QC_encode(progfuncs, numfunctions*sizeof(QCC_dfunction_t), 2, (char *)functions, h); //write i = SafeSeek (h, 0, SEEK_CUR); SafeSeek(h, progs.ofs_functions, SEEK_SET);//seek back len = LittleLong(len); SafeWrite (h, &len, sizeof(int)); //write size. SafeSeek(h, i, SEEK_SET); } else SafeWrite (h, functions, numfunctions*sizeof(QCC_dfunction_t)); switch(outputsize) { case 32: progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR); progs.numglobaldefs = numglobaldefs; for (i=0 ; i= PROG_DEBUGVERSION) { if (outputsize == 32) progs.secondaryversion = PROG_SECONDARYVERSION32; else progs.secondaryversion = PROG_SECONDARYVERSION16; progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR); progs.numbodylessfuncs = WriteBodylessFuncs(h); if (debugdefined) { progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR); if (progs.blockscompressed&64) { SafeWrite (h, &len, sizeof(int)); //save for later len = QC_encode(progfuncs, numstatements*sizeof(int), 2, (char *)statement_linenums, h); //write i = SafeSeek (h, 0, SEEK_CUR); SafeSeek(h, progs.ofslinenums, SEEK_SET);//seek back len = LittleLong(len); SafeWrite (h, &len, sizeof(int)); //write size. SafeSeek(h, i, SEEK_SET); } else SafeWrite (h, statement_linenums, numstatements*sizeof(int)); } else progs.ofslinenums = 0; if (types) { progs.ofs_types = SafeSeek (h, 0, SEEK_CUR); if (progs.blockscompressed&128) { SafeWrite (h, &len, sizeof(int)); //save for later len = QC_encode(progfuncs, sizeof(QCC_type_t)*numtypeinfos, 2, (char *)qcc_typeinfo, h); //write i = SafeSeek (h, 0, SEEK_CUR); SafeSeek(h, progs.ofs_types, SEEK_SET);//seek back# len = LittleLong(len); SafeWrite (h, &len, sizeof(int)); //write size. SafeSeek(h, i, SEEK_SET); } else SafeWrite (h, qcc_typeinfo, sizeof(QCC_type_t)*numtypeinfos); progs.numtypes = numtypeinfos; } else { progs.ofs_types = 0; progs.numtypes = 0; } progs.ofsfiles = WriteSourceFiles(h, &progs, debugdefined); } progs.version = outputversion; printf ("%6i TOTAL SIZE\n", (int)SafeSeek (h, 0, SEEK_CUR)); progs.entityfields = pr.size_fields; progs.crc = crc; // qbyte swap the header and write it out for (i=0 ; i 60) { *s++ = '.'; *s++ = '.'; *s++ = '.'; break; } } *s++ = '"'; *s++ = 0; return buf; } QCC_def_t *QCC_PR_DefForFieldOfs (gofs_t ofs) { QCC_def_t *d; for (d=pr.def_head.next ; d ; d=d->next) { if (d->type->type != ev_field) continue; if (*((unsigned int *)&qcc_pr_globals[d->ofs]) == ofs) return d; } QCC_Error (ERR_NOTDEFINED, "PR_DefForFieldOfs: couldn't find %i",ofs); return NULL; } /* ============ PR_ValueString Returns a string describing *data in a type specific manner ============= */ char *QCC_PR_ValueString (etype_t type, void *val) { static char line[256]; QCC_def_t *def; QCC_dfunction_t *f; switch (type) { case ev_string: sprintf (line, "%s", QCC_PR_String(strings + *(int *)val)); break; case ev_entity: sprintf (line, "entity %i", *(int *)val); break; case ev_function: f = functions + *(int *)val; if (!f) sprintf (line, "undefined function"); else sprintf (line, "%s()", strings + f->s_name); break; case ev_field: def = QCC_PR_DefForFieldOfs ( *(int *)val ); sprintf (line, ".%s", def->name); break; case ev_void: sprintf (line, "void"); break; case ev_float: sprintf (line, "%5.1f", *(float *)val); break; case ev_integer: sprintf (line, "%i", *(int *)val); break; case ev_vector: sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]); break; case ev_pointer: sprintf (line, "pointer"); break; default: sprintf (line, "bad type %i", type); break; } return line; } /* ============ PR_GlobalString Returns a string with a description and the contents of a global, padded to 20 field width ============ */ /*char *QCC_PR_GlobalStringNoContents (gofs_t ofs) { int i; QCC_def_t *def; void *val; static char line[128]; val = (void *)&qcc_pr_globals[ofs]; def = pr_global_defs[ofs]; if (!def) // Error ("PR_GlobalString: no def for %i", ofs); sprintf (line,"%i(?""?""?)", ofs); else sprintf (line,"%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) strcat (line," "); strcat (line," "); return line; } char *QCC_PR_GlobalString (gofs_t ofs) { char *s; int i; QCC_def_t *def; void *val; static char line[128]; val = (void *)&qcc_pr_globals[ofs]; def = pr_global_defs[ofs]; if (!def) return QCC_PR_GlobalStringNoContents(ofs); if (def->initialized && def->type->type != ev_function) { s = QCC_PR_ValueString (def->type->type, &qcc_pr_globals[ofs]); sprintf (line,"%i(%s)", ofs, s); } else sprintf (line,"%i(%s)", ofs, def->name); i = strlen(line); for ( ; i<16 ; i++) strcat (line," "); strcat (line," "); return line; }*/ /* ============ PR_PrintOfs ============ */ /*void QCC_PR_PrintOfs (gofs_t ofs) { printf ("%s\n",QCC_PR_GlobalString(ofs)); }*/ /* ================= PR_PrintStatement ================= */ /*void QCC_PR_PrintStatement (QCC_dstatement_t *s) { int i; printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname); i = strlen(pr_opcodes[s->op].opname); for ( ; i<10 ; i++) printf (" "); if (s->op == OP_IF || s->op == OP_IFNOT) printf ("%sbranch %i",QCC_PR_GlobalString(s->a),s->b); else if (s->op == OP_GOTO) { printf ("branch %i",s->a); } else if ( (unsigned)(s->op - OP_STORE_F) < 6) { printf ("%s",QCC_PR_GlobalString(s->a)); printf ("%s", QCC_PR_GlobalStringNoContents(s->b)); } else { if (s->a) printf ("%s",QCC_PR_GlobalString(s->a)); if (s->b) printf ("%s",QCC_PR_GlobalString(s->b)); if (s->c) printf ("%s", QCC_PR_GlobalStringNoContents(s->c)); } printf ("\n"); }*/ /* ============ PR_PrintDefs ============ */ /*void QCC_PR_PrintDefs (void) { QCC_def_t *d; for (d=pr.def_head.next ; d ; d=d->next) QCC_PR_PrintOfs (d->ofs); }*/ QCC_type_t *QCC_PR_NewType (char *name, int basictype) { if (numtypeinfos>= maxtypeinfos) QCC_Error(ERR_TOOMANYTYPES, "Too many types"); memset(&qcc_typeinfo[numtypeinfos], 0, sizeof(QCC_type_t)); qcc_typeinfo[numtypeinfos].type = basictype; qcc_typeinfo[numtypeinfos].name = name; qcc_typeinfo[numtypeinfos].num_parms = 0; qcc_typeinfo[numtypeinfos].param = NULL; qcc_typeinfo[numtypeinfos].size = type_size[basictype]; numtypeinfos++; return &qcc_typeinfo[numtypeinfos-1]; } /* ============== PR_BeginCompilation called before compiling a batch of files, clears the pr struct ============== */ void QCC_PR_BeginCompilation (void *memory, int memsize) { extern int recursivefunctiontype; extern struct freeoffset_s *freeofs; int i; char name[16]; pr.memory = memory; pr.max_memory = memsize; pr.def_tail = &pr.def_head; /* numpr_globals = RESERVED_OFS; for (i=0 ; iaux_type = type_float; type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float); type_function->aux_type = type_void; //type_field->aux_type = type_float; if (keyword_int) QCC_PR_NewType("int", ev_integer); if (keyword_integer) QCC_PR_NewType("integer", ev_integer); if (output_parms) { //this tends to confuse the brains out of decompilers. :) numpr_globals = 1; QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 1)->references++; for (i = 0; i < MAX_PARMS; i++) { sprintf(name, "PARM%i", i); QCC_PR_GetDef(type_vector, name, NULL, true, 1)->references++; } } else { numpr_globals = RESERVED_OFS; // for (i=0 ; inext = NULL; pr_error_count = 0; recursivefunctiontype = 0; freeofs = NULL; } /* ============== PR_FinishCompilation called after all files are compiled to check for errors Returns false if errors were detected. ============== */ int QCC_PR_FinishCompilation (void) { QCC_def_t *d; int errors; errors = false; // check to make sure all functions prototyped have code for (d=pr.def_head.next ; d ; d=d->next) { if (d->type->type == ev_function && !d->scope)// function parms are ok { // f = G_FUNCTION(d->ofs); // if (!f || (!f->code && !f->builtin) ) if (d->initialized==0) { if (!strncmp(d->name, "ArrayGet*", 9)) { 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->ofstype->type) { case ev_float: ADD(qcva("\tfloat\t%s;\n",d->name)); break; case ev_vector: ADD(qcva("\tvec3_t\t%s;\n",d->name)); d=d->next->next->next; // skip the elements break; case ev_string: ADD(qcva("\tstring_t\t%s;\n",d->name)); break; case ev_function: ADD(qcva("\tfunc_t\t%s;\n",d->name)); break; case ev_entity: ADD(qcva("\tint\t%s;\n",d->name)); break; case ev_integer: ADD(qcva("\tint\t%s;\n",d->name)); break; default: ADD(qcva("\tint\t%s;\n",d->name)); break; } } ADD("} globalvars_t;\n\n"); // print all fields ADD("typedef struct"); ADD2(" entvars_s"); ADD("\n{\n"); for (d=pr.def_head.next ; d ; d=d->next) { if (!strcmp (d->name, "end_sys_fields")) break; if (d->type->type != ev_field) continue; switch (d->type->aux_type->type) { case ev_float: ADD(qcva("\tfloat\t%s;\n",d->name)); break; case ev_vector: ADD(qcva("\tvec3_t\t%s;\n",d->name)); d=d->next->next->next; // skip the elements break; case ev_string: ADD(qcva("\tstring_t\t%s;\n",d->name)); break; case ev_function: ADD(qcva("\tfunc_t\t%s;\n",d->name)); break; case ev_entity: ADD(qcva("\tint\t%s;\n",d->name)); break; case ev_integer: ADD(qcva("\tint\t%s;\n",d->name)); break; default: ADD(qcva("\tint\t%s;\n",d->name)); break; } } ADD("} entvars_t;\n\n"); ///temp ADD2("//with this the crc isn't needed for fields.\n#ifdef FIELDSSTRUCT\nstruct fieldvars_s {\n\tint ofs;\n\tint type;\n\tchar *name;\n} fieldvars[] = {\n"); f=0; for (d=pr.def_head.next ; d ; d=d->next) { if (!strcmp (d->name, "end_sys_fields")) break; if (d->type->type != ev_field) continue; if (f) ADD2(",\n"); ADD2(qcva("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name)); f = 1; } ADD2("\n};\n#endif\n\n"); //end temp ADD2(qcva("#define PROGHEADER_CRC %i\n", crc)); if (QCC_CheckParm("-progdefs")) { printf ("writing %s\n", filename); f = SafeOpenWrite("progdefs.h", 16384); SafeWrite(f, file, strlen(file)); SafeClose(f); } if (ForcedCRC) return ForcedCRC; return crc; } /*void QCC_PrintFunction (char *name) { int i; QCC_dstatement_t *ds; QCC_dfunction_t *df; for (i=0 ; ifirst_statement; while (1) { QCC_PR_PrintStatement (ds); if (!ds->op) break; ds++; } }*/ /* void QCC_PrintOfs(unsigned int ofs) { int i; bool printfunc; QCC_dstatement_t *ds; QCC_dfunction_t *df; for (i=0 ; ifirst_statement; printfunc = false; while (1) { if (!ds->op) break; if (ds->a == ofs || ds->b == ofs || ds->c == ofs) { QCC_PR_PrintStatement (ds); printfunc = true; } ds++; } if (printfunc) { QCC_PrintFunction(strings + functions[i].s_name); printf(" \n \n"); } } } */ /* ============================================================================== DIRECTORY COPYING / PACKFILE CREATION ============================================================================== */ typedef struct { char name[56]; int filepos, filelen; } packfile_t; typedef struct { char id[4]; int dirofs; int dirlen; } packheader_t; packfile_t pfiles[4096], *pf; int packhandle; int packbytes; /* ============ CreatePath ============ */ void QCC_CreatePath (char *path) { /* char *ofs; for (ofs = path+1 ; *ofs ; ofs++) { if (*ofs == '/') { // create the directory *ofs = 0; #ifdef QCC mkdir(path); #else QCC_mkdir (path); #endif *ofs = '/'; } } */ } /* =========== PackFile Copy a file into the pak file =========== */ void QCC_PackFile (char *src, char *name) { int remaining; #if 1 char *f; #else int in; int count; char buf[4096]; #endif if ( (qbyte *)pf - (qbyte *)pfiles > sizeof(pfiles) ) QCC_Error (ERR_TOOMANYPAKFILES, "Too many files in pak file"); #if 1 f = FS_ReadToMem(src, NULL, &remaining); if (!f) { printf ("%64s : %7s\n", name, ""); // QCC_Error("Failed to open file %s", src); return; } pf->filepos = LittleLong (SafeSeek (packhandle, 0, SEEK_CUR)); pf->filelen = LittleLong (remaining); strcpy (pf->name, name); printf ("%64s : %7i\n", pf->name, remaining); packbytes += remaining; SafeWrite (packhandle, f, remaining); FS_CloseFromMem(f); #else in = SafeOpenRead (src); remaining = filelength (in); pf->filepos = LittleLong (lseek (packhandle, 0, SEEK_CUR)); pf->filelen = LittleLong (remaining); strcpy (pf->name, name); printf ("%64s : %7i\n", pf->name, remaining); packbytes += remaining; while (remaining) { if (remaining < sizeof(buf)) count = remaining; else count = sizeof(buf); SafeRead (in, buf, count); SafeWrite (packhandle, buf, count); remaining -= count; } close (in); #endif pf++; } /* =========== CopyFile Copies a file, creating any directories needed =========== */ void QCC_CopyFile (char *src, char *dest) { /* int in, out; int remaining, count; char buf[4096]; print ("%s to %s\n", src, dest); in = SafeOpenRead (src); remaining = filelength (in); QCC_CreatePath (dest); out = SafeOpenWrite (dest, remaining+10); while (remaining) { if (remaining < sizeof(buf)) count = remaining; else count = sizeof(buf); SafeRead (in, buf, count); SafeWrite (out, buf, count); remaining -= count; } close (in); SafeClose (out); */ } /* =========== CopyFiles =========== */ void _QCC_CopyFiles (int blocknum, int copytype, char *srcdir, char *destdir) { int i; int dirlen; unsigned short crc; packheader_t header; char name[1024]; char srcfile[1024], destfile[1024]; packbytes = 0; if (copytype == 2) { pf = pfiles; packhandle = SafeOpenWrite (destdir, 1024*1024); SafeWrite (packhandle, &header, sizeof(header)); } for (i=0 ; i 0) printf ("%3i unique precache_sounds\n", numsounds); if (nummodels > 0) printf ("%3i unique precache_models\n", nummodels); if (numtextures > 0) printf ("%3i unique precache_textures\n", numtextures); if (numfiles > 0) printf ("%3i unique precache_files\n", numfiles); p = QCC_CheckParm ("-copy"); if (p && p < myargc-2) { // create a new directory tree strcpy (srcdir, myargv[p+1]); strcpy (destdir, myargv[p+2]); if (srcdir[strlen(srcdir)-1] != '/') strcat (srcdir, "/"); if (destdir[strlen(destdir)-1] != '/') strcat (destdir, "/"); _QCC_CopyFiles(0, 1, srcdir, destdir); return; } for ( p = 0; p < 5; p++) { s = QCC_Packname[p]; if (!*s) continue; strcpy(destdir, s); strcpy(srcdir, ""); _QCC_CopyFiles(p+1, 2, srcdir, destdir); } return; /* blocknum = 1; p = QCC_CheckParm ("-pak2"); if (p && p = sizeof(cnst->value)) QCC_Error(ERR_PRECOMPILERCONSTANTTOOLONG, "Compiler constant value is too long\n"); strncpy(cnst->value, val, sizeof(cnst->value)-1); cnst->value[sizeof(cnst->value)-1] = '\0'; } } //optimisations. else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) ) { 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 \n"); // printf ("to build a clean data tree: qcc -copy \n"); // printf ("to build a clean pak file: qcc -pak \n"); // printf ("to bsp all bmodels: qcc -bspmodels \n"); printf ("-Fwasm causes FTEQCC to dump all asm to qc.asm\n"); printf ("-O0 to disable optimisations\n"); printf ("-O1 to optimise for size\n"); printf ("-O2 to optimise more - some behaviours may change\n"); printf ("-O3 to optimise lots - experimental or non-future-proof\n"); printf ("-Oname to enable an optimisation\n"); printf ("-Ono-name to disable optimisations\n"); printf ("-Kkeyword to activate keyword\n"); printf ("-Kno-keyword to disable keyword\n"); printf ("-Wall to give a stupid number of warnings\n"); printf ("-Ttarget to set a output format\n"); printf ("-Fautoproto to enable automatic prototyping\n"); qcc_compileactive = false; return; } if (opt_locals_marshalling) printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nLocals marshalling might be buggy. Use with caution\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); p = QCC_CheckParm ("-src"); if (p && p < argc-1 ) { strcpy (qccmsourcedir, argv[p+1]); strcat (qccmsourcedir, "/"); printf ("Source directory: %s\n", qccmsourcedir); } else #ifndef QCCONLY if (!*qcc_gamedir) sprintf (qccmsourcedir, "src/"); else sprintf (qccmsourcedir, "%s/src/", qcc_gamedir); #else *qccmsourcedir = '\0'; #endif QCC_InitData (); #if 0 p = QCC_CheckParm ("-base"); if (p && p < argc-1 ) sprintf (qccmprogsdat, "%s%s", qccmsourcedir, argv[p+1]); else { //look for a preprogs.src... :o) sprintf (qccmprogsdat, "%spreprogs.src", qccmsourcedir); if (externs->FileSize(qccmprogsdat) <= 0) sprintf (qccmprogsdat, "%sprogs.src", qccmsourcedir); } #endif QCC_PR_BeginCompilation ((void *)qccHunkAlloc (0x100000), 0x100000); #if 0 QCC_ReadPoff(qccmprogsdat); #endif p = QCC_CheckParm ("-srcfile"); if (p && p < argc-1 ) sprintf (qccmprogsdat, "%s%s", qccmsourcedir, argv[p+1]); else { //look for a preprogs.src... :o) sprintf (qccmprogsdat, "%spreprogs.src", qccmsourcedir); if (externs->FileSize(qccmprogsdat) <= 0) sprintf (qccmprogsdat, "%sprogs.src", qccmsourcedir); } printf ("Source file: %s\n", qccmprogsdat); if (QCC_LoadFile (qccmprogsdat, (void *)&qccmsrc) == -1) { return; } newstylesource = false; while(*qccmsrc && *qccmsrc < ' ') qccmsrc++; pr_file_p = QCC_COM_Parse(qccmsrc); #ifdef WRITEASM if (writeasm) { asmfile = fopen("qc.asm", "wb"); if (!asmfile) QCC_Error (ERR_INTERNAL, "Couldn't open file for asm output."); } #endif if (*qcc_token == '#') { void StartNewStyleCompile(void); newstylesource = true; StartNewStyleCompile(); return; } pr_file_p = qccmsrc; QCC_PR_LexWhitespace(); qccmsrc = pr_file_p; s = qccmsrc; pr_file_p = qccmsrc; QCC_PR_SimpleGetToken (); strcpy(qcc_token, pr_token); qccmsrc = pr_file_p; if (!qccmsrc) QCC_Error (ERR_NOOUTPUT, "No destination filename. qcc -help for info."); strcpy (destfile, qcc_token); #ifndef QCCONLY p=1; s2 = strcpy(destfile2, destfile); if (!strncmp(s2, "./", 2)) s2+=2; else { while(!strncmp(s2, "../", 3)) { s2+=3; p++; } } strcpy(qccmfilename, qccmsourcedir); for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--) { if (*s == '/' || *s == '\\') { *(s+1) = '\0'; p--; } } if (s>=qccmfilename) sprintf(destfile, "%s%s", qccmfilename, s2); else sprintf(destfile, "%s", s2); #endif printf ("outputfile: %s\n", destfile); pr_dumpasm = false; currentchunk = NULL; origionalqccmsrc = qccmsrc; } void new_QCC_ContinueCompile(void); //called between exe frames - won't loose net connection (is the theory)... void QCC_ContinueCompile(void) { char *s, *s2; currentchunk = NULL; if (!qcc_compileactive) //HEY! return; if (newstylesource) { new_QCC_ContinueCompile(); return; } qccmsrc = QCC_COM_Parse(qccmsrc); if (!qccmsrc) { if (autoprototype) { qccmsrc = origionalqccmsrc; autoprototype = false; return; } QCC_FinishCompile(); return; } s = qcc_token; strcpy (qccmfilename, qccmsourcedir); while(1) { if (!strncmp(s, "..\\", 3)) { s2 = qccmfilename + strlen(qccmfilename)-2; while (s2>=qccmfilename) { if (*s2 == '/' || *s2 == '\\') { s2[1] = '\0'; break; } s2--; } s+=3; continue; } if (!strncmp(s, ".\\", 2)) { s+=2; continue; } break; } strcat (qccmfilename, s); if (autoprototype) printf ("prototyping %s\n", qccmfilename); else printf ("compiling %s\n", qccmfilename); QCC_LoadFile (qccmfilename, (void *)&qccmsrc2); if (!QCC_PR_CompileFile (qccmsrc2, qccmfilename) ) QCC_Error (ERR_PARSEERRORS, "Errors have occured\n"); } void QCC_FinishCompile(void) { int crc; // int p; currentchunk = NULL; if (setjmp(pr_parse_abort)) QCC_Error(ERR_INTERNAL, ""); if (!QCC_PR_FinishCompilation ()) { QCC_Error (ERR_PARSEERRORS, "compilation errors"); } /* p = QCC_CheckParm ("-asm"); if (p) { for (p++ ; p MAX_ERRORS) return; QCC_PR_SkipToSemicolon (); if (pr_token_type == tt_eof) return; } QCC_PR_ClearGrabMacros (); // clear the frame macros compilingfile = qccmprogsdat; pr_file_p = qccmsrc; s_file = s_file2 = QCC_CopyString (compilingfile); pr_source_line = 0; QCC_PR_NewLine (false); QCC_PR_Lex (); // read first token } void new_QCC_ContinueCompile(void) { if (setjmp(pr_parse_abort)) { // if (pr_error_count != 0) { QCC_Error (ERR_PARSEERRORS, "Errors have occured"); return; } QCC_PR_SkipToSemicolon (); if (pr_token_type == tt_eof) return; } if (pr_token_type == tt_eof) { if (pr_error_count) QCC_Error (ERR_PARSEERRORS, "Errors have occured"); QCC_FinishCompile(); return; } pr_scope = NULL; // outside all functions QCC_PR_ParseDefs (NULL); } /*void new_QCC_ContinueCompile(void) { char *s, *s2; if (!qcc_compileactive) //HEY! return; // compile all the files qccmsrc = QCC_COM_Parse(qccmsrc); if (!qccmsrc) { QCC_FinishCompile(); return; } s = qcc_token; strcpy (qccmfilename, qccmsourcedir); while(1) { if (!strncmp(s, "..\\", 3)) { s2 = qccmfilename + strlen(qccmfilename)-2; while (s2>=qccmfilename) { if (*s2 == '/' || *s2 == '\\') { s2[1] = '\0'; break; } s2--; } s+=3; continue; } if (!strncmp(s, ".\\", 2)) { s+=2; continue; } break; } // strcat (qccmfilename, s); // printf ("compiling %s\n", qccmfilename); // QCC_LoadFile (qccmfilename, (void *)&qccmsrc2); // if (!new_QCC_PR_CompileFile (qccmsrc2, qccmfilename) ) // QCC_Error ("Errors have occured\n"); { if (!pr.memory) QCC_Error ("PR_CompileFile: Didn't clear"); QCC_PR_ClearGrabMacros (); // clear the frame macros compilingfile = filename; pr_file_p = qccmsrc2; s_file = QCC_CopyString (filename); pr_source_line = 0; QCC_PR_NewLine (); QCC_PR_Lex (); // read first token while (pr_token_type != tt_eof) { if (setjmp(pr_parse_abort)) { if (++pr_error_count > MAX_ERRORS) return false; QCC_PR_SkipToSemicolon (); if (pr_token_type == tt_eof) return false; } pr_scope = NULL; // outside all functions QCC_PR_ParseDefs (); } } return (pr_error_count == 0); }*/ #ifdef QCCONLY progfuncs_t *progfuncs; short (*BigShort) (short l); short (*LittleShort) (short l); long (*BigLong) (long l); long (*LittleLong) (long l); float (*BigFloat) (float l); float (*LittleFloat) (float l); /* ============== LoadFile ============== */ 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) { 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