12 char QCC_copyright[1024];
14 char QCC_Packname[5][128];
16 extern int optres_test1;
17 extern int optres_test2;
20 static pbool pr_werror;
24 pbool QCC_PR_SimpleGetToken (void);
25 void QCC_PR_LexWhitespace (void);
27 void *FS_ReadToMem(char *fname, void *membuf, int *len);
28 void FS_CloseFromMem(void *mem);
30 struct qcc_includechunk_s *currentchunk;
32 unsigned int MAX_REGS;
46 #define MAXSOURCEFILESLIST 8
47 char sourcefileslist[MAXSOURCEFILESLIST][1024];
48 int currentsourcefile;
51 void QCC_PR_ResetErrorScope(void);
58 float *qcc_pr_globals;
59 unsigned int numpr_globals;
64 QCC_dstatement_t *statements;
66 int *statement_linenums;
68 QCC_dfunction_t *functions;
71 QCC_ddef_t *qcc_globals;
77 //typedef char PATHSTRING[MAX_DATA_PATH];
79 PATHSTRING *precache_sounds;
80 int *precache_sounds_block;
83 PATHSTRING *precache_textures;
84 int *precache_textures_block;
87 PATHSTRING *precache_models;
88 int *precache_models_block;
91 PATHSTRING *precache_files;
92 int *precache_files_block;
95 extern int numCompilerConstants;
96 hashtable_t compconstantstable;
97 hashtable_t globalstable;
98 hashtable_t localstable;
99 hashtable_t floatconstdefstable;
100 hashtable_t stringconstdefstable;
101 hashtable_t stringconstdefstable_dotranslate;
103 int dotranslate_count;
105 pbool qccwarningdisabled[WARN_MAX];
107 qcc_targetformat_t qcc_targetformat;
111 QCC_type_t *qcc_typeinfo;
121 {"Q302", WARN_NOTREFERENCED},
122 // {"", WARN_NOTREFERENCEDCONST},
123 // {"", WARN_CONFLICTINGRETURNS},
124 {"Q105", WARN_TOOFEWPARAMS},
125 {"Q101", WARN_TOOMANYPARAMS},
126 // {"", WARN_UNEXPECTEDPUNCT},
127 {"Q106", WARN_ASSIGNMENTTOCONSTANT},
128 {"Q203", WARN_MISSINGRETURNVALUE},
129 {"Q204", WARN_WRONGRETURNTYPE},
130 {"Q205", WARN_POINTLESSSTATEMENT},
131 {"Q206", WARN_MISSINGRETURN},
132 {"Q207", WARN_DUPLICATEDEFINITION},
133 {"Q100", WARN_PRECOMPILERMESSAGE},
134 // {"", WARN_STRINGTOOLONG},
135 // {"", WARN_BADTARGET},
136 {"Q120", WARN_BADPRAGMA},
137 // {"", WARN_HANGINGSLASHR},
138 // {"", WARN_NOTDEFINED},
139 // {"", WARN_SWITCHTYPEMISMATCH},
140 // {"", WARN_CONFLICTINGUNIONMEMBER},
141 // {"", WARN_KEYWORDDISABLED},
142 // {"", WARN_ENUMFLAGS_NOTINTEGER},
143 // {"", WARN_ENUMFLAGS_NOTBINARY},
144 // {"", WARN_CASEINSENSATIVEFRAMEMACRO},
145 {"Q111", WARN_DUPLICATELABEL},
146 {"Q201", WARN_ASSIGNMENTINCONDITIONAL},
147 {"F300", WARN_DEADCODE},
151 int QCC_WarningForName(char *name)
154 for (i = 0; warningnames[i].name; i++)
156 if (!stricmp(name, warningnames[i].name))
157 return warningnames[i].index;
162 optimisations_t optimisations[] =
164 //level 0 = no optimisations
165 //level 1 = size optimisations
166 //level 2 = speed optimisations
167 //level 3 = dodgy optimisations.
168 //level 4 = experimental...
170 {&opt_assignments, "t", 1, FLAG_ASDEFAULT, "assignments", "c = a*b is performed in one operation rather than two, and can cause older decompilers to fail."},
171 {&opt_shortenifnots, "i", 1, FLAG_ASDEFAULT, "shortenifs", "if (!a) was traditionally compiled in two statements. This optimisation does it in one, but can cause some decompilers to get confused."},
172 {&opt_nonvec_parms, "p", 1, FLAG_ASDEFAULT, "nonvec_parms", "In the original qcc, function parameters were specified as a vector store even for floats. This fixes that."},
173 {&opt_constant_names, "c", 2, FLAG_KILLSDEBUGGERS, "constant_names", "This optimisation strips out the names of constants (but not strings) from your progs, resulting in smaller files. It makes decompilers leave out names or fabricate numerical ones."},
174 {&opt_constant_names_strings, "cs", 3, FLAG_KILLSDEBUGGERS, "constant_names_strings", "This optimisation strips out the names of string constants from your progs. However, this can break addons, so don't use it in those cases."},
175 {&opt_dupconstdefs, "d", 1, FLAG_ASDEFAULT, "dupconstdefs", "This will merge definitions of constants which are the same value. Pay extra attention to assignment to constant warnings."},
176 {&opt_noduplicatestrings, "s", 1, 0, "noduplicatestrings", "This will compact the string table that is stored in the progs. It will be considerably smaller with this."},
177 {&opt_locals, "l", 1, FLAG_KILLSDEBUGGERS, "locals", "Strips out local names and definitions. This makes it REALLY hard to decompile"},
178 {&opt_function_names, "n", 1, FLAG_KILLSDEBUGGERS, "function_names", "This strips out the names of functions which are never called. Doesn't make much of an impact though."},
179 {&opt_filenames, "f", 1, FLAG_KILLSDEBUGGERS, "filenames", "This strips out the filenames of the progs. This can confuse the really old decompilers, but is nothing to the more recent ones."},
180 {&opt_unreferenced, "u", 1, FLAG_ASDEFAULT, "unreferenced", "Removes the entries of unreferenced variables. Doesn't make a difference in well maintained code."},
181 {&opt_overlaptemps, "r", 1, FLAG_ASDEFAULT, "overlaptemps", "Optimises the pr_globals count by overlapping temporaries. In QC, every multiplication, division or operation in general produces a temporary variable. This optimisation prevents excess, and in the case of Hexen2's gamecode, reduces the count by 50k. This is the most important optimisation, ever."},
182 {&opt_constantarithmatic, "a", 1, FLAG_ASDEFAULT, "constantarithmatic", "5*6 actually emits an operation into the progs. This prevents that happening, effectivly making the compiler see 30"},
183 {&opt_precache_file, "pf", 2, 0, "precache_file", "Strip out stuff wasted used in function calls and strings to the precache_file builtin (which is actually a stub in quake)."},
184 {&opt_return_only, "ro", 3, FLAG_KILLSDEBUGGERS, "return_only", "Functions ending in a return statement do not need a done statement at the end of the function. This can confuse some decompilers, making functions appear larger than they were."},
185 {&opt_compound_jumps, "cj", 3, FLAG_KILLSDEBUGGERS, "compound_jumps", "This optimisation plays an effect mostly with nested if/else statements, instead of jumping to an unconditional jump statement, it'll jump to the final destination instead. This will bewilder decompilers."},
186 // {&opt_comexprremoval, "cer", 4, 0, "expression_removal", "Eliminate common sub-expressions"}, //this would be too hard...
187 {&opt_stripfunctions, "sf", 3, 0, "strip_functions", "Strips out the 'defs' of functions that were only ever called directly. This does not affect saved games."},
188 {&opt_locals_marshalling, "lm", 4, FLAG_KILLSDEBUGGERS, "locals_marshalling", "Store all locals in one section of the pr_globals. Vastly reducing it. This effectivly does the job of overlaptemps. It's been noticed as buggy by a few, however, and the curcumstances where it causes problems are not yet known."},
189 {&opt_vectorcalls, "vc", 4, FLAG_KILLSDEBUGGERS, "vectorcalls", "Where a function is called with just a vector, this causes the function call to store three floats instead of one vector. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not match entirly."},
193 #define defaultkeyword FLAG_HIDDENINGUI|FLAG_ASDEFAULT|FLAG_MIDCOMPILE
194 #define nondefaultkeyword FLAG_HIDDENINGUI|0|FLAG_MIDCOMPILE
195 //global to store useage to, flags, codename, human-readable name, help text
196 compiler_flag_t compiler_flag[] = {
198 {&keyword_asm, defaultkeyword, "asm", "Keyword: asm", "Disables the 'asm' keyword. Use the writeasm flag to see an example of the asm."},
199 {&keyword_break, defaultkeyword, "break", "Keyword: break", "Disables the 'break' keyword."},
200 {&keyword_case, defaultkeyword, "case", "Keyword: case", "Disables the 'case' keyword."},
201 {&keyword_class, defaultkeyword, "class", "Keyword: class", "Disables the 'class' keyword."},
202 {&keyword_const, defaultkeyword, "const", "Keyword: const", "Disables the 'const' keyword."},
203 {&keyword_continue, defaultkeyword, "continue", "Keyword: continue", "Disables the 'continue' keyword."},
204 {&keyword_default, defaultkeyword, "default", "Keyword: default", "Disables the 'default' keyword."},
205 {&keyword_entity, defaultkeyword, "entity", "Keyword: entity", "Disables the 'entity' keyword."},
206 {&keyword_enum, defaultkeyword, "enum", "Keyword: enum", "Disables the 'enum' keyword."}, //kinda like in c, but typedef not supported.
207 {&keyword_enumflags, defaultkeyword, "enumflags", "Keyword: enumflags", "Disables the 'enumflags' keyword."}, //like enum, but doubles instead of adds 1.
208 {&keyword_extern, defaultkeyword, "extern", "Keyword: extern", "Disables the 'extern' keyword. Use only on functions inside addons."}, //function is external, don't error or warn if the body was not found
209 {&keyword_float, defaultkeyword, "float", "Keyword: float", "Disables the 'float' keyword. (Disables the float keyword without 'local' preceeding it)"},
210 {&keyword_for, defaultkeyword, "for", "Keyword: for", "Disables the 'for' keyword. Syntax: for(assignment; while; increment) {codeblock;}"},
211 {&keyword_goto, defaultkeyword, "goto", "Keyword: goto", "Disables the 'goto' keyword."},
212 {&keyword_int, defaultkeyword, "int", "Keyword: int", "Disables the 'int' keyword."},
213 {&keyword_integer, defaultkeyword, "integer", "Keyword: integer", "Disables the 'integer' keyword."},
214 {&keyword_noref, defaultkeyword, "noref", "Keyword: noref", "Disables the 'noref' keyword."}, //nowhere else references this, don't strip it.
215 {&keyword_nosave, defaultkeyword, "nosave", "Keyword: nosave", "Disables the 'nosave' keyword."}, //don't write the def to the output.
216 {&keyword_shared, defaultkeyword, "shared", "Keyword: shared", "Disables the 'shared' keyword."}, //mark global to be copied over when progs changes (part of FTE_MULTIPROGS)
217 {&keyword_state, nondefaultkeyword,"state", "Keyword: state", "Disables the 'state' keyword."},
218 {&keyword_string, defaultkeyword, "string", "Keyword: string", "Disables the 'string' keyword."},
219 {&keyword_struct, defaultkeyword, "struct", "Keyword: struct", "Disables the 'struct' keyword."},
220 {&keyword_switch, defaultkeyword, "switch", "Keyword: switch", "Disables the 'switch' keyword."},
221 {&keyword_thinktime, nondefaultkeyword,"thinktime", "Keyword: thinktime", "Disables the 'thinktime' keyword which is used in HexenC"},
222 {&keyword_typedef, defaultkeyword, "typedef", "Keyword: typedef", "Disables the 'typedef' keyword."}, //fixme
223 {&keyword_union, defaultkeyword, "union", "Keyword: union", "Disables the 'union' keyword."}, //you surly know what a union is!
224 {&keyword_var, defaultkeyword, "var", "Keyword: var", "Disables the 'var' keyword."},
225 {&keyword_vector, defaultkeyword, "vector", "Keyword: vector", "Disables the 'vector' keyword."},
229 {&keywords_coexist, FLAG_ASDEFAULT, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."},
230 {&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers)
231 {&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance.
232 {&writeasm, 0, "wasm", "Dump Assembler", "Writes out a qc.asm which contains all your functions but in assembler. This is a great way to look for bugs in fteqcc, but can also be used to see exactly what your functions turn into, and thus how to optimise statements better."}, //spit out a qc.asm file, containing an assembler dump of the ENTIRE progs. (Doesn't include initialisation of constants)
233 {&flag_ifstring, FLAG_MIDCOMPILE,"ifstring", "if(string) fix", "Causes if(string) to behave identically to if(string!="") This is most useful with addons of course, but also has adverse effects with FRIK_FILE's fgets, where it becomes impossible to determin the end of the file. In such a case, you can still use asm {IF string 2;RETURN} to detect eof and leave the function."}, //correction for if(string) no-ifstring to get the standard behaviour.
234 {&flag_iffloat, FLAG_MIDCOMPILE,"iffloat","if(-0.0) fix","Fixes certain floating point logic."},
235 {&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensativity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
236 {&flag_caseinsensative, 0, "caseinsens", "Case insensativity", "Causes fteqcc to become case insensative whilst compiling names. It's generally not advised to use this as it compiles a little more slowly and provides little benefit. However, it is required for full reacc support."}, //symbols will be matched to an insensative case if the specified case doesn't exist. This should b usable for any mod
237 {&flag_laxcasts, FLAG_MIDCOMPILE,"lax", "Lax type checks", "Disables many errors (generating warnings instead) when function calls or operations refer to two normally incompatible types. This is required for reacc support, and can also allow certain (evil) mods to compile that were originally written for frikqcc."}, //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
238 {&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"},
239 {&opt_logicops, FLAG_MIDCOMPILE,"lo", "Logic ops", "This changes the behaviour of your code. It generates additional if operations to early-out in if statements. With this flag, the line if (0 && somefunction()) will never call the function. It can thus be considered an optimisation. However, due to the change of behaviour, it is not considered so by fteqcc. Note that due to inprecisions with floats, this flag can cause runaway loop errors within the player walk and run functions (without iffloat also enabled). This code is advised:\nplayer_stand1:\n if (self.velocity_x || self.velocity_y)\nplayer_run\n if (!(self.velocity_x || self.velocity_y))"},
240 {&flag_msvcstyle, FLAG_MIDCOMPILE,"msvcstyle", "MSVC-style errors", "Generates warning and error messages in a format that msvc understands, to facilitate ide integration."},
241 {&flag_filetimes, 0, "filetimes", "Check Filetimes", "Recompiles the progs only if the file times are modified."},
242 {&flag_fasttrackarrays, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"fastarrays","fast arrays where possible", "Generates extra instructions inside array handling functions to detect engine and use extension opcodes only in supporting engines.\nAdds a global which is set by the engine if the engine supports the extra opcodes. Note that this applies to all arrays or none."},
243 {&flag_assume_integer, FLAG_MIDCOMPILE,"assumeint", "Assume Integers", "Numerical constants are assumed to be integers, instead of floats."},
244 {&pr_subscopedlocals, FLAG_MIDCOMPILE, "subscope", "Subscoped Locals", "Restrict the scope of locals to the block they are actually defined within, as in C."},
249 qcc_targetformat_t target;
252 {QCF_STANDARD, "standard"},
253 {QCF_STANDARD, "q1"},
254 {QCF_STANDARD, "quakec"},
255 {QCF_HEXEN2, "hexen2"},
259 {QCF_KK7, "bigprogs"},
260 {QCF_KK7, "version7"},
263 {QCF_DARKPLACES,"darkplaces"},
264 {QCF_DARKPLACES,"dp"},
265 {QCF_QTEST, "qtest"},
273 Runs qbsp and light on all of the models with a .bsp extension
276 int QCC_CheckParm (char *check);
278 void QCC_BspModels (void)
288 p = QCC_CheckParm ("-bspmodels");
292 QCC_Error (ERR_BADPARMS, "-bspmodels must preceed a game directory");
293 gamedir = myargv[p+1];
295 for (i=0 ; i<nummodels ; i++)
297 m = precache_models[i];
298 if (strcmp(m+strlen(m)-4, ".bsp"))
301 name[strlen(m)-4] = 0;
302 sprintf (cmd, "qbsp %s/%s ; light -extra %s/%s", gamedir, name, gamedir, name);
303 result = system (cmd); // do something with the result
306 QCC_Error(ERR_INTERNAL, "QCC_BspModels() system returned non zero (failure) with: qbsp %s/%s ; light -extra %s/%s (%i)\n", gamedir, name, gamedir, name, errno);
310 // CopyString returns an offset from the string heap
311 int QCC_CopyString (char *str)
316 if (opt_noduplicatestrings)
321 for (s = strings; s < strings+strofs; s++)
324 optres_noduplicatestrings += strlen(str);
330 strcpy (strings+strofs, str);
331 strofs += strlen(str)+1;
335 int QCC_CopyDupBackString (char *str)
340 for (s = strings+strofs-1; s>strings ; s--)
345 strcpy (strings+strofs, str);
346 strofs += strlen(str)+1;
350 void QCC_PrintStrings (void)
354 for (i=0 ; i<strofs ; i += l)
356 l = strlen(strings+i) + 1;
358 for (j=0 ; j<l ; j++)
360 if (strings[i+j] == '\n')
366 putchar (strings[i+j]);
373 /*void QCC_PrintFunctions (void)
378 for (i=0 ; i<numfunctions ; i++)
381 printf ("%s : %s : %i %i (", strings + d->s_file, strings + d->s_name, d->first_statement, d->parm_start);
382 for (j=0 ; j<d->numparms ; j++)
383 printf ("%i ",d->parm_size[j]);
388 void QCC_PrintFields (void)
393 for (i=0 ; i<numfielddefs ; i++)
396 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
400 void QCC_PrintGlobals (void)
405 for (i=0 ; i<numglobaldefs ; i++)
408 printf ("%5i : (%i) %s\n", d->ofs, d->type, strings + d->s_name);
412 int encode(int len, int method, char *in, int handle);
413 int WriteSourceFiles(int h, dprograms_t *progs, pbool sourceaswell)
415 includeddatafile_t *idf;
416 qcc_cachedsourcefile_t *f;
421 for (f = qcc_sourcefile; f ; f=f->next)
423 if (f->type == FT_CODE && !sourceaswell)
426 SafeWrite(h, f->filename, strlen(f->filename)+1);
427 i = PRLittleLong(f->size);
428 SafeWrite(h, &i, sizeof(int));
430 i = PRLittleLong(encrpytmode);
431 SafeWrite(h, &i, sizeof(int));
434 for (i = 0; i < f->size; i++)
437 SafeWrite(h, f->file, f->size);
440 for (f = qcc_sourcefile,num=0; f ; f=f->next)
442 if (f->type == FT_CODE && !sourceaswell)
449 idf = qccHunkAlloc(sizeof(includeddatafile_t)*num);
450 for (f = qcc_sourcefile,num=0; f ; f=f->next)
452 if (f->type == FT_CODE && !sourceaswell)
455 strcpy(idf[num].filename, f->filename);
456 idf[num].size = f->size;
458 idf[num].compmethod = 2;
460 idf[num].compmethod = 1;
462 idf[num].ofs = SafeSeek(h, 0, SEEK_CUR);
463 idf[num].compsize = QC_encode(progfuncs, f->size, idf[num].compmethod, f->file, h);
467 ofs = SafeSeek(h, 0, SEEK_CUR);
468 SafeWrite(h, &num, sizeof(int));
469 SafeWrite(h, idf, sizeof(includeddatafile_t)*num);
471 qcc_sourcefile = NULL;
476 void QCC_InitData (void)
478 static char parmname[12][MAX_PARMS];
479 static temp_t ret_temp;
482 qcc_sourcefile = NULL;
490 memset(&ret_temp, 0, sizeof(ret_temp));
492 def_ret.ofs = OFS_RETURN;
493 def_ret.name = "return";
494 def_ret.temp = &ret_temp;
495 def_ret.constant = false;
497 ret_temp.ofs = def_ret.ofs;
498 ret_temp.scope = NULL;
500 ret_temp.next = NULL;
501 for (i=0 ; i<MAX_PARMS ; i++)
503 def_parms[i].temp = NULL;
504 def_parms[i].type = NULL;
505 def_parms[i].ofs = OFS_PARM0 + 3*i;
506 def_parms[i].name = parmname[i];
507 sprintf(parmname[i], "parm%i", i);
511 int WriteBodylessFuncs (int handle)
515 for (d=pr.def_head.next ; d ; d=d->next)
517 if (d->type->type == ev_function && !d->scope)// function parms are ok
519 if (d->initialized != 1 && d->references>0)
521 SafeWrite(handle, d->name, strlen(d->name)+1);
530 //marshalled locals remaps all the functions to use the range MAX_REGS onwards for the offset to their locals.
531 //this function remaps all the locals back into the function.
532 void QCC_UnmarshalLocals(void)
542 for (def = pr.def_head.next ; def ; def = def->next)
544 if (def->ofs >= MAX_REGS) //unmap defs.
546 def->ofs = def->ofs + ofs - MAX_REGS;
552 for (i = 0; i < numfunctions; i++)
554 if (functions[i].parm_start == MAX_REGS)
555 functions[i].parm_start = ofs;
558 QCC_RemapOffsets(0, numstatements, MAX_REGS, MAX_REGS + maxo-numpr_globals + 3, ofs);
560 numpr_globals = maxo+3;
561 if (numpr_globals > MAX_REGS)
562 QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals are in use to unmarshal all locals");
565 printf("Total of %i marshalled globals\n", maxo-ofs);
568 CompilerConstant_t *QCC_PR_CheckCompConstDefined(char *def);
569 pbool QCC_WriteData (int crc)
571 char element[MAX_NAME];
572 QCC_def_t *def, *comp_x, *comp_y, *comp_z;
577 pbool debugtarget = false;
579 int outputsttype = PST_DEFAULT;
580 pbool warnedunref = false;
582 if (numstatements==1 && numfunctions==1 && numglobaldefs==1 && numfielddefs==1)
584 printf("nothing to write\n");
588 progs.blockscompressed=0;
590 if (numstatements > MAX_STATEMENTS)
591 QCC_Error(ERR_TOOMANYSTATEMENTS, "Too many statements - %i\nAdd \"MAX_STATEMENTS\" \"%i\" to qcc.cfg", numstatements, (numstatements+32768)&~32767);
593 if (strofs > MAX_STRINGS)
594 QCC_Error(ERR_TOOMANYSTRINGS, "Too many strings - %i\nAdd \"MAX_STRINGS\" \"%i\" to qcc.cfg", strofs, (strofs+32768)&~32767);
596 QCC_UnmarshalLocals();
598 switch (qcc_targetformat)
603 printf("Warning: There are some functions without bodies.\n");
605 if (numpr_globals > 65530 )
607 printf("Forcing target to FTE32 due to numpr_globals\n");
608 outputsttype = PST_FTE32;
610 else if (qcc_targetformat == QCF_HEXEN2)
612 printf("Progs execution requires a Hexen2 compatible engine\n");
617 if (numpr_globals >= 32768) //not much of a different format. Rewrite output to get it working on original executors?
618 printf("An enhanced executor will be required (FTE/QF/KK)\n");
620 printf("Progs should run on any Quake executor\n");
624 qcc_targetformat = QCF_FTE;
628 if (qcc_targetformat == QCF_FTEDEBUG)
631 if (numpr_globals > 65530)
633 printf("Using 32 bit target due to numpr_globals\n");
634 outputsttype = PST_FTE32;
637 if (qcc_targetformat == QCF_DARKPLACES)
641 //compression of blocks?
642 if (compressoutput) progs.blockscompressed |=1; //statements
643 if (compressoutput) progs.blockscompressed |=2; //defs
644 if (compressoutput) progs.blockscompressed |=4; //fields
645 if (compressoutput) progs.blockscompressed |=8; //functions
646 if (compressoutput) progs.blockscompressed |=16; //strings
647 if (compressoutput) progs.blockscompressed |=32; //globals
648 if (compressoutput) progs.blockscompressed |=64; //line numbers
649 if (compressoutput) progs.blockscompressed |=128; //types
650 //include a type block?
651 types = debugtarget;//!!QCC_PR_CheckCompConstDefined("TYPES"); //useful for debugging and saving (maybe, anyway...).
652 if (sizeof(char *) != sizeof(string_t))
654 //qcc_typeinfo_t has a char* inside it, which changes size
655 printf("AMD64 builds cannot write typeinfo structures\n");
661 if (qcc_targetformat == QCF_DARKPLACES)
662 printf("DarkPlaces or FTE will be required\n");
664 printf("An FTE executor will be required\n");
669 printf("Warning: There are some functions without bodies.\n");
670 if (numpr_globals > 65530)
671 printf("Warning: Saving is not supported. Ensure all engine read fields and globals are defined early on.\n");
673 printf("A KK compatible executor will be required (FTE/KK)\n");
674 outputsttype = PST_KKQWSV;
677 printf("Compiled QTest progs will most likely not work at all. YOU'VE BEEN WARNED!\n");
678 outputsttype = PST_QTEST;
681 Sys_Error("invalid progs type chosen!");
684 //part of how compilation works. This def is always present, and never used.
685 def = QCC_PR_GetDef(NULL, "end_sys_globals", NULL, false, 0, false);
689 def = QCC_PR_GetDef(NULL, "end_sys_fields", NULL, false, 0, false);
693 for (def = pr.def_head.next ; def ; def = def->next)
695 if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector))
696 { //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x
697 sprintf(element, "%s_x", def->name);
698 comp_x = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
699 sprintf(element, "%s_y", def->name);
700 comp_y = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
701 sprintf(element, "%s_z", def->name);
702 comp_z = QCC_PR_GetDef(NULL, element, def->scope, false, 0, false);
705 if (comp_x && comp_y && comp_z)
707 h += comp_x->references;
708 h += comp_y->references;
709 h += comp_z->references;
711 if (!def->references)
712 if (!comp_x->references || !comp_y->references || !comp_z->references) //one of these vars is useless...
721 comp_x->references = h;
723 comp_y->references = h;
725 comp_z->references = h;
728 if (def->references<=0)
731 QCC_PR_Warning(WARN_NOTREFERENCEDCONST, strings + def->s_file, def->s_line, "%s no references", def->name);
733 QCC_PR_Warning(WARN_NOTREFERENCED, strings + def->s_file, def->s_line, "%s no references", def->name);
736 QCC_PR_Note(WARN_NOTREFERENCED, NULL, 0, "You can use the noref prefix or pragma to silence this message.");
740 if (opt_unreferenced && def->type->type != ev_field)
742 optres_unreferenced++;
747 if (def->type->type == ev_function)
749 if (opt_function_names && functions[G_FUNCTION(def->ofs)].first_statement<0)
751 optres_function_names++;
754 if (!def->timescalled)
756 if (def->references<=1)
757 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);
759 // QCC_PR_Warning(WARN_DEADCODE, strings + def->s_file, def->s_line, "%s is never directly called", def->name);
761 if (opt_stripfunctions && def->timescalled >= def->references-1) //make sure it's not copied into a different var.
762 { //if it ever does self.think then it could be needed for saves.
763 optres_stripfunctions++; //if it's only ever called explicitly, the engine doesn't need to know.
767 // df = &functions[numfunctions];
771 else if (def->type->type == ev_field && def->constant)
773 dd = &fields[numfielddefs];
775 dd->type = def->type->aux_type->type;
776 dd->s_name = QCC_CopyString (def->name);
777 dd->ofs = G_INT(def->ofs);
779 else if ((def->scope||def->constant) && (def->type->type != ev_string || opt_constant_names_strings))
781 if (opt_constant_names)
783 if (def->type->type == ev_string)
784 optres_constant_names_strings += strlen(def->name);
786 optres_constant_names += strlen(def->name);
791 // if (!def->saved && def->type->type != ev_string)
793 dd = &qcc_globals[numglobaldefs];
797 dd->type = def->type-qcc_typeinfo;
799 dd->type = def->type->type;
800 #ifdef DEF_SAVEGLOBAL
801 if ( def->saved && ((!def->initialized || def->type->type == ev_function)
802 // && def->type->type != ev_function
803 && def->type->type != ev_field
804 && def->scope == NULL))
806 dd->type |= DEF_SAVEGLOBAL;
810 dd->type |= DEF_SHARED;
812 if (opt_locals && (def->scope || !strcmp(def->name, "IMMEDIATE")))
815 optres_locals += strlen(def->name);
818 dd->s_name = QCC_CopyString (def->name);
822 for (i = 0; i < numglobaldefs; i++)
824 dd = &qcc_globals[i];
825 if (!(dd->type & DEF_SAVEGLOBAL)) //only warn about saved ones.
828 for (h = 0; h < numglobaldefs; h++)
832 if (dd->ofs == qcc_globals[h].ofs)
834 if (dd->type != qcc_globals[h].type)
836 if (dd->type != ev_vector && qcc_globals[h].type != ev_float)
837 QCC_PR_Warning(0, NULL, 0, "Mismatched union global types (%s and %s)", strings+dd->s_name, strings+qcc_globals[h].s_name);
839 //remove the saveglobal flag on the duplicate globals.
840 qcc_globals[h].type &= ~DEF_SAVEGLOBAL;
844 for (i = 1; i < numfielddefs; i++)
848 if (dd->type == ev_vector) //just ignore vectors.
851 for (h = 1; h < numfielddefs; h++)
855 if (dd->ofs == fields[h].ofs)
857 if (dd->type != fields[h].type)
859 if (fields[h].type != ev_vector)
861 QCC_PR_Warning(0, NULL, 0, "Mismatched union field types (%s and %s)", strings+dd->s_name, strings+fields[h].s_name);
868 if (numglobaldefs > MAX_GLOBALS)
869 QCC_Error(ERR_TOOMANYGLOBALS, "Too many globals - %i\nAdd \"MAX_GLOBALS\" \"%i\" to qcc.cfg", numglobaldefs, (numglobaldefs+32768)&~32767);
872 for (i = 0; i < nummodels; i++)
874 if (!precache_models_used[i])
875 QCC_PR_Warning(WARN_EXTRAPRECACHE, NULL, 0, "Model %s was precached but not directly used", precache_models[i]);
876 else if (!precache_models_block[i])
877 QCC_PR_Warning(WARN_NOTPRECACHED, NULL, 0, "Model %s was used but not precached", precache_models[i]);
883 strofs = (strofs+3)&~3;
887 printf ("%6i strofs (of %i)\n", strofs, MAX_STRINGS);
888 printf ("%6i numstatements (of %i)\n", numstatements, MAX_STATEMENTS);
889 printf ("%6i numfunctions (of %i)\n", numfunctions, MAX_FUNCTIONS);
890 printf ("%6i numglobaldefs (of %i)\n", numglobaldefs, MAX_GLOBALS);
891 printf ("%6i numfielddefs (%i unique) (of %i)\n", numfielddefs, pr.size_fields, MAX_FIELDS);
892 printf ("%6i numpr_globals (of %i)\n", numpr_globals, MAX_REGS);
896 strcpy(destfile, "progs.dat");
898 printf("Writing %s\n", destfile);
899 h = SafeOpenWrite (destfile, 2*1024*1024);
900 SafeWrite (h, &progs, sizeof(progs));
901 SafeWrite (h, "\r\n\r\n", 4);
902 SafeWrite (h, QCC_copyright, strlen(QCC_copyright)+1);
903 SafeWrite (h, "\r\n\r\n", 4);
904 while(SafeSeek (h, 0, SEEK_CUR) & 3)//this is a lame way to do it
906 SafeWrite (h, "\0", 1);
909 progs.ofs_strings = SafeSeek (h, 0, SEEK_CUR);
910 progs.numstrings = strofs;
912 if (progs.blockscompressed&16)
914 SafeWrite (h, &len, sizeof(int)); //save for later
915 len = QC_encode(progfuncs, strofs*sizeof(char), 2, (char *)strings, h); //write
916 i = SafeSeek (h, 0, SEEK_CUR);
917 SafeSeek(h, progs.ofs_strings, SEEK_SET);//seek back
918 len = PRLittleLong(len);
919 SafeWrite (h, &len, sizeof(int)); //write size.
920 SafeSeek(h, i, SEEK_SET);
923 SafeWrite (h, strings, strofs);
925 progs.ofs_statements = SafeSeek (h, 0, SEEK_CUR);
926 progs.numstatements = numstatements;
928 if (qcc_targetformat == QCF_HEXEN2)
930 for (i=0 ; i<numstatements ; i++)
932 if (statements[i].op >= OP_CALL1 && statements[i].op <= OP_CALL8)
933 QCC_Error(ERR_BADTARGETSWITCH, "Target switching produced incompatible instructions");
934 else if (statements[i].op >= OP_CALL1H && statements[i].op <= OP_CALL8H)
935 statements[i].op = statements[i].op - OP_CALL1H + OP_CALL1;
939 for (i=0 ; i<numstatements ; i++)
945 for (i=0 ; i<numstatements ; i++)
947 statements[i].op = PRLittleLong/*PRLittleShort*/(statements[i].op);
948 statements[i].a = PRLittleLong/*PRLittleShort*/(statements[i].a);
949 statements[i].b = PRLittleLong/*PRLittleShort*/(statements[i].b);
950 statements[i].c = PRLittleLong/*PRLittleShort*/(statements[i].c);
953 if (progs.blockscompressed&1)
955 SafeWrite (h, &len, sizeof(int)); //save for later
956 len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement32_t), 2, (char *)statements, h); //write
957 i = SafeSeek (h, 0, SEEK_CUR);
958 SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
959 len = PRLittleLong(len);
960 SafeWrite (h, &len, sizeof(int)); //write size.
961 SafeSeek(h, i, SEEK_SET);
964 SafeWrite (h, statements, numstatements*sizeof(QCC_dstatement32_t));
967 #define qtst ((qtest_statement_t*) statements)
968 for (i=0 ; i<numstatements ; i++) // scale down from 16-byte internal to 12-byte qtest
970 QCC_dstatement_t stmt = statements[i];
971 qtst[i].line = 0; // no line support
972 qtst[i].op = PRLittleShort((unsigned short)stmt.op);
974 qtst[i].a = PRLittleShort((short)stmt.a);
976 qtst[i].a = (unsigned short)PRLittleShort((unsigned short)stmt.a);
978 qtst[i].b = PRLittleShort((short)stmt.b);
980 qtst[i].b = (unsigned short)PRLittleShort((unsigned short)stmt.b);
982 qtst[i].c = PRLittleShort((short)stmt.c);
984 qtst[i].c = (unsigned short)PRLittleShort((unsigned short)stmt.c);
988 SafeWrite (h, qtst, numstatements*sizeof(qtest_statement_t));
992 #define statements16 ((QCC_dstatement16_t*) statements)
993 for (i=0 ; i<numstatements ; i++) //resize as we go - scaling down
995 statements16[i].op = PRLittleShort((unsigned short)statements[i].op);
996 if (statements[i].a < 0)
997 statements16[i].a = PRLittleShort((short)statements[i].a);
999 statements16[i].a = (unsigned short)PRLittleShort((unsigned short)statements[i].a);
1000 if (statements[i].b < 0)
1001 statements16[i].b = PRLittleShort((short)statements[i].b);
1003 statements16[i].b = (unsigned short)PRLittleShort((unsigned short)statements[i].b);
1004 if (statements[i].c < 0)
1005 statements16[i].c = PRLittleShort((short)statements[i].c);
1007 statements16[i].c = (unsigned short)PRLittleShort((unsigned short)statements[i].c);
1010 if (progs.blockscompressed&1)
1012 SafeWrite (h, &len, sizeof(int)); //save for later
1013 len = QC_encode(progfuncs, numstatements*sizeof(QCC_dstatement16_t), 2, (char *)statements16, h); //write
1014 i = SafeSeek (h, 0, SEEK_CUR);
1015 SafeSeek(h, progs.ofs_statements, SEEK_SET);//seek back
1016 len = PRLittleLong(len);
1017 SafeWrite (h, &len, sizeof(int)); //write size.
1018 SafeSeek(h, i, SEEK_SET);
1021 SafeWrite (h, statements16, numstatements*sizeof(QCC_dstatement16_t));
1024 Sys_Error("structtype error");
1027 progs.ofs_functions = SafeSeek (h, 0, SEEK_CUR);
1028 progs.numfunctions = numfunctions;
1030 switch (outputsttype)
1034 // this sucks but the structures are just too different
1035 qtest_function_t *qtestfuncs = (qtest_function_t *)qccHunkAlloc(sizeof(qtest_function_t)*numfunctions);
1037 for (i=0 ; i<numfunctions ; i++)
1041 qtestfuncs[i].unused1 = 0;
1042 qtestfuncs[i].profile = 0;
1043 qtestfuncs[i].first_statement = PRLittleLong (functions[i].first_statement);
1044 qtestfuncs[i].parm_start = PRLittleLong (functions[i].parm_start);
1045 qtestfuncs[i].s_name = PRLittleLong (functions[i].s_name);
1046 qtestfuncs[i].s_file = PRLittleLong (functions[i].s_file);
1047 qtestfuncs[i].numparms = PRLittleLong ((functions[i].numparms>MAX_PARMS)?MAX_PARMS:functions[i].numparms);
1048 qtestfuncs[i].locals = PRLittleLong (functions[i].locals);
1049 for (j = 0; j < MAX_PARMS; j++)
1050 qtestfuncs[i].parm_size[j] = PRLittleLong((int)functions[i].parm_size[j]);
1053 SafeWrite (h, qtestfuncs, numfunctions*sizeof(qtest_function_t));
1059 for (i=0 ; i<numfunctions ; i++)
1061 functions[i].first_statement = PRLittleLong (functions[i].first_statement);
1062 functions[i].parm_start = PRLittleLong (functions[i].parm_start);
1063 functions[i].s_name = PRLittleLong (functions[i].s_name);
1064 functions[i].s_file = PRLittleLong (functions[i].s_file);
1065 functions[i].numparms = PRLittleLong ((functions[i].numparms>MAX_PARMS)?MAX_PARMS:functions[i].numparms);
1066 functions[i].locals = PRLittleLong (functions[i].locals);
1069 if (progs.blockscompressed&8)
1071 SafeWrite (h, &len, sizeof(int)); //save for later
1072 len = QC_encode(progfuncs, numfunctions*sizeof(QCC_dfunction_t), 2, (char *)functions, h); //write
1073 i = SafeSeek (h, 0, SEEK_CUR);
1074 SafeSeek(h, progs.ofs_functions, SEEK_SET);//seek back
1075 len = PRLittleLong(len);
1076 SafeWrite (h, &len, sizeof(int)); //write size.
1077 SafeSeek(h, i, SEEK_SET);
1080 SafeWrite (h, functions, numfunctions*sizeof(QCC_dfunction_t));
1083 Sys_Error("structtype error");
1086 switch(outputsttype)
1089 // qtest needs a struct remap but should be able to get away with a simple swap here
1090 for (i=0 ; i<numglobaldefs ; i++)
1092 qtest_def_t qtdef = ((qtest_def_t *)qcc_globals)[i];
1093 qcc_globals[i].type = qtdef.type;
1094 qcc_globals[i].ofs = qtdef.ofs;
1095 qcc_globals[i].s_name = qtdef.s_name;
1097 for (i=0 ; i<numfielddefs ; i++)
1099 qtest_def_t qtdef = ((qtest_def_t *)fields)[i];
1100 fields[i].type = qtdef.type;
1101 fields[i].ofs = qtdef.ofs;
1102 fields[i].s_name = qtdef.s_name;
1104 // passthrough.. reuse FTE32 code
1106 progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR);
1107 progs.numglobaldefs = numglobaldefs;
1108 for (i=0 ; i<numglobaldefs ; i++)
1110 qcc_globals[i].type = PRLittleLong/*PRLittleShort*/ (qcc_globals[i].type);
1111 qcc_globals[i].ofs = PRLittleLong/*PRLittleShort*/ (qcc_globals[i].ofs);
1112 qcc_globals[i].s_name = PRLittleLong (qcc_globals[i].s_name);
1115 if (progs.blockscompressed&2)
1117 SafeWrite (h, &len, sizeof(int)); //save for later
1118 len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef_t), 2, (char *)qcc_globals, h); //write
1119 i = SafeSeek (h, 0, SEEK_CUR);
1120 SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
1121 len = PRLittleLong(len);
1122 SafeWrite (h, &len, sizeof(int)); //write size.
1123 SafeSeek(h, i, SEEK_SET);
1126 SafeWrite (h, qcc_globals, numglobaldefs*sizeof(QCC_ddef_t));
1128 progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
1129 progs.numfielddefs = numfielddefs;
1131 for (i=0 ; i<numfielddefs ; i++)
1133 fields[i].type = PRLittleLong/*PRLittleShort*/ (fields[i].type);
1134 fields[i].ofs = PRLittleLong/*PRLittleShort*/ (fields[i].ofs);
1135 fields[i].s_name = PRLittleLong (fields[i].s_name);
1138 if (progs.blockscompressed&4)
1140 SafeWrite (h, &len, sizeof(int)); //save for later
1141 len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef_t), 2, (char *)fields, h); //write
1142 i = SafeSeek (h, 0, SEEK_CUR);
1143 SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
1144 len = PRLittleLong(len);
1145 SafeWrite (h, &len, sizeof(int)); //write size.
1146 SafeSeek(h, i, SEEK_SET);
1149 SafeWrite (h, fields, numfielddefs*sizeof(QCC_ddef_t));
1153 #define qcc_globals16 ((QCC_ddef16_t*)qcc_globals)
1154 #define fields16 ((QCC_ddef16_t*)fields)
1155 progs.ofs_globaldefs = SafeSeek (h, 0, SEEK_CUR);
1156 progs.numglobaldefs = numglobaldefs;
1157 for (i=0 ; i<numglobaldefs ; i++)
1159 qcc_globals16[i].type = (unsigned short)PRLittleShort ((unsigned short)qcc_globals[i].type);
1160 qcc_globals16[i].ofs = (unsigned short)PRLittleShort ((unsigned short)qcc_globals[i].ofs);
1161 qcc_globals16[i].s_name = PRLittleLong (qcc_globals[i].s_name);
1164 if (progs.blockscompressed&2)
1166 SafeWrite (h, &len, sizeof(int)); //save for later
1167 len = QC_encode(progfuncs, numglobaldefs*sizeof(QCC_ddef16_t), 2, (char *)qcc_globals16, h); //write
1168 i = SafeSeek (h, 0, SEEK_CUR);
1169 SafeSeek(h, progs.ofs_globaldefs, SEEK_SET);//seek back
1170 len = PRLittleLong(len);
1171 SafeWrite (h, &len, sizeof(int)); //write size.
1172 SafeSeek(h, i, SEEK_SET);
1175 SafeWrite (h, qcc_globals16, numglobaldefs*sizeof(QCC_ddef16_t));
1177 progs.ofs_fielddefs = SafeSeek (h, 0, SEEK_CUR);
1178 progs.numfielddefs = numfielddefs;
1180 for (i=0 ; i<numfielddefs ; i++)
1182 fields16[i].type = (unsigned short)PRLittleShort ((unsigned short)fields[i].type);
1183 fields16[i].ofs = (unsigned short)PRLittleShort ((unsigned short)fields[i].ofs);
1184 fields16[i].s_name = PRLittleLong (fields[i].s_name);
1187 if (progs.blockscompressed&4)
1189 SafeWrite (h, &len, sizeof(int)); //save for later
1190 len = QC_encode(progfuncs, numfielddefs*sizeof(QCC_ddef16_t), 2, (char *)fields16, h); //write
1191 i = SafeSeek (h, 0, SEEK_CUR);
1192 SafeSeek(h, progs.ofs_fielddefs, SEEK_SET);//seek back
1193 len = PRLittleLong(len);
1194 SafeWrite (h, &len, sizeof(int)); //write size.
1195 SafeSeek(h, i, SEEK_SET);
1198 SafeWrite (h, fields16, numfielddefs*sizeof(QCC_ddef16_t));
1201 Sys_Error("structtype error");
1204 progs.ofs_globals = SafeSeek (h, 0, SEEK_CUR);
1205 progs.numglobals = numpr_globals;
1207 for (i=0 ; (unsigned)i<numpr_globals ; i++)
1208 ((int *)qcc_pr_globals)[i] = PRLittleLong (((int *)qcc_pr_globals)[i]);
1210 if (progs.blockscompressed&32)
1212 SafeWrite (h, &len, sizeof(int)); //save for later
1213 len = QC_encode(progfuncs, numpr_globals*4, 2, (char *)qcc_pr_globals, h); //write
1214 i = SafeSeek (h, 0, SEEK_CUR);
1215 SafeSeek(h, progs.ofs_globals, SEEK_SET);//seek back
1216 len = PRLittleLong(len);
1217 SafeWrite (h, &len, sizeof(int)); //write size.
1218 SafeSeek(h, i, SEEK_SET);
1221 SafeWrite (h, qcc_pr_globals, numpr_globals*4);
1224 for (i=0 ; i<numtypeinfos ; i++)
1226 if (qcc_typeinfo[i].aux_type)
1227 qcc_typeinfo[i].aux_type = (QCC_type_t*)(qcc_typeinfo[i].aux_type - qcc_typeinfo);
1228 if (qcc_typeinfo[i].next)
1229 qcc_typeinfo[i].next = (QCC_type_t*)(qcc_typeinfo[i].next - qcc_typeinfo);
1230 qcc_typeinfo[i].name = (char*)QCC_CopyDupBackString(qcc_typeinfo[i].name);
1234 progs.ofslinenums = 0;
1235 progs.secondaryversion = 0;
1236 progs.ofsbodylessfuncs = 0;
1237 progs.numbodylessfuncs = 0;
1238 progs.ofs_types = 0;
1241 switch(qcc_targetformat)
1244 progs.version = PROG_QTESTVERSION;
1247 progs.version = PROG_KKQWSVVERSION;
1250 case QCF_HEXEN2: //urgh
1251 progs.version = PROG_VERSION;
1253 case QCF_DARKPLACES:
1256 progs.version = PROG_EXTENDEDVERSION;
1258 if (outputsttype == PST_FTE32)
1259 progs.secondaryversion = PROG_SECONDARYVERSION32;
1261 progs.secondaryversion = PROG_SECONDARYVERSION16;
1263 progs.ofsbodylessfuncs = SafeSeek (h, 0, SEEK_CUR);
1264 progs.numbodylessfuncs = WriteBodylessFuncs(h);
1268 progs.ofslinenums = SafeSeek (h, 0, SEEK_CUR);
1269 if (progs.blockscompressed&64)
1271 SafeWrite (h, &len, sizeof(int)); //save for later
1272 len = QC_encode(progfuncs, numstatements*sizeof(int), 2, (char *)statement_linenums, h); //write
1273 i = SafeSeek (h, 0, SEEK_CUR);
1274 SafeSeek(h, progs.ofslinenums, SEEK_SET);//seek back
1275 len = PRLittleLong(len);
1276 SafeWrite (h, &len, sizeof(int)); //write size.
1277 SafeSeek(h, i, SEEK_SET);
1280 SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1283 progs.ofslinenums = 0;
1287 progs.ofs_types = SafeSeek (h, 0, SEEK_CUR);
1288 if (progs.blockscompressed&128)
1290 SafeWrite (h, &len, sizeof(int)); //save for later
1291 len = QC_encode(progfuncs, sizeof(QCC_type_t)*numtypeinfos, 2, (char *)qcc_typeinfo, h); //write
1292 i = SafeSeek (h, 0, SEEK_CUR);
1293 SafeSeek(h, progs.ofs_types, SEEK_SET);//seek back#
1294 len = PRLittleLong(len);
1295 SafeWrite (h, &len, sizeof(int)); //write size.
1296 SafeSeek(h, i, SEEK_SET);
1299 SafeWrite (h, qcc_typeinfo, sizeof(QCC_type_t)*numtypeinfos);
1300 progs.numtypes = numtypeinfos;
1304 progs.ofs_types = 0;
1308 progs.ofsfiles = WriteSourceFiles(h, &progs, debugtarget);
1313 printf ("%6i TOTAL SIZE\n", (int)SafeSeek (h, 0, SEEK_CUR));
1315 progs.entityfields = pr.size_fields;
1319 // qbyte swap the header and write it out
1321 for (i=0 ; i<sizeof(progs)/4 ; i++)
1322 ((int *)&progs)[i] = PRLittleLong ( ((int *)&progs)[i] );
1325 SafeSeek (h, 0, SEEK_SET);
1326 SafeWrite (h, &progs, sizeof(progs));
1333 printf("Not writing linenumbers file due to conflicting optimisation\n");
1337 unsigned int lnotype = *(unsigned int*)"LNOF";
1338 unsigned int version = 1;
1339 StripExtension(destfile);
1340 strcat(destfile, ".lno");
1342 printf("Writing %s for debugging\n", destfile);
1343 h = SafeOpenWrite (destfile, 2*1024*1024);
1344 SafeWrite (h, &lnotype, sizeof(int));
1345 SafeWrite (h, &version, sizeof(int));
1346 SafeWrite (h, &numglobaldefs, sizeof(int));
1347 SafeWrite (h, &numpr_globals, sizeof(int));
1348 SafeWrite (h, &numfielddefs, sizeof(int));
1349 SafeWrite (h, &numstatements, sizeof(int));
1350 SafeWrite (h, statement_linenums, numstatements*sizeof(int));
1364 Returns a string suitable for printing (no newlines, max 60 chars length)
1367 char *QCC_PR_String (char *string)
1369 static char buf[80];
1374 while (string && *string)
1376 if (s == buf + sizeof(buf) - 2)
1378 if (*string == '\n')
1383 else if (*string == '"')
1406 QCC_def_t *QCC_PR_DefForFieldOfs (gofs_t ofs)
1410 for (d=pr.def_head.next ; d ; d=d->next)
1412 if (d->type->type != ev_field)
1414 if (*((unsigned int *)&qcc_pr_globals[d->ofs]) == ofs)
1417 QCC_Error (ERR_NOTDEFINED, "PR_DefForFieldOfs: couldn't find %i",ofs);
1425 Returns a string describing *data in a type specific manner
1428 char *QCC_PR_ValueString (etype_t type, void *val)
1430 static char line[256];
1437 sprintf (line, "%s", QCC_PR_String(strings + *(int *)val));
1440 sprintf (line, "entity %i", *(int *)val);
1443 f = functions + *(int *)val;
1445 sprintf (line, "undefined function");
1447 sprintf (line, "%s()", strings + f->s_name);
1450 def = QCC_PR_DefForFieldOfs ( *(int *)val );
1451 sprintf (line, ".%s", def->name);
1454 sprintf (line, "void");
1457 sprintf (line, "%5.1f", *(float *)val);
1460 sprintf (line, "%i", *(int *)val);
1463 sprintf (line, "'%5.1f %5.1f %5.1f'", ((float *)val)[0], ((float *)val)[1], ((float *)val)[2]);
1466 sprintf (line, "pointer");
1469 sprintf (line, "bad type %i", type);
1480 Returns a string with a description and the contents of a global,
1481 padded to 20 field width
1484 /*char *QCC_PR_GlobalStringNoContents (gofs_t ofs)
1489 static char line[128];
1491 val = (void *)&qcc_pr_globals[ofs];
1492 def = pr_global_defs[ofs];
1494 // Error ("PR_GlobalString: no def for %i", ofs);
1495 sprintf (line,"%i(?""?""?)", ofs);
1497 sprintf (line,"%i(%s)", ofs, def->name);
1507 char *QCC_PR_GlobalString (gofs_t ofs)
1513 static char line[128];
1515 val = (void *)&qcc_pr_globals[ofs];
1516 def = pr_global_defs[ofs];
1518 return QCC_PR_GlobalStringNoContents(ofs);
1519 if (def->initialized && def->type->type != ev_function)
1521 s = QCC_PR_ValueString (def->type->type, &qcc_pr_globals[ofs]);
1522 sprintf (line,"%i(%s)", ofs, s);
1525 sprintf (line,"%i(%s)", ofs, def->name);
1540 /*void QCC_PR_PrintOfs (gofs_t ofs)
1542 printf ("%s\n",QCC_PR_GlobalString(ofs));
1550 /*void QCC_PR_PrintStatement (QCC_dstatement_t *s)
1554 printf ("%4i : %4i : %s ", (int)(s - statements), statement_linenums[s-statements], pr_opcodes[s->op].opname);
1555 i = strlen(pr_opcodes[s->op].opname);
1559 if (s->op == OP_IF || s->op == OP_IFNOT)
1560 printf ("%sbranch %i",QCC_PR_GlobalString(s->a),s->b);
1561 else if (s->op == OP_GOTO)
1563 printf ("branch %i",s->a);
1565 else if ( (unsigned)(s->op - OP_STORE_F) < 6)
1567 printf ("%s",QCC_PR_GlobalString(s->a));
1568 printf ("%s", QCC_PR_GlobalStringNoContents(s->b));
1573 printf ("%s",QCC_PR_GlobalString(s->a));
1575 printf ("%s",QCC_PR_GlobalString(s->b));
1577 printf ("%s", QCC_PR_GlobalStringNoContents(s->c));
1588 /*void QCC_PR_PrintDefs (void)
1592 for (d=pr.def_head.next ; d ; d=d->next)
1593 QCC_PR_PrintOfs (d->ofs);
1596 QCC_type_t *QCC_PR_NewType (char *name, int basictype)
1598 if (numtypeinfos>= maxtypeinfos)
1599 QCC_Error(ERR_TOOMANYTYPES, "Too many types");
1600 memset(&qcc_typeinfo[numtypeinfos], 0, sizeof(QCC_type_t));
1601 qcc_typeinfo[numtypeinfos].type = basictype;
1602 qcc_typeinfo[numtypeinfos].name = name;
1603 qcc_typeinfo[numtypeinfos].num_parms = 0;
1604 qcc_typeinfo[numtypeinfos].param = NULL;
1605 qcc_typeinfo[numtypeinfos].size = type_size[basictype];
1610 return &qcc_typeinfo[numtypeinfos-1];
1617 called before compiling a batch of files, clears the pr struct
1620 void QCC_PR_BeginCompilation (void *memory, int memsize)
1622 extern int recursivefunctiontype;
1623 extern struct freeoffset_s *freeofs;
1628 pr.max_memory = memsize;
1630 pr.def_tail = &pr.def_head;
1632 QCC_PR_ResetErrorScope();
1635 /* numpr_globals = RESERVED_OFS;
1637 for (i=0 ; i<RESERVED_OFS ; i++)
1638 pr_global_defs[i] = &def_void;
1641 type_void = QCC_PR_NewType("void", ev_void);
1642 type_string = QCC_PR_NewType("string", ev_string);
1643 type_float = QCC_PR_NewType("float", ev_float);
1644 type_vector = QCC_PR_NewType("vector", ev_vector);
1645 type_entity = QCC_PR_NewType("entity", ev_entity);
1646 type_field = QCC_PR_NewType("field", ev_field);
1647 type_function = QCC_PR_NewType("function", ev_function);
1648 type_pointer = QCC_PR_NewType("pointer", ev_pointer);
1649 type_integer = QCC_PR_NewType("__integer", ev_integer);
1650 type_variant = QCC_PR_NewType("__variant", ev_variant);
1652 type_floatfield = QCC_PR_NewType("fieldfloat", ev_field);
1653 type_floatfield->aux_type = type_float;
1654 type_pointer->aux_type = QCC_PR_NewType("pointeraux", ev_float);
1656 type_function->aux_type = type_void;
1658 //type_field->aux_type = type_float;
1660 if (keyword_integer)
1661 type_integer = QCC_PR_NewType("integer", ev_integer);
1663 type_integer = QCC_PR_NewType("int", ev_integer);
1668 { //this tends to confuse the brains out of decompilers. :)
1670 QCC_PR_GetDef(type_vector, "RETURN", NULL, true, 1, false)->references++;
1671 for (i = 0; i < MAX_PARMS; i++)
1673 sprintf(name, "PARM%i", i);
1674 QCC_PR_GetDef(type_vector, name, NULL, true, 1, false)->references++;
1679 numpr_globals = RESERVED_OFS;
1680 // for (i=0 ; i<RESERVED_OFS ; i++)
1681 // pr_global_defs[i] = NULL;
1684 // link the function type in so state forward declarations match proper type
1686 // type_function->next = NULL;
1688 pr_warning_count = 0;
1689 recursivefunctiontype = 0;
1696 PR_FinishCompilation
1698 called after all files are compiled to check for errors
1699 Returns false if errors were detected.
1702 int QCC_PR_FinishCompilation (void)
1709 // check to make sure all functions prototyped have code
1710 for (d=pr.def_head.next ; d ; d=d->next)
1712 if (d->type->type == ev_function && !d->scope)// function parms are ok
1714 // f = G_FUNCTION(d->ofs);
1715 // if (!f || (!f->code && !f->builtin) )
1716 if (d->initialized==0)
1719 if (!strncmp(d->name, "ArrayGet*", 9))
1721 QCC_PR_EmitArrayGetFunction(d, d->name+9);
1724 else if (!strncmp(d->name, "ArraySet*", 9))
1726 QCC_PR_EmitArraySetFunction(d, d->name+9);
1729 else if (!strncmp(d->name, "Class*", 6))
1731 QCC_PR_EmitClassFromFunction(d, d->name+6);
1736 QCC_PR_ParseErrorPrintDef(ERR_NOFUNC, d, "function %s was not defined",d->name);
1737 bodylessfuncs = true;
1743 else if (d->initialized==2)
1744 bodylessfuncs = true;
1752 //=============================================================================
1754 // FIXME: byte swap?
1756 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
1757 // and the initial and final xor values shown below... in other words, the
1758 // CCITT standard CRC used by XMODEM
1761 #define CRC_INIT_VALUE 0xffff
1762 #define CRC_XOR_VALUE 0x0000
1764 static unsigned short QCC_crctable[256] =
1766 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1767 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1768 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1769 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1770 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1771 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1772 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1773 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1774 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1775 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1776 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1777 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1778 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1779 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1780 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1781 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1782 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1783 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1784 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1785 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1786 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1787 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1788 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1789 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1790 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1791 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1792 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1793 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1794 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1795 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1796 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1797 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1800 void QCC_CRC_Init(unsigned short *crcvalue)
1802 *crcvalue = CRC_INIT_VALUE;
1805 void QCC_CRC_ProcessByte(unsigned short *crcvalue, qbyte data)
1807 *crcvalue = (*crcvalue << 8) ^ QCC_crctable[(*crcvalue >> 8) ^ data];
1810 unsigned short QCC_CRC_Value(unsigned short crcvalue)
1812 return crcvalue ^ CRC_XOR_VALUE;
1814 //=============================================================================
1821 Writes the global and entity structures out
1822 Returns a crc of the header, to be stored in the progs file for comparison
1827 char *Sva(char *msg, ...)
1830 static char buf[1024];
1833 QC_vsnprintf (buf,sizeof(buf)-1, msg, l);
1840 #define PROGDEFS_MAX_SIZE 16384
1841 //write (to file buf) and add to the crc
1842 static void Add(char *p, unsigned short *crc, char *file)
1845 int i = strlen(file);
1846 if (i + strlen(p)+1 >= PROGDEFS_MAX_SIZE)
1850 QCC_CRC_ProcessByte(crc, *s);
1855 #define ADD(p) Add(p, &crc, file)
1856 //#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';}
1858 static void Add3(char *p, unsigned short *crc, char *file)
1862 QCC_CRC_ProcessByte(crc, *s);
1864 #define ADD3(p) Add3(p, &crc, file)
1866 unsigned short QCC_PR_WriteProgdefs (char *filename)
1868 #define ADD2(p) strncat(file, p, PROGDEFS_MAX_SIZE-1 - strlen(file)) //no crc (later changes)
1869 char file[PROGDEFS_MAX_SIZE];
1877 QCC_CRC_Init (&crc);
1879 // print global vars until the first field is defined
1882 //ADD2: dump but don't crc
1883 //ADD3: crc but don't dump
1886 if (qcc_targetformat == QCF_HEXEN2)
1887 ADD3("generated by hcc, do not modify");
1889 ADD3("file generated by qcc, do not modify");
1890 ADD2("File generated by FTEQCC, relevent for engine modding only, the generated crc must be the same as your engine expects.");
1891 ADD(" */\n\ntypedef struct");
1892 ADD2(" globalvars_s");
1895 "\tint ofs_return[3];\n" //makes it easier with the get globals func
1896 "\tint ofs_parm0[3];\n"
1897 "\tint ofs_parm1[3];\n"
1898 "\tint ofs_parm2[3];\n"
1899 "\tint ofs_parm3[3];\n"
1900 "\tint ofs_parm4[3];\n"
1901 "\tint ofs_parm5[3];\n"
1902 "\tint ofs_parm6[3];\n"
1903 "\tint ofs_parm7[3];\n");
1904 ADD3(qcva("\tint\tpad[%i];\n", RESERVED_OFS));
1905 for (d=pr.def_head.next ; d ; d=d->next)
1907 if (!strcmp (d->name, "end_sys_globals"))
1909 if (d->ofs<RESERVED_OFS)
1912 switch (d->type->type)
1915 ADD(qcva("\tfloat\t%s;\n",d->name));
1918 ADD(qcva("\tvec3_t\t%s;\n",d->name));
1919 d=d->next->next->next; // skip the elements
1922 ADD(qcva("\tstring_t\t%s;\n",d->name));
1925 ADD(qcva("\tfunc_t\t%s;\n",d->name));
1928 ADD(qcva("\tint\t%s;\n",d->name));
1931 ADD(qcva("\tint\t%s;\n",d->name));
1934 ADD(qcva("\tint\t%s;\n",d->name));
1938 ADD("} globalvars_t;\n\n");
1941 ADD("typedef struct");
1944 for (d=pr.def_head.next ; d ; d=d->next)
1946 if (!strcmp (d->name, "end_sys_fields"))
1949 if (d->type->type != ev_field)
1952 switch (d->type->aux_type->type)
1955 ADD(qcva("\tfloat\t%s;\n",d->name));
1958 ADD(qcva("\tvec3_t\t%s;\n",d->name));
1959 d=d->next->next->next; // skip the elements
1962 ADD(qcva("\tstring_t\t%s;\n",d->name));
1965 ADD(qcva("\tfunc_t\t%s;\n",d->name));
1968 ADD(qcva("\tint\t%s;\n",d->name));
1971 ADD(qcva("\tint\t%s;\n",d->name));
1974 ADD(qcva("\tint\t%s;\n",d->name));
1978 ADD("} entvars_t;\n\n");
1981 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");
1983 for (d=pr.def_head.next ; d ; d=d->next)
1985 if (!strcmp (d->name, "end_sys_fields"))
1988 if (d->type->type != ev_field)
1992 ADD2(qcva("\t{%i,\t%i,\t\"%s\"}",G_INT(d->ofs), d->type->aux_type->type, d->name));
1995 ADD2("\n};\n#endif\n\n");
1998 ADD2(qcva("#define PROGHEADER_CRC %i\n", crc));
2000 if (QCC_CheckParm("-progdefs"))
2002 printf ("writing %s\n", filename);
2003 f = SafeOpenWrite(filename, 16384);
2004 SafeWrite(f, file, strlen(file));
2014 case 12923: //#pragma sourcefile usage
2018 printf("Recognised progs as QuakeWorld\n");
2022 printf("Recognised progs as NetQuake server gamecode\n");
2027 printf("Recognised progs as Quake pre-release...\n");
2032 printf("Recognised progs as original Hexen2\n");
2036 printf("Recognised progs as Hexen2 Mission Pack\n");
2040 printf("Recognised progs as Hexen2 (demo)\n");
2043 case 22390: //EXT_CSQC_1
2045 printf("Recognised progs as an EXT_CSQC_1 module\n");
2048 case 32199: //outdated ext_csqc
2049 printf("Recognised progs as outdated CSQC module\n");
2052 printf("Recognised progs as outdated CSQC module\n");
2056 printf("Recognised progs as a DP/FTE Menu module\n");
2060 printf("Warning: please update your tenebrae system defs.\n");
2063 printf("Warning: progs CRC not recognised from quake nor clones\n");
2072 /*void QCC_PrintFunction (char *name)
2075 QCC_dstatement_t *ds;
2076 QCC_dfunction_t *df;
2078 for (i=0 ; i<numfunctions ; i++)
2079 if (!strcmp (name, strings + functions[i].s_name))
2081 if (i==numfunctions)
2082 QCC_Error (ERR_NOFUNC, "No function named \"%s\"", name);
2085 printf ("Statements for function %s:\n", name);
2086 ds = statements + df->first_statement;
2089 QCC_PR_PrintStatement (ds);
2096 void QCC_PrintOfs(unsigned int ofs)
2100 QCC_dstatement_t *ds;
2101 QCC_dfunction_t *df;
2103 for (i=0 ; i<numfunctions ; i++)
2106 ds = statements + df->first_statement;
2112 if (ds->a == ofs || ds->b == ofs || ds->c == ofs)
2114 QCC_PR_PrintStatement (ds);
2121 QCC_PrintFunction(strings + functions[i].s_name);
2129 ==============================================================================
2131 DIRECTORY COPYING / PACKFILE CREATION
2133 ==============================================================================
2139 int filepos, filelen;
2149 packfile_t pfiles[4096], *pf;
2159 void QCC_CreatePath (char *path)
2164 for (ofs = path+1 ; *ofs ; ofs++)
2167 { // create the directory
2185 Copy a file into the pak file
2188 void QCC_PackFile (char *src, char *name)
2200 if ( (qbyte *)pf - (qbyte *)pfiles > sizeof(pfiles) )
2201 QCC_Error (ERR_TOOMANYPAKFILES, "Too many files in pak file");
2204 f = FS_ReadToMem(src, NULL, &remaining);
2207 printf ("%64s : %7s\n", name, "");
2208 // QCC_Error("Failed to open file %s", src);
2212 pf->filepos = PRLittleLong (SafeSeek (packhandle, 0, SEEK_CUR));
2213 pf->filelen = PRLittleLong (remaining);
2214 strcpy (pf->name, name);
2215 printf ("%64s : %7i\n", pf->name, remaining);
2217 packbytes += remaining;
2219 SafeWrite (packhandle, f, remaining);
2223 in = SafeOpenRead (src);
2224 remaining = filelength (in);
2226 pf->filepos = PRLittleLong (lseek (packhandle, 0, SEEK_CUR));
2227 pf->filelen = PRLittleLong (remaining);
2228 strcpy (pf->name, name);
2229 printf ("%64s : %7i\n", pf->name, remaining);
2231 packbytes += remaining;
2235 if (remaining < sizeof(buf))
2238 count = sizeof(buf);
2239 SafeRead (in, buf, count);
2240 SafeWrite (packhandle, buf, count);
2254 Copies a file, creating any directories needed
2257 void QCC_CopyFile (char *src, char *dest)
2261 int remaining, count;
2264 print ("%s to %s\n", src, dest);
2266 in = SafeOpenRead (src);
2267 remaining = filelength (in);
2269 QCC_CreatePath (dest);
2270 out = SafeOpenWrite (dest, remaining+10);
2274 if (remaining < sizeof(buf))
2277 count = sizeof(buf);
2278 SafeRead (in, buf, count);
2279 SafeWrite (out, buf, count);
2295 void _QCC_CopyFiles (int blocknum, int copytype, char *srcdir, char *destdir)
2300 packheader_t header;
2302 char srcfile[1024], destfile[1024];
2309 packhandle = SafeOpenWrite (destdir, 1024*1024);
2310 SafeWrite (packhandle, &header, sizeof(header));
2313 for (i=0 ; i<numsounds ; i++)
2315 if (precache_sounds_block[i] != blocknum)
2317 sprintf (srcfile,"%s%s",srcdir, precache_sounds[i]);
2318 sprintf (destfile,"%s%s",destdir, precache_sounds[i]);
2320 QCC_CopyFile (srcfile, destfile);
2322 QCC_PackFile (srcfile, precache_sounds[i]);
2324 for (i=0 ; i<nummodels ; i++)
2326 if (precache_models_block[i] != blocknum)
2328 sprintf (srcfile,"%s%s",srcdir, precache_models[i]);
2329 sprintf (destfile,"%s%s",destdir, precache_models[i]);
2331 QCC_CopyFile (srcfile, destfile);
2333 QCC_PackFile (srcfile, precache_models[i]);
2335 for (i=0 ; i<numtextures ; i++)
2337 if (precache_textures_block[i] != blocknum)
2341 sprintf (name, "%s", precache_textures[i]);
2342 sprintf (srcfile,"%s%s",srcdir, name);
2343 sprintf (destfile,"%s%s",destdir, name);
2345 QCC_CopyFile (srcfile, destfile);
2347 QCC_PackFile (srcfile, name);
2350 sprintf (name, "%s.bmp", precache_textures[i]);
2351 sprintf (srcfile,"%s%s",srcdir, name);
2352 sprintf (destfile,"%s%s",destdir, name);
2354 QCC_CopyFile (srcfile, destfile);
2356 QCC_PackFile (srcfile, name);
2359 sprintf (name, "%s.tga", precache_textures[i]);
2360 sprintf (srcfile,"%s%s",srcdir, name);
2361 sprintf (destfile,"%s%s",destdir, name);
2363 QCC_CopyFile (srcfile, destfile);
2365 QCC_PackFile (srcfile, name);
2368 for (i=0 ; i<numfiles ; i++)
2370 if (precache_files_block[i] != blocknum)
2372 sprintf (srcfile,"%s%s",srcdir, precache_files[i]);
2373 sprintf (destfile,"%s%s",destdir, precache_files[i]);
2375 QCC_CopyFile (srcfile, destfile);
2377 QCC_PackFile (srcfile, precache_files[i]);
2386 dirlen = (qbyte *)pf - (qbyte *)pfiles;
2387 header.dirofs = PRLittleLong(SafeSeek (packhandle, 0, SEEK_CUR));
2388 header.dirlen = PRLittleLong(dirlen);
2390 SafeWrite (packhandle, pfiles, dirlen);
2392 SafeSeek (packhandle, 0, SEEK_SET);
2393 SafeWrite (packhandle, &header, sizeof(header));
2394 SafeClose (packhandle);
2396 // do a crc of the file
2397 QCC_CRC_Init (&crc);
2398 for (i=0 ; i<dirlen ; i++)
2399 QCC_CRC_ProcessByte (&crc, ((qbyte *)pfiles)[i]);
2402 printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
2406 void QCC_CopyFiles (void)
2409 char srcdir[1024], destdir[1024];
2415 printf ("%3i unique precache_sounds\n", numsounds);
2417 printf ("%3i unique precache_models\n", nummodels);
2418 if (numtextures > 0)
2419 printf ("%3i unique precache_textures\n", numtextures);
2421 printf ("%3i unique precache_files\n", numfiles);
2424 p = QCC_CheckParm ("-copy");
2425 if (p && p < myargc-2)
2426 { // create a new directory tree
2428 strcpy (srcdir, myargv[p+1]);
2429 strcpy (destdir, myargv[p+2]);
2430 if (srcdir[strlen(srcdir)-1] != '/')
2431 strcat (srcdir, "/");
2432 if (destdir[strlen(destdir)-1] != '/')
2433 strcat (destdir, "/");
2435 _QCC_CopyFiles(0, 1, srcdir, destdir);
2439 for ( p = 0; p < 5; p++)
2441 s = QCC_Packname[p];
2446 _QCC_CopyFiles(p+1, 2, srcdir, destdir);
2452 p = QCC_CheckParm ("-pak2");
2453 if (p && p <myargc-2)
2456 p = QCC_CheckParm ("-pak");
2457 if (p && p < myargc-2)
2458 { // create a pak file
2459 strcpy (srcdir, myargv[p+1]);
2460 strcpy (destdir, myargv[p+2]);
2461 if (srcdir[strlen(srcdir)-1] != '/')
2462 strcat (srcdir, "/");
2463 DefaultExtension (destdir, ".pak");
2468 _QCC_CopyFiles(blocknum, copytype, srcdir, destdir);
2473 //============================================================================
2476 void QCC_PR_CommandLinePrecompilerOptions (void)
2478 CompilerConstant_t *cnst;
2482 for (i = 1;i<myargc;i++)
2485 if ( !strncmp(myargv[i], "-D", 2) )
2487 name = myargv[i] + 2;
2488 val = strchr(name, '=');
2494 cnst = QCC_PR_DefineName(name);
2497 cnst->value = qccHunkAlloc(strlen(val)+1);
2498 memcpy(cnst->value, val, strlen(val)+1);
2503 else if ( !strnicmp(myargv[i], "-O", 2) || !strnicmp(myargv[i], "/O", 2) )
2506 if (myargv[i][2] >= '0' && myargv[i][2] <= '3')
2509 else if (!strnicmp(myargv[i]+2, "no-", 3))
2513 for (p = 0; optimisations[p].enabled; p++)
2515 if ((*optimisations[p].abbrev && !stricmp(myargv[i]+5, optimisations[p].abbrev)) || !stricmp(myargv[i]+5, optimisations[p].fullname))
2517 *optimisations[p].enabled = false;
2526 for (p = 0; optimisations[p].enabled; p++)
2527 if ((*optimisations[p].abbrev && !stricmp(myargv[i]+2, optimisations[p].abbrev)) || !stricmp(myargv[i]+2, optimisations[p].fullname))
2529 *optimisations[p].enabled = true;
2533 if (!optimisations[p].enabled)
2534 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised optimisation parameter (%s)", myargv[i]);
2537 else if ( !strnicmp(myargv[i], "-K", 2) || !strnicmp(myargv[i], "/K", 2) )
2540 if (!strnicmp(myargv[i]+2, "no-", 3))
2542 for (p = 0; compiler_flag[p].enabled; p++)
2543 if (!stricmp(myargv[i]+5, compiler_flag[p].abbrev))
2545 *compiler_flag[p].enabled = false;
2551 for (p = 0; compiler_flag[p].enabled; p++)
2552 if (!stricmp(myargv[i]+2, compiler_flag[p].abbrev))
2554 *compiler_flag[p].enabled = true;
2559 if (!compiler_flag[p].enabled)
2560 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised keyword parameter (%s)", myargv[i]);
2562 else if ( !strnicmp(myargv[i], "-F", 2) || !strnicmp(myargv[i], "/F", 2) )
2565 if (!strnicmp(myargv[i]+2, "no-", 3))
2567 for (p = 0; compiler_flag[p].enabled; p++)
2568 if (!stricmp(myargv[i]+5, compiler_flag[p].abbrev))
2570 *compiler_flag[p].enabled = false;
2576 for (p = 0; compiler_flag[p].enabled; p++)
2577 if (!stricmp(myargv[i]+2, compiler_flag[p].abbrev))
2579 *compiler_flag[p].enabled = true;
2584 if (!compiler_flag[p].enabled)
2585 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised flag parameter (%s)", myargv[i]);
2589 else if ( !strncmp(myargv[i], "-T", 2) || !strncmp(myargv[i], "/T", 2) )
2592 for (p = 0; targets[p].name; p++)
2593 if (!stricmp(myargv[i]+2, targets[p].name))
2595 qcc_targetformat = targets[p].target;
2599 if (!targets[p].name)
2600 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised target parameter (%s)", myargv[i]);
2603 else if ( !strnicmp(myargv[i], "-W", 2) || !strnicmp(myargv[i], "/W", 2) )
2605 if (!stricmp(myargv[i]+2, "all"))
2606 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2607 else if (!stricmp(myargv[i]+2, "none"))
2608 memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled));
2609 else if(!stricmp(myargv[i]+2, "error"))
2611 else if (!stricmp(myargv[i]+2, "no-mundane"))
2612 { //disable mundane performance/efficiency/blah warnings that don't affect code.
2613 qccwarningdisabled[WARN_SAMENAMEASGLOBAL] = true;
2614 qccwarningdisabled[WARN_DUPLICATEDEFINITION] = true;
2615 qccwarningdisabled[WARN_CONSTANTCOMPARISON] = true;
2616 qccwarningdisabled[WARN_ASSIGNMENTINCONDITIONAL] = true;
2617 qccwarningdisabled[WARN_DEADCODE] = true;
2618 qccwarningdisabled[WARN_NOTREFERENCEDCONST] = true;
2619 qccwarningdisabled[WARN_NOTREFERENCED] = true;
2620 qccwarningdisabled[WARN_POINTLESSSTATEMENT] = true;
2621 qccwarningdisabled[WARN_ASSIGNMENTTOCONSTANTFUNC] = true;
2622 qccwarningdisabled[WARN_BADPRAGMA] = true; //C specs say that these should be ignored. We're close enough to C that I consider that a valid statement.
2623 qccwarningdisabled[WARN_IDENTICALPRECOMPILER] = true;
2624 qccwarningdisabled[WARN_UNDEFNOTDEFINED] = true;
2625 qccwarningdisabled[WARN_FIXEDRETURNVALUECONFLICT] = true;
2626 qccwarningdisabled[WARN_EXTRAPRECACHE] = true;
2627 qccwarningdisabled[WARN_CORRECTEDRETURNTYPE] = true;
2632 if (!strnicmp(myargv[i]+2, "no-", 3))
2634 for (p = 0; warningnames[p].name; p++)
2635 if (!strcmp(myargv[i]+5, warningnames[p].name))
2637 qccwarningdisabled[warningnames[p].index] = true;
2643 for (p = 0; warningnames[p].name; p++)
2644 if (!stricmp(myargv[i]+2, warningnames[p].name))
2646 qccwarningdisabled[warningnames[p].index] = false;
2651 if (!warningnames[p].name)
2652 QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised warning parameter (%s)", myargv[i]);
2666 char qccmfilename[1024];
2667 char qccmprogsdat[1024];
2668 char qccmsourcedir[1024];
2670 void QCC_FinishCompile(void);
2673 void SetEndian(void);
2677 void QCC_SetDefaultProperties (void)
2682 Hash_InitTable(&compconstantstable, MAX_CONSTANTS, qccHunkAlloc(Hash_BytesForBuckets(MAX_CONSTANTS)));
2687 QCC_PR_DefineName("FTEQCC");
2689 if (QCC_CheckParm("/Oz"))
2691 qcc_targetformat = QCF_FTE;
2692 QCC_PR_DefineName("OP_COMP_STATEMENTS");
2693 QCC_PR_DefineName("OP_COMP_DEFS");
2694 QCC_PR_DefineName("OP_COMP_FIELDS");
2695 QCC_PR_DefineName("OP_COMP_FUNCTIONS");
2696 QCC_PR_DefineName("OP_COMP_STRINGS");
2697 QCC_PR_DefineName("OP_COMP_GLOBALS");
2698 QCC_PR_DefineName("OP_COMP_LINES");
2699 QCC_PR_DefineName("OP_COMP_TYPES");
2702 if (QCC_CheckParm("/O0") || QCC_CheckParm("-O0"))
2704 else if (QCC_CheckParm("/O1") || QCC_CheckParm("-O1"))
2706 else if (QCC_CheckParm("/O2") || QCC_CheckParm("-O2"))
2708 else if (QCC_CheckParm("/O3") || QCC_CheckParm("-O3"))
2715 for (i = 0; optimisations[i].enabled; i++)
2717 if (optimisations[i].flags & FLAG_ASDEFAULT)
2718 *optimisations[i].enabled = true;
2720 *optimisations[i].enabled = false;
2725 for (i = 0; optimisations[i].enabled; i++)
2727 if (level >= optimisations[i].optimisationlevel)
2728 *optimisations[i].enabled = true;
2730 *optimisations[i].enabled = false;
2734 if (QCC_CheckParm ("-h2"))
2735 qcc_targetformat = QCF_HEXEN2;
2736 else if (QCC_CheckParm ("-fte"))
2737 qcc_targetformat = QCF_FTE;
2738 else if (QCC_CheckParm ("-dp"))
2739 qcc_targetformat = QCF_DARKPLACES;
2741 qcc_targetformat = QCF_STANDARD;
2744 //enable all warnings
2745 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2747 //play with default warnings.
2748 qccwarningdisabled[WARN_NOTREFERENCEDCONST] = true;
2749 qccwarningdisabled[WARN_MACROINSTRING] = true;
2750 // qccwarningdisabled[WARN_ASSIGNMENTTOCONSTANT] = true;
2751 qccwarningdisabled[WARN_FIXEDRETURNVALUECONFLICT] = true;
2752 qccwarningdisabled[WARN_EXTRAPRECACHE] = true;
2753 qccwarningdisabled[WARN_DEADCODE] = true;
2754 qccwarningdisabled[WARN_INEFFICIENTPLUSPLUS] = true;
2755 qccwarningdisabled[WARN_FTE_SPECIFIC] = true;
2756 qccwarningdisabled[WARN_EXTENSION_USED] = true;
2757 qccwarningdisabled[WARN_IFSTRING_USED] = true;
2761 if (QCC_CheckParm("-nowarn") || QCC_CheckParm("-Wnone"))
2762 memset(qccwarningdisabled, 1, sizeof(qccwarningdisabled));
2763 if (QCC_CheckParm("-Wall"))
2764 memset(qccwarningdisabled, 0, sizeof(qccwarningdisabled));
2766 if (QCC_CheckParm("-h2"))
2767 qccwarningdisabled[WARN_CASEINSENSATIVEFRAMEMACRO] = true;
2769 //Check the command line
2770 QCC_PR_CommandLinePrecompilerOptions();
2773 if (qcc_targetformat == QCF_HEXEN2) //force on the thinktime keyword if hexen2 progs.
2774 keyword_thinktime = true;
2776 if (QCC_CheckParm("/Debug")) //disable any debug optimisations
2778 for (i = 0; optimisations[i].enabled; i++)
2780 if (optimisations[i].flags & FLAG_KILLSDEBUGGERS)
2781 *optimisations[i].enabled = false;
2786 //builds a list of files, pretends that they came from a progs.src
2787 int QCC_FindQCFiles()
2794 int numfiles = 0, i, j;
2795 char *filelist[256], *temp;
2798 qccmsrc = qccHunkAlloc(8192);
2799 strcat(qccmsrc, "progs.dat\n");//"#pragma PROGS_DAT progs.dat\n");
2802 h = FindFirstFile("*.qc", &fd);
2803 if (h == INVALID_HANDLE_VALUE)
2808 filelist[numfiles] = qccHunkAlloc (strlen(fd.cFileName)+1);
2809 strcpy(filelist[numfiles], fd.cFileName);
2811 } while(FindNextFile(h, &fd)!=0);
2814 printf("-Facc is not supported on this platform. Please make a progs.src file instead\n");
2817 //Sort alphabetically.
2820 for (i = 0; i < numfiles-1; i++)
2822 for (j = i+1; j < numfiles; j++)
2824 if (stricmp(filelist[i], filelist[j]) > 0)
2827 filelist[j] = filelist[i];
2832 for (i = 0; i < numfiles; i++)
2834 strcat(qccmsrc, filelist[i]);
2835 strcat(qccmsrc, "\n");
2836 // strcat(qccmsrc, "#include \"");
2837 // strcat(qccmsrc, filelist[i]);
2838 // strcat(qccmsrc, "\"\n");
2844 int qcc_compileactive = false;
2845 extern int accglobalsblock;
2846 char *originalqccmsrc; //for autoprototype.
2847 void QCC_main (int argc, char **argv) //as part of the quake engine
2849 extern int pr_bracelevel;
2854 char destfile2[1024], *s2;
2863 qcc_compileactive = true;
2865 pHash_Get = &Hash_Get;
2866 pHash_GetNext = &Hash_GetNext;
2867 pHash_Add = &Hash_Add;
2870 MAX_STRINGS = 1000000;
2871 MAX_GLOBALS = 65535;
2873 MAX_STATEMENTS = 0x80000;
2874 MAX_FUNCTIONS = 16384;
2875 maxtypeinfos = 16384;
2876 MAX_CONSTANTS = 2048;
2880 p = externs->FileSize("qcc.cfg");
2882 p = externs->FileSize("src/qcc.cfg");
2885 s = qccHunkAlloc(p+1);
2886 s = externs->ReadFile("qcc.cfg", s, p);
2890 s = QCC_COM_Parse(s);
2891 if (!strcmp(qcc_token, "MAX_REGS"))
2893 s = QCC_COM_Parse(s);
2894 MAX_REGS = atoi(qcc_token);
2895 } else if (!strcmp(qcc_token, "MAX_STRINGS")) {
2896 s = QCC_COM_Parse(s);
2897 MAX_STRINGS = atoi(qcc_token);
2898 } else if (!strcmp(qcc_token, "MAX_GLOBALS")) {
2899 s = QCC_COM_Parse(s);
2900 MAX_GLOBALS = atoi(qcc_token);
2901 } else if (!strcmp(qcc_token, "MAX_FIELDS")) {
2902 s = QCC_COM_Parse(s);
2903 MAX_FIELDS = atoi(qcc_token);
2904 } else if (!strcmp(qcc_token, "MAX_STATEMENTS")) {
2905 s = QCC_COM_Parse(s);
2906 MAX_STATEMENTS = atoi(qcc_token);
2907 } else if (!strcmp(qcc_token, "MAX_FUNCTIONS")) {
2908 s = QCC_COM_Parse(s);
2909 MAX_FUNCTIONS = atoi(qcc_token);
2910 } else if (!strcmp(qcc_token, "MAX_TYPES")) {
2911 s = QCC_COM_Parse(s);
2912 maxtypeinfos = atoi(qcc_token);
2913 } else if (!strcmp(qcc_token, "MAX_TEMPS")) {
2914 s = QCC_COM_Parse(s);
2915 max_temps = atoi(qcc_token);
2916 } else if (!strcmp(qcc_token, "CONSTANTS")) {
2917 s = QCC_COM_Parse(s);
2918 MAX_CONSTANTS = atoi(qcc_token);
2923 printf("Bad token in qcc.cfg file\n");
2926 /* don't try to be clever
2929 s = qccHunkAlloc(8192);
2930 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",
2931 MAX_REGS, MAX_STRINGS, MAX_GLOBALS, MAX_FIELDS, MAX_STATEMENTS, MAX_FUNCTIONS, maxtypeinfos);
2932 externs->WriteFile("qcc.cfg", s, strlen(s));
2936 strcpy(QCC_copyright, "This file was created with ForeThought's modified QuakeC compiler\nThanks to ID Software");
2937 for (p = 0; p < 5; p++)
2938 strcpy(QCC_Packname[p], "");
2940 for (p = 0; compiler_flag[p].enabled; p++)
2942 *compiler_flag[p].enabled = compiler_flag[p].flags & FLAG_ASDEFAULT;
2946 QCC_SetDefaultProperties();
2948 optres_shortenifnots = 0;
2949 optres_overlaptemps = 0;
2950 optres_noduplicatestrings = 0;
2951 optres_constantarithmatic = 0;
2952 optres_nonvec_parms = 0;
2953 optres_constant_names = 0;
2954 optres_constant_names_strings = 0;
2955 optres_precache_file = 0;
2956 optres_filenames = 0;
2957 optres_assignments = 0;
2958 optres_unreferenced = 0;
2959 optres_function_names = 0;
2961 optres_dupconstdefs = 0;
2962 optres_return_only = 0;
2963 optres_compound_jumps = 0;
2964 // optres_comexprremoval = 0;
2965 optres_stripfunctions = 0;
2966 optres_locals_marshalling = 0;
2967 optres_logicops = 0;
2972 accglobalsblock = 0;
2979 strings = (void *)qccHunkAlloc(sizeof(char) * MAX_STRINGS);
2982 statements = (void *)qccHunkAlloc(sizeof(QCC_dstatement_t) * MAX_STATEMENTS);
2984 statement_linenums = (void *)qccHunkAlloc(sizeof(int) * MAX_STATEMENTS);
2986 functions = (void *)qccHunkAlloc(sizeof(QCC_dfunction_t) * MAX_FUNCTIONS);
2991 qcc_pr_globals = (void *)qccHunkAlloc(sizeof(float) * MAX_REGS);
2994 Hash_InitTable(&globalstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS)));
2995 Hash_InitTable(&localstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS)));
2996 Hash_InitTable(&floatconstdefstable, MAX_REGS+1, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS+1)));
2997 Hash_InitTable(&stringconstdefstable, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS)));
2998 Hash_InitTable(&stringconstdefstable_dotranslate, MAX_REGS, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS)));
3000 dotranslate_count=0;
3002 // pr_global_defs = (QCC_def_t **)qccHunkAlloc(sizeof(QCC_def_t *) * MAX_REGS);
3004 qcc_globals = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_GLOBALS);
3007 fields = (void *)qccHunkAlloc(sizeof(QCC_ddef_t) * MAX_FIELDS);
3010 memset(pr_immediate_string, 0, sizeof(pr_immediate_string));
3012 precache_sounds = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_SOUNDS);
3013 precache_sounds_block = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS);
3014 precache_sounds_used = (void *)qccHunkAlloc(sizeof(int)*MAX_SOUNDS);
3017 precache_textures = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_TEXTURES);
3018 precache_textures_block = (void *)qccHunkAlloc(sizeof(int)*MAX_TEXTURES);
3021 precache_models = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_MODELS);
3022 precache_models_block = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS);
3023 precache_models_used = (void *)qccHunkAlloc(sizeof(int)*MAX_MODELS);
3026 precache_files = (void *)qccHunkAlloc(sizeof(char)*MAX_DATA_PATH*MAX_FILES);
3027 precache_files_block = (void *)qccHunkAlloc(sizeof(int)*MAX_FILES);
3030 qcc_typeinfo = (void *)qccHunkAlloc(sizeof(QCC_type_t)*maxtypeinfos);
3033 qcc_tempofs = qccHunkAlloc(sizeof(int) * max_temps);
3038 memset(&pr, 0, sizeof(pr));
3039 #ifdef MAX_EXTRA_PARMS
3040 memset(&extra_parms, 0, sizeof(extra_parms));
3043 if ( QCC_CheckParm ("/?") || QCC_CheckParm ("?") || QCC_CheckParm ("-?") || QCC_CheckParm ("-help") || QCC_CheckParm ("--help"))
3045 printf ("qcc looks for progs.src in the current directory.\n");
3046 printf ("to look in a different directory: qcc -src <directory>\n");
3047 // printf ("to build a clean data tree: qcc -copy <srcdir> <destdir>\n");
3048 // printf ("to build a clean pak file: qcc -pak <srcdir> <packfile>\n");
3049 // printf ("to bsp all bmodels: qcc -bspmodels <gamedir>\n");
3050 printf ("-Fwasm <funcname> causes FTEQCC to dump all asm to qc.asm\n");
3051 printf ("-O0 to disable optimisations\n");
3052 printf ("-O1 to optimise for size\n");
3053 printf ("-O2 to optimise more - some behaviours may change\n");
3054 printf ("-O3 to optimise lots - experimental or non-future-proof\n");
3055 printf ("-Oname to enable an optimisation\n");
3056 printf ("-Ono-name to disable optimisations\n");
3057 printf ("-Kkeyword to activate keyword\n");
3058 printf ("-Kno-keyword to disable keyword\n");
3059 printf ("-Wall to give a stupid number of warnings\n");
3060 printf ("-Ttarget to set a output format\n");
3061 printf ("-Fautoproto to enable automatic prototyping\n");
3062 printf ("-Fsubscope to make locals specific to their subscope\n");
3064 qcc_compileactive = false;
3068 if (flag_caseinsensative)
3070 printf("Compiling without case sensativity\n");
3071 pHash_Get = &Hash_GetInsensative;
3072 pHash_GetNext = &Hash_GetNextInsensative;
3073 pHash_Add = &Hash_AddInsensative;
3077 if (opt_locals_marshalling)
3078 printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nLocals marshalling might be buggy. Use with caution\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
3080 p = QCC_CheckParm ("-src");
3081 if (p && p < argc-1 )
3083 strcpy (qccmsourcedir, argv[p+1]);
3084 strcat (qccmsourcedir, "/");
3085 printf ("Source directory: %s\n", qccmsourcedir);
3088 *qccmsourcedir = '\0';
3092 QCC_PR_BeginCompilation ((void *)qccHunkAlloc (0x100000), 0x100000);
3096 if (!QCC_FindQCFiles())
3097 QCC_Error (ERR_COULDNTOPENFILE, "Couldn't open file for asm output.");
3101 if (!numsourcefiles)
3103 p = QCC_CheckParm ("-qc");
3104 if (!p || p >= argc-1 || argv[p+1][0] == '-')
3105 p = QCC_CheckParm ("-srcfile");
3106 if (p && p < argc-1 )
3107 sprintf (qccmprogsdat, "%s", argv[p+1]);
3109 { //look for a preprogs.src... :o)
3110 sprintf (qccmprogsdat, "preprogs.src");
3111 if (externs->FileSize(qccmprogsdat) <= 0)
3112 sprintf (qccmprogsdat, "progs.src");
3116 strcpy(sourcefileslist[numsourcefiles++], qccmprogsdat);
3117 currentsourcefile = 0;
3119 else if (currentsourcefile == numsourcefiles)
3122 qcc_compileactive = false;
3124 currentsourcefile = 0;
3128 if (currentsourcefile)
3129 printf("-------------------------------------\n");
3131 sprintf (qccmprogsdat, "%s%s", qccmsourcedir, sourcefileslist[currentsourcefile++]);
3132 printf ("Source file: %s\n", qccmprogsdat);
3134 if (QCC_LoadFile (qccmprogsdat, (void *)&qccmsrc) == -1)
3143 asmfile = fopen("qc.asm", "wb");
3145 QCC_Error (ERR_INTERNAL, "Couldn't open file for asm output.");
3149 newstylesource = false;
3150 while(*qccmsrc && *qccmsrc < ' ')
3152 pr_file_p = QCC_COM_Parse(qccmsrc);
3154 if (QCC_CheckParm ("-qc"))
3156 strcpy(destfile, qccmprogsdat);
3157 StripExtension(destfile);
3158 strcat(destfile, ".qco");
3160 p = QCC_CheckParm ("-o");
3161 if (!p || p >= argc-1 || argv[p+1][0] == '-')
3162 if (p && p < argc-1 )
3163 sprintf (destfile, "%s%s", qccmsourcedir, argv[p+1]);
3167 if (*qcc_token == '#')
3169 void StartNewStyleCompile(void);
3171 newstylesource = true;
3172 StartNewStyleCompile();
3176 pr_file_p = qccmsrc;
3177 QCC_PR_LexWhitespace();
3178 qccmsrc = pr_file_p;
3181 pr_file_p = qccmsrc;
3182 QCC_PR_SimpleGetToken ();
3183 strcpy(qcc_token, pr_token);
3184 qccmsrc = pr_file_p;
3187 QCC_Error (ERR_NOOUTPUT, "No destination filename. qcc -help for info.");
3188 strcpy (destfile, qcc_token);
3192 s2 = strcpy(destfile2, destfile);
3193 if (!strncmp(s2, "./", 2))
3197 while(!strncmp(s2, "../", 3))
3203 strcpy(qccmfilename, qccmsourcedir);
3204 for (s=qccmfilename+strlen(qccmfilename);p && s>=qccmfilename; s--)
3206 if (*s == '/' || *s == '\\')
3212 sprintf(destfile, "%s", s2);
3216 memmove(destfile+3, destfile, strlen(destfile)+1);
3227 pbool modified = false;
3229 if (stat(destfile, &os) != -1)
3231 while ((pr_file_p=QCC_COM_Parse(pr_file_p)))
3233 if (stat(qcc_token, &s) == -1 || s.st_mtime > os.st_mtime)
3235 printf("%s changed\n", qcc_token);
3242 printf("No changes\n");
3243 qcc_compileactive = false;
3248 pr_file_p = qccmsrc;
3253 printf ("outputfile: %s\n", destfile);
3257 currentchunk = NULL;
3259 originalqccmsrc = qccmsrc;
3262 void new_QCC_ContinueCompile(void);
3263 //called between exe frames - won't loose net connection (is the theory)...
3264 void QCC_ContinueCompile(void)
3267 currentchunk = NULL;
3268 if (!qcc_compileactive)
3274 new_QCC_ContinueCompile();
3278 qccmsrc = QCC_COM_Parse(qccmsrc);
3283 qccmsrc = originalqccmsrc;
3284 QCC_SetDefaultProperties();
3285 autoprototype = false;
3288 QCC_FinishCompile();
3293 QCC_main(myargc, myargv);
3298 strcpy (qccmfilename, qccmsourcedir);
3301 if (!strncmp(s, "..\\", 3) || !strncmp(s, "../", 3))
3303 s2 = qccmfilename + strlen(qccmfilename)-2;
3304 while (s2>=qccmfilename)
3306 if (*s2 == '/' || *s2 == '\\')
3313 if (s2>=qccmfilename)
3319 if (!strncmp(s, ".\\", 2) || !strncmp(s, "./", 2))
3327 strcat (qccmfilename, s);
3329 printf ("prototyping %s\n", qccmfilename);
3332 printf ("compiling %s\n", qccmfilename);
3334 QCC_LoadFile (qccmfilename, (void *)&qccmsrc2);
3336 if (!QCC_PR_CompileFile (qccmsrc2, qccmfilename) )
3337 QCC_Error (ERR_PARSEERRORS, "Errors have occured\n");
3339 void QCC_FinishCompile(void)
3341 pbool donesomething;
3344 currentchunk = NULL;
3346 if (setjmp(pr_parse_abort))
3347 QCC_Error(ERR_INTERNAL, "");
3349 if (!QCC_PR_FinishCompilation ())
3351 QCC_Error (ERR_PARSEERRORS, "compilation errors");
3354 /* p = QCC_CheckParm ("-asm");
3357 for (p++ ; p<myargc ; p++)
3359 if (myargv[p][0] == '-')
3361 QCC_PrintFunction (myargv[p]);
3365 /*p = QCC_CheckParm ("-ofs");
3368 for (p++ ; p<myargc ; p++)
3370 if (myargv[p][0] == '-')
3372 QCC_PrintOfs (atoi(myargv[p]));
3376 if (pr_werror && pr_warning_count != 0)
3377 QCC_Error (ERR_PARSEERRORS, "compilation errors");
3380 crc = QCC_PR_WriteProgdefs ("progdefs.h");
3383 donesomething = QCC_WriteData (crc);
3385 // regenerate bmodels if -bspmodels
3388 // report / copy the data files
3395 printf ("Compile Complete\n\n");
3397 if (optres_shortenifnots)
3398 printf("optres_shortenifnots %i\n", optres_shortenifnots);
3399 if (optres_overlaptemps)
3400 printf("optres_overlaptemps %i\n", optres_overlaptemps);
3401 if (optres_noduplicatestrings)
3402 printf("optres_noduplicatestrings %i\n", optres_noduplicatestrings);
3403 if (optres_constantarithmatic)
3404 printf("optres_constantarithmatic %i\n", optres_constantarithmatic);
3405 if (optres_nonvec_parms)
3406 printf("optres_nonvec_parms %i\n", optres_nonvec_parms);
3407 if (optres_constant_names)
3408 printf("optres_constant_names %i\n", optres_constant_names);
3409 if (optres_constant_names_strings)
3410 printf("optres_constant_names_strings %i\n", optres_constant_names_strings);
3411 if (optres_precache_file)
3412 printf("optres_precache_file %i\n", optres_precache_file);
3413 if (optres_filenames)
3414 printf("optres_filenames %i\n", optres_filenames);
3415 if (optres_assignments)
3416 printf("optres_assignments %i\n", optres_assignments);
3417 if (optres_unreferenced)
3418 printf("optres_unreferenced %i\n", optres_unreferenced);
3420 printf("optres_locals %i\n", optres_locals);
3421 if (optres_function_names)
3422 printf("optres_function_names %i\n", optres_function_names);
3423 if (optres_dupconstdefs)
3424 printf("optres_dupconstdefs %i\n", optres_dupconstdefs);
3425 if (optres_return_only)
3426 printf("optres_return_only %i\n", optres_return_only);
3427 if (optres_compound_jumps)
3428 printf("optres_compound_jumps %i\n", optres_compound_jumps);
3429 // if (optres_comexprremoval)
3430 // printf("optres_comexprremoval %i\n", optres_comexprremoval);
3431 if (optres_stripfunctions)
3432 printf("optres_stripfunctions %i\n", optres_stripfunctions);
3433 if (optres_locals_marshalling)
3434 printf("optres_locals_marshalling %i\n", optres_locals_marshalling);
3435 if (optres_logicops)
3436 printf("optres_logicops %i\n", optres_logicops);
3440 printf("optres_test1 %i\n", optres_test1);
3442 printf("optres_test2 %i\n", optres_test2);
3444 printf("numtemps %i\n", numtemps);
3446 if (!flag_msvcstyle)
3447 printf("%i warnings\n", pr_warning_count);
3450 qcc_compileactive = false;
3457 extern char *compilingfile;
3458 extern QCC_string_t s_file, s_file2;
3459 extern char *pr_file_p;
3460 extern int pr_source_line;
3461 extern QCC_def_t *pr_scope;
3462 void QCC_PR_ParseDefs (char *classname);
3468 void StartNewStyleCompile(void)
3470 if (setjmp(pr_parse_abort))
3472 if (++pr_error_count > MAX_ERRORS)
3474 if (setjmp(pr_parse_abort))
3477 QCC_PR_SkipToSemicolon ();
3478 if (pr_token_type == tt_eof)
3483 QCC_PR_ClearGrabMacros (); // clear the frame macros
3485 compilingfile = qccmprogsdat;
3487 pr_file_p = qccmsrc;
3488 s_file = s_file2 = QCC_CopyString (compilingfile);
3492 QCC_PR_NewLine (false);
3494 QCC_PR_Lex (); // read first token
3496 void new_QCC_ContinueCompile(void)
3498 if (setjmp(pr_parse_abort))
3500 // if (pr_error_count != 0)
3502 QCC_Error (ERR_PARSEERRORS, "Errors have occured");
3505 QCC_PR_SkipToSemicolon ();
3506 if (pr_token_type == tt_eof)
3510 if (pr_token_type == tt_eof)
3513 QCC_Error (ERR_PARSEERRORS, "Errors have occured");
3514 QCC_FinishCompile();
3519 QCC_main(myargc, myargv);
3523 pr_scope = NULL; // outside all functions
3525 QCC_PR_ParseDefs (NULL);
3528 /*void new_QCC_ContinueCompile(void)
3531 if (!qcc_compileactive)
3535 // compile all the files
3537 qccmsrc = QCC_COM_Parse(qccmsrc);
3540 QCC_FinishCompile();
3545 strcpy (qccmfilename, qccmsourcedir);
3548 if (!strncmp(s, "..\\", 3))
3550 s2 = qccmfilename + strlen(qccmfilename)-2;
3551 while (s2>=qccmfilename)
3553 if (*s2 == '/' || *s2 == '\\')
3563 if (!strncmp(s, ".\\", 2))
3571 // strcat (qccmfilename, s);
3572 // printf ("compiling %s\n", qccmfilename);
3573 // QCC_LoadFile (qccmfilename, (void *)&qccmsrc2);
3575 // if (!new_QCC_PR_CompileFile (qccmsrc2, qccmfilename) )
3576 // QCC_Error ("Errors have occured\n");
3582 QCC_Error ("PR_CompileFile: Didn't clear");
3584 QCC_PR_ClearGrabMacros (); // clear the frame macros
3586 compilingfile = filename;
3588 pr_file_p = qccmsrc2;
3589 s_file = QCC_CopyString (filename);
3595 QCC_PR_Lex (); // read first token
3597 while (pr_token_type != tt_eof)
3599 if (setjmp(pr_parse_abort))
3601 if (++pr_error_count > MAX_ERRORS)
3603 QCC_PR_SkipToSemicolon ();
3604 if (pr_token_type == tt_eof)
3608 pr_scope = NULL; // outside all functions
3610 QCC_PR_ParseDefs ();
3613 return (pr_error_count == 0);